The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ipc/util.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/ipc/util.c
    3  * Copyright (C) 1992 Krishna Balasubramanian
    4  *
    5  * Sep 1997 - Call suser() last after "normal" permission checks so we
    6  *            get BSD style process accounting right.
    7  *            Occurs in several places in the IPC code.
    8  *            Chris Evans, <chris@ferret.lmh.ox.ac.uk>
    9  * Nov 1999 - ipc helper functions, unified SMP locking
   10  *            Manfred Spraul <manfreds@colorfullife.com>
   11  */
   12 
   13 #include <linux/config.h>
   14 #include <linux/mm.h>
   15 #include <linux/shm.h>
   16 #include <linux/init.h>
   17 #include <linux/msg.h>
   18 #include <linux/smp_lock.h>
   19 #include <linux/vmalloc.h>
   20 #include <linux/slab.h>
   21 #include <linux/highuid.h>
   22 
   23 #if defined(CONFIG_SYSVIPC)
   24 
   25 #include "util.h"
   26 
   27 /**
   28  *      ipc_init        -       initialise IPC subsystem
   29  *
   30  *      The various system5 IPC resources (semaphores, messages and shared
   31  *      memory are initialised
   32  */
   33  
   34 void __init ipc_init (void)
   35 {
   36         sem_init();
   37         msg_init();
   38         shm_init();
   39         return;
   40 }
   41 
   42 /**
   43  *      ipc_init_ids            -       initialise IPC identifiers
   44  *      @ids: Identifier set
   45  *      @size: Number of identifiers
   46  *
   47  *      Given a size for the ipc identifier range (limited below IPCMNI)
   48  *      set up the sequence range to use then allocate and initialise the
   49  *      array itself. 
   50  */
   51  
   52 void __init ipc_init_ids(struct ipc_ids* ids, int size)
   53 {
   54         int i;
   55         sema_init(&ids->sem,1);
   56 
   57         if(size > IPCMNI)
   58                 size = IPCMNI;
   59         ids->size = size;
   60         ids->in_use = 0;
   61         ids->max_id = -1;
   62         ids->seq = 0;
   63         {
   64                 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
   65                 if(seq_limit > USHRT_MAX)
   66                         ids->seq_max = USHRT_MAX;
   67                  else
   68                         ids->seq_max = seq_limit;
   69         }
   70 
   71         ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
   72 
   73         if(ids->entries == NULL) {
   74                 printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
   75                 ids->size = 0;
   76         }
   77         ids->ary = SPIN_LOCK_UNLOCKED;
   78         for(i=0;i<ids->size;i++)
   79                 ids->entries[i].p = NULL;
   80 }
   81 
   82 /**
   83  *      ipc_findkey     -       find a key in an ipc identifier set     
   84  *      @ids: Identifier set
   85  *      @key: The key to find
   86  *
   87  *      Returns the identifier if found or -1 if not.
   88  */
   89  
   90 int ipc_findkey(struct ipc_ids* ids, key_t key)
   91 {
   92         int id;
   93         struct kern_ipc_perm* p;
   94 
   95         for (id = 0; id <= ids->max_id; id++) {
   96                 p = ids->entries[id].p;
   97                 if(p==NULL)
   98                         continue;
   99                 if (key == p->key)
  100                         return id;
  101         }
  102         return -1;
  103 }
  104 
  105 static int grow_ary(struct ipc_ids* ids, int newsize)
  106 {
  107         struct ipc_id* new;
  108         struct ipc_id* old;
  109         int i;
  110 
  111         if(newsize > IPCMNI)
  112                 newsize = IPCMNI;
  113         if(newsize <= ids->size)
  114                 return newsize;
  115 
  116         new = ipc_alloc(sizeof(struct ipc_id)*newsize);
  117         if(new == NULL)
  118                 return ids->size;
  119         memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
  120         for(i=ids->size;i<newsize;i++) {
  121                 new[i].p = NULL;
  122         }
  123         spin_lock(&ids->ary);
  124 
  125         old = ids->entries;
  126         ids->entries = new;
  127         i = ids->size;
  128         ids->size = newsize;
  129         spin_unlock(&ids->ary);
  130         ipc_free(old, sizeof(struct ipc_id)*i);
  131         return ids->size;
  132 }
  133 
  134 /**
  135  *      ipc_addid       -       add an IPC identifier
  136  *      @ids: IPC identifier set
  137  *      @new: new IPC permission set
  138  *      @size: new size limit for the id array
  139  *
  140  *      Add an entry 'new' to the IPC arrays. The permissions object is
  141  *      initialised and the first free entry is set up and the id assigned
  142  *      is returned. The list is returned in a locked state on success.
  143  *      On failure the list is not locked and -1 is returned.
  144  */
  145  
  146 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
  147 {
  148         int id;
  149 
  150         size = grow_ary(ids,size);
  151         for (id = 0; id < size; id++) {
  152                 if(ids->entries[id].p == NULL)
  153                         goto found;
  154         }
  155         return -1;
  156 found:
  157         ids->in_use++;
  158         if (id > ids->max_id)
  159                 ids->max_id = id;
  160 
  161         new->cuid = new->uid = current->euid;
  162         new->gid = new->cgid = current->egid;
  163 
  164         new->seq = ids->seq++;
  165         if(ids->seq > ids->seq_max)
  166                 ids->seq = 0;
  167 
  168         spin_lock(&ids->ary);
  169         ids->entries[id].p = new;
  170         return id;
  171 }
  172 
  173 /**
  174  *      ipc_rmid        -       remove an IPC identifier
  175  *      @ids: identifier set
  176  *      @id: Identifier to remove
  177  *
  178  *      The identifier must be valid, and in use. The kernel will panic if
  179  *      fed an invalid identifier. The entry is removed and internal
  180  *      variables recomputed. The object associated with the identifier
  181  *      is returned.
  182  */
  183  
  184 struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
  185 {
  186         struct kern_ipc_perm* p;
  187         int lid = id % SEQ_MULTIPLIER;
  188         if(lid >= ids->size)
  189                 BUG();
  190         p = ids->entries[lid].p;
  191         ids->entries[lid].p = NULL;
  192         if(p==NULL)
  193                 BUG();
  194         ids->in_use--;
  195 
  196         if (lid == ids->max_id) {
  197                 do {
  198                         lid--;
  199                         if(lid == -1)
  200                                 break;
  201                 } while (ids->entries[lid].p == NULL);
  202                 ids->max_id = lid;
  203         }
  204         return p;
  205 }
  206 
  207 /**
  208  *      ipc_alloc       -       allocate ipc space
  209  *      @size: size desired
  210  *
  211  *      Allocate memory from the appropriate pools and return a pointer to it.
  212  *      NULL is returned if the allocation fails
  213  */
  214  
  215 void* ipc_alloc(int size)
  216 {
  217         void* out;
  218         if(size > PAGE_SIZE)
  219                 out = vmalloc(size);
  220         else
  221                 out = kmalloc(size, GFP_KERNEL);
  222         return out;
  223 }
  224 
  225 /**
  226  *      ipc_free        -       free ipc space
  227  *      @ptr: pointer returned by ipc_alloc
  228  *      @size: size of block
  229  *
  230  *      Free a block created with ipc_alloc. The caller must know the size
  231  *      used in the allocation call.
  232  */
  233  
  234 void ipc_free(void* ptr, int size)
  235 {
  236         if(size > PAGE_SIZE)
  237                 vfree(ptr);
  238         else
  239                 kfree(ptr);
  240 }
  241 
  242 /**
  243  *      ipcperms        -       check IPC permissions
  244  *      @ipcp: IPC permission set
  245  *      @flag: desired permission set.
  246  *
  247  *      Check user, group, other permissions for access
  248  *      to ipc resources. return 0 if allowed
  249  */
  250  
  251 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
  252 {       /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
  253         int requested_mode, granted_mode;
  254 
  255         requested_mode = (flag >> 6) | (flag >> 3) | flag;
  256         granted_mode = ipcp->mode;
  257         if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
  258                 granted_mode >>= 6;
  259         else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
  260                 granted_mode >>= 3;
  261         /* is there some bit set in requested_mode but not in granted_mode? */
  262         if ((requested_mode & ~granted_mode & 0007) && 
  263             !capable(CAP_IPC_OWNER))
  264                 return -1;
  265 
  266         return 0;
  267 }
  268 
  269 /*
  270  * Functions to convert between the kern_ipc_perm structure and the
  271  * old/new ipc_perm structures
  272  */
  273 
  274 /**
  275  *      kernel_to_ipc64_perm    -       convert kernel ipc permissions to user
  276  *      @in: kernel permissions
  277  *      @out: new style IPC permissions
  278  *
  279  *      Turn the kernel object 'in' into a set of permissions descriptions
  280  *      for returning to userspace (out).
  281  */
  282  
  283 
  284 void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
  285 {
  286         out->key        = in->key;
  287         out->uid        = in->uid;
  288         out->gid        = in->gid;
  289         out->cuid       = in->cuid;
  290         out->cgid       = in->cgid;
  291         out->mode       = in->mode;
  292         out->seq        = in->seq;
  293 }
  294 
  295 /**
  296  *      ipc64_perm_to_ipc_perm  -       convert old ipc permissions to new
  297  *      @in: new style IPC permissions
  298  *      @out: old style IPC permissions
  299  *
  300  *      Turn the new style permissions object in into a compatibility
  301  *      object and store it into the 'out' pointer.
  302  */
  303  
  304 void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
  305 {
  306         out->key        = in->key;
  307         out->uid        = NEW_TO_OLD_UID(in->uid);
  308         out->gid        = NEW_TO_OLD_GID(in->gid);
  309         out->cuid       = NEW_TO_OLD_UID(in->cuid);
  310         out->cgid       = NEW_TO_OLD_GID(in->cgid);
  311         out->mode       = in->mode;
  312         out->seq        = in->seq;
  313 }
  314 
  315 #if !defined(__ia64__) && !defined(__hppa__)
  316 
  317 /**
  318  *      ipc_parse_version       -       IPC call version
  319  *      @cmd: pointer to command
  320  *
  321  *      Return IPC_64 for new style IPC and IPC_OLD for old style IPC. 
  322  *      The cmd value is turned from an encoding command and version into
  323  *      just the command code.
  324  */
  325  
  326 int ipc_parse_version (int *cmd)
  327 {
  328 #ifdef __x86_64__
  329         if (!(current->thread.flags & THREAD_IA32))
  330                 return IPC_64; 
  331 #endif
  332         if (*cmd & IPC_64) {
  333                 *cmd ^= IPC_64;
  334                 return IPC_64;
  335         } else {
  336                 return IPC_OLD;
  337         }
  338 }
  339 
  340 #endif /* __ia64__ */
  341 
  342 #else
  343 /*
  344  * Dummy functions when SYSV IPC isn't configured
  345  */
  346 
  347 void sem_exit (void)
  348 {
  349     return;
  350 }
  351 
  352 asmlinkage long sys_semget (key_t key, int nsems, int semflg)
  353 {
  354         return -ENOSYS;
  355 }
  356 
  357 asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
  358 {
  359         return -ENOSYS;
  360 }
  361 
  362 asmlinkage long sys_semtimedop(int semid, struct sembuf *sops, unsigned nsops,
  363                                const struct timespec *timeout)
  364 {
  365         return -ENOSYS;
  366 }
  367 
  368 asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
  369 {
  370         return -ENOSYS;
  371 }
  372 
  373 asmlinkage long sys_msgget (key_t key, int msgflg)
  374 {
  375         return -ENOSYS;
  376 }
  377 
  378 asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
  379 {
  380         return -ENOSYS;
  381 }
  382 
  383 asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
  384                        int msgflg)
  385 {
  386         return -ENOSYS;
  387 }
  388 
  389 asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
  390 {
  391         return -ENOSYS;
  392 }
  393 
  394 asmlinkage long sys_shmget (key_t key, size_t size, int shmflag)
  395 {
  396         return -ENOSYS;
  397 }
  398 
  399 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr)
  400 {
  401         return -ENOSYS;
  402 }
  403 
  404 asmlinkage long sys_shmdt (char *shmaddr)
  405 {
  406         return -ENOSYS;
  407 }
  408 
  409 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
  410 {
  411         return -ENOSYS;
  412 }
  413 
  414 #endif /* CONFIG_SYSVIPC */

Cache object: 994d8830825d379e78a4166ebdaca8d2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.