This commit was manufactured by cvs2svn to create branch
[linux-2.6.git] / ipc / util.c
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  * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
12  *            Mingming Cao <cmm@us.ibm.com>
13  */
14
15 #include <linux/config.h>
16 #include <linux/mm.h>
17 #include <linux/shm.h>
18 #include <linux/init.h>
19 #include <linux/msg.h>
20 #include <linux/smp_lock.h>
21 #include <linux/vmalloc.h>
22 #include <linux/slab.h>
23 #include <linux/highuid.h>
24 #include <linux/security.h>
25 #include <linux/rcupdate.h>
26 #include <linux/workqueue.h>
27 #include <linux/vs_base.h>
28
29 #include <asm/unistd.h>
30
31 #include <asm/unistd.h>
32
33 #include "util.h"
34
35 /**
36  *      ipc_init        -       initialise IPC subsystem
37  *
38  *      The various system5 IPC resources (semaphores, messages and shared
39  *      memory are initialised
40  */
41  
42 static int __init ipc_init(void)
43 {
44         sem_init();
45         msg_init();
46         shm_init();
47         return 0;
48 }
49 __initcall(ipc_init);
50
51 /**
52  *      ipc_init_ids            -       initialise IPC identifiers
53  *      @ids: Identifier set
54  *      @size: Number of identifiers
55  *
56  *      Given a size for the ipc identifier range (limited below IPCMNI)
57  *      set up the sequence range to use then allocate and initialise the
58  *      array itself. 
59  */
60  
61 void __init ipc_init_ids(struct ipc_ids* ids, int size)
62 {
63         int i;
64         sema_init(&ids->sem,1);
65
66         if(size > IPCMNI)
67                 size = IPCMNI;
68         ids->in_use = 0;
69         ids->max_id = -1;
70         ids->seq = 0;
71         {
72                 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
73                 if(seq_limit > USHRT_MAX)
74                         ids->seq_max = USHRT_MAX;
75                  else
76                         ids->seq_max = seq_limit;
77         }
78
79         ids->entries = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*size +
80                                      sizeof(struct ipc_id_ary));
81
82         if(ids->entries == NULL) {
83                 printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
84                 size = 0;
85                 ids->entries = &ids->nullentry;
86         }
87         ids->entries->size = size;
88         for(i=0;i<size;i++)
89                 ids->entries->p[i] = NULL;
90 }
91
92 /**
93  *      ipc_findkey     -       find a key in an ipc identifier set     
94  *      @ids: Identifier set
95  *      @key: The key to find
96  *      
97  *      Requires ipc_ids.sem locked.
98  *      Returns the identifier if found or -1 if not.
99  */
100  
101 int ipc_findkey(struct ipc_ids* ids, key_t key)
102 {
103         int id;
104         struct kern_ipc_perm* p;
105         int max_id = ids->max_id;
106
107         /*
108          * rcu_dereference() is not needed here
109          * since ipc_ids.sem is held
110          */
111         for (id = 0; id <= max_id; id++) {
112                 p = ids->entries->p[id];
113                 if (p==NULL)
114                         continue;
115                 if (!vx_check(p->xid, VX_IDENT))
116                         continue;
117                 if (key == p->key)
118                         return id;
119         }
120         return -1;
121 }
122
123 /*
124  * Requires ipc_ids.sem locked
125  */
126 static int grow_ary(struct ipc_ids* ids, int newsize)
127 {
128         struct ipc_id_ary* new;
129         struct ipc_id_ary* old;
130         int i;
131         int size = ids->entries->size;
132
133         if(newsize > IPCMNI)
134                 newsize = IPCMNI;
135         if(newsize <= size)
136                 return newsize;
137
138         new = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*newsize +
139                             sizeof(struct ipc_id_ary));
140         if(new == NULL)
141                 return size;
142         new->size = newsize;
143         memcpy(new->p, ids->entries->p, sizeof(struct kern_ipc_perm *)*size +
144                                         sizeof(struct ipc_id_ary));
145         for(i=size;i<newsize;i++) {
146                 new->p[i] = NULL;
147         }
148         old = ids->entries;
149
150         /*
151          * Use rcu_assign_pointer() to make sure the memcpyed contents
152          * of the new array are visible before the new array becomes visible.
153          */
154         rcu_assign_pointer(ids->entries, new);
155
156         ipc_rcu_putref(old);
157         return newsize;
158 }
159
160 /**
161  *      ipc_addid       -       add an IPC identifier
162  *      @ids: IPC identifier set
163  *      @new: new IPC permission set
164  *      @size: new size limit for the id array
165  *
166  *      Add an entry 'new' to the IPC arrays. The permissions object is
167  *      initialised and the first free entry is set up and the id assigned
168  *      is returned. The list is returned in a locked state on success.
169  *      On failure the list is not locked and -1 is returned.
170  *
171  *      Called with ipc_ids.sem held.
172  */
173  
174 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
175 {
176         int id;
177
178         size = grow_ary(ids,size);
179
180         /*
181          * rcu_dereference()() is not needed here since
182          * ipc_ids.sem is held
183          */
184         for (id = 0; id < size; id++) {
185                 if(ids->entries->p[id] == NULL)
186                         goto found;
187         }
188         return -1;
189 found:
190         ids->in_use++;
191         if (id > ids->max_id)
192                 ids->max_id = id;
193
194         new->cuid = new->uid = current->euid;
195         new->gid = new->cgid = current->egid;
196
197         new->seq = ids->seq++;
198         if(ids->seq > ids->seq_max)
199                 ids->seq = 0;
200
201         spin_lock_init(&new->lock);
202         new->deleted = 0;
203         rcu_read_lock();
204         spin_lock(&new->lock);
205         ids->entries->p[id] = new;
206         return id;
207 }
208
209 /**
210  *      ipc_rmid        -       remove an IPC identifier
211  *      @ids: identifier set
212  *      @id: Identifier to remove
213  *
214  *      The identifier must be valid, and in use. The kernel will panic if
215  *      fed an invalid identifier. The entry is removed and internal
216  *      variables recomputed. The object associated with the identifier
217  *      is returned.
218  *      ipc_ids.sem and the spinlock for this ID is hold before this function
219  *      is called, and remain locked on the exit.
220  */
221  
222 struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
223 {
224         struct kern_ipc_perm* p;
225         int lid = id % SEQ_MULTIPLIER;
226         if(lid >= ids->entries->size)
227                 BUG();
228
229         /* 
230          * do not need a rcu_dereference()() here to force ordering
231          * on Alpha, since the ipc_ids.sem is held.
232          */     
233         p = ids->entries->p[lid];
234         ids->entries->p[lid] = NULL;
235         if(p==NULL)
236                 BUG();
237         ids->in_use--;
238
239         if (lid == ids->max_id) {
240                 do {
241                         lid--;
242                         if(lid == -1)
243                                 break;
244                 } while (ids->entries->p[lid] == NULL);
245                 ids->max_id = lid;
246         }
247         p->deleted = 1;
248         return p;
249 }
250
251 /**
252  *      ipc_alloc       -       allocate ipc space
253  *      @size: size desired
254  *
255  *      Allocate memory from the appropriate pools and return a pointer to it.
256  *      NULL is returned if the allocation fails
257  */
258  
259 void* ipc_alloc(int size)
260 {
261         void* out;
262         if(size > PAGE_SIZE)
263                 out = vmalloc(size);
264         else
265                 out = kmalloc(size, GFP_KERNEL);
266         return out;
267 }
268
269 /**
270  *      ipc_free        -       free ipc space
271  *      @ptr: pointer returned by ipc_alloc
272  *      @size: size of block
273  *
274  *      Free a block created with ipc_alloc. The caller must know the size
275  *      used in the allocation call.
276  */
277
278 void ipc_free(void* ptr, int size)
279 {
280         if(size > PAGE_SIZE)
281                 vfree(ptr);
282         else
283                 kfree(ptr);
284 }
285
286 /*
287  * rcu allocations:
288  * There are three headers that are prepended to the actual allocation:
289  * - during use: ipc_rcu_hdr.
290  * - during the rcu grace period: ipc_rcu_grace.
291  * - [only if vmalloc]: ipc_rcu_sched.
292  * Their lifetime doesn't overlap, thus the headers share the same memory.
293  * Unlike a normal union, they are right-aligned, thus some container_of
294  * forward/backward casting is necessary:
295  */
296 struct ipc_rcu_hdr
297 {
298         int refcount;
299         int is_vmalloc;
300         void *data[0];
301 };
302
303
304 struct ipc_rcu_grace
305 {
306         struct rcu_head rcu;
307         /* "void *" makes sure alignment of following data is sane. */
308         void *data[0];
309 };
310
311 struct ipc_rcu_sched
312 {
313         struct work_struct work;
314         /* "void *" makes sure alignment of following data is sane. */
315         void *data[0];
316 };
317
318 #define HDRLEN_KMALLOC          (sizeof(struct ipc_rcu_grace) > sizeof(struct ipc_rcu_hdr) ? \
319                                         sizeof(struct ipc_rcu_grace) : sizeof(struct ipc_rcu_hdr))
320 #define HDRLEN_VMALLOC          (sizeof(struct ipc_rcu_sched) > HDRLEN_KMALLOC ? \
321                                         sizeof(struct ipc_rcu_sched) : HDRLEN_KMALLOC)
322
323 static inline int rcu_use_vmalloc(int size)
324 {
325         /* Too big for a single page? */
326         if (HDRLEN_KMALLOC + size > PAGE_SIZE)
327                 return 1;
328         return 0;
329 }
330
331 /**
332  *      ipc_rcu_alloc   -       allocate ipc and rcu space 
333  *      @size: size desired
334  *
335  *      Allocate memory for the rcu header structure +  the object.
336  *      Returns the pointer to the object.
337  *      NULL is returned if the allocation fails. 
338  */
339  
340 void* ipc_rcu_alloc(int size)
341 {
342         void* out;
343         /* 
344          * We prepend the allocation with the rcu struct, and
345          * workqueue if necessary (for vmalloc). 
346          */
347         if (rcu_use_vmalloc(size)) {
348                 out = vmalloc(HDRLEN_VMALLOC + size);
349                 if (out) {
350                         out += HDRLEN_VMALLOC;
351                         container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
352                         container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
353                 }
354         } else {
355                 out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL);
356                 if (out) {
357                         out += HDRLEN_KMALLOC;
358                         container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
359                         container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
360                 }
361         }
362
363         return out;
364 }
365
366 void ipc_rcu_getref(void *ptr)
367 {
368         container_of(ptr, struct ipc_rcu_hdr, data)->refcount++;
369 }
370
371 /**
372  *      ipc_schedule_free       - free ipc + rcu space
373  * 
374  * Since RCU callback function is called in bh,
375  * we need to defer the vfree to schedule_work
376  */
377 static void ipc_schedule_free(struct rcu_head *head)
378 {
379         struct ipc_rcu_grace *grace =
380                 container_of(head, struct ipc_rcu_grace, rcu);
381         struct ipc_rcu_sched *sched =
382                         container_of(&(grace->data[0]), struct ipc_rcu_sched, data[0]);
383
384         INIT_WORK(&sched->work, vfree, sched);
385         schedule_work(&sched->work);
386 }
387
388 /**
389  *      ipc_immediate_free      - free ipc + rcu space
390  *
391  *      Free from the RCU callback context
392  *
393  */
394 static void ipc_immediate_free(struct rcu_head *head)
395 {
396         struct ipc_rcu_grace *free =
397                 container_of(head, struct ipc_rcu_grace, rcu);
398         kfree(free);
399 }
400
401 void ipc_rcu_putref(void *ptr)
402 {
403         if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0)
404                 return;
405
406         if (container_of(ptr, struct ipc_rcu_hdr, data)->is_vmalloc) {
407                 call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
408                                 ipc_schedule_free);
409         } else {
410                 call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
411                                 ipc_immediate_free);
412         }
413 }
414
415 /**
416  *      ipcperms        -       check IPC permissions
417  *      @ipcp: IPC permission set
418  *      @flag: desired permission set.
419  *
420  *      Check user, group, other permissions for access
421  *      to ipc resources. return 0 if allowed
422  */
423  
424 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
425 {       /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
426         int requested_mode, granted_mode;
427
428         if (!vx_check(ipcp->xid, VX_ADMIN|VX_IDENT)) /* maybe just VX_IDENT? */
429                 return -1;
430         requested_mode = (flag >> 6) | (flag >> 3) | flag;
431         granted_mode = ipcp->mode;
432         if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
433                 granted_mode >>= 6;
434         else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
435                 granted_mode >>= 3;
436         /* is there some bit set in requested_mode but not in granted_mode? */
437         if ((requested_mode & ~granted_mode & 0007) && 
438             !capable(CAP_IPC_OWNER))
439                 return -1;
440
441         return security_ipc_permission(ipcp, flag);
442 }
443
444 /*
445  * Functions to convert between the kern_ipc_perm structure and the
446  * old/new ipc_perm structures
447  */
448
449 /**
450  *      kernel_to_ipc64_perm    -       convert kernel ipc permissions to user
451  *      @in: kernel permissions
452  *      @out: new style IPC permissions
453  *
454  *      Turn the kernel object 'in' into a set of permissions descriptions
455  *      for returning to userspace (out).
456  */
457  
458
459 void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
460 {
461         out->key        = in->key;
462         out->uid        = in->uid;
463         out->gid        = in->gid;
464         out->cuid       = in->cuid;
465         out->cgid       = in->cgid;
466         out->mode       = in->mode;
467         out->seq        = in->seq;
468 }
469
470 /**
471  *      ipc64_perm_to_ipc_perm  -       convert old ipc permissions to new
472  *      @in: new style IPC permissions
473  *      @out: old style IPC permissions
474  *
475  *      Turn the new style permissions object in into a compatibility
476  *      object and store it into the 'out' pointer.
477  */
478  
479 void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
480 {
481         out->key        = in->key;
482         SET_UID(out->uid, in->uid);
483         SET_GID(out->gid, in->gid);
484         SET_UID(out->cuid, in->cuid);
485         SET_GID(out->cgid, in->cgid);
486         out->mode       = in->mode;
487         out->seq        = in->seq;
488 }
489
490 /*
491  * So far only shm_get_stat() calls ipc_get() via shm_get(), so ipc_get()
492  * is called with shm_ids.sem locked.  Since grow_ary() is also called with
493  * shm_ids.sem down(for Shared Memory), there is no need to add read 
494  * barriers here to gurantee the writes in grow_ary() are seen in order 
495  * here (for Alpha).
496  *
497  * However ipc_get() itself does not necessary require ipc_ids.sem down. So
498  * if in the future ipc_get() is used by other places without ipc_ids.sem
499  * down, then ipc_get() needs read memery barriers as ipc_lock() does.
500  */
501 struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id)
502 {
503         struct kern_ipc_perm* out;
504         int lid = id % SEQ_MULTIPLIER;
505         if(lid >= ids->entries->size)
506                 return NULL;
507         out = ids->entries->p[lid];
508         return out;
509 }
510
511 struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
512 {
513         struct kern_ipc_perm* out;
514         int lid = id % SEQ_MULTIPLIER;
515         struct ipc_id_ary* entries;
516
517         rcu_read_lock();
518         entries = rcu_dereference(ids->entries);
519         if(lid >= entries->size) {
520                 rcu_read_unlock();
521                 return NULL;
522         }
523         out = entries->p[lid];
524         if(out == NULL) {
525                 rcu_read_unlock();
526                 return NULL;
527         }
528         spin_lock(&out->lock);
529         
530         /* ipc_rmid() may have already freed the ID while ipc_lock
531          * was spinning: here verify that the structure is still valid
532          */
533         if (out->deleted) {
534                 spin_unlock(&out->lock);
535                 rcu_read_unlock();
536                 return NULL;
537         }
538         return out;
539 }
540
541 void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
542 {
543         rcu_read_lock();
544         spin_lock(&perm->lock);
545 }
546
547 void ipc_unlock(struct kern_ipc_perm* perm)
548 {
549         spin_unlock(&perm->lock);
550         rcu_read_unlock();
551 }
552
553 int ipc_buildid(struct ipc_ids* ids, int id, int seq)
554 {
555         return SEQ_MULTIPLIER*seq + id;
556 }
557
558 int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid)
559 {
560         if(uid/SEQ_MULTIPLIER != ipcp->seq)
561                 return 1;
562         return 0;
563 }
564
565 #ifdef __ARCH_WANT_IPC_PARSE_VERSION
566
567
568 /**
569  *      ipc_parse_version       -       IPC call version
570  *      @cmd: pointer to command
571  *
572  *      Return IPC_64 for new style IPC and IPC_OLD for old style IPC. 
573  *      The cmd value is turned from an encoding command and version into
574  *      just the command code.
575  */
576  
577 int ipc_parse_version (int *cmd)
578 {
579         if (*cmd & IPC_64) {
580                 *cmd ^= IPC_64;
581                 return IPC_64;
582         } else {
583                 return IPC_OLD;
584         }
585 }
586
587 #endif /* __ARCH_WANT_IPC_PARSE_VERSION */