diff options
Diffstat (limited to 'ipc/util.c')
-rw-r--r-- | ipc/util.c | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/ipc/util.c b/ipc/util.c index 49e75efe305b..fd29246dc3c8 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -194,7 +194,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header, | |||
194 | * Requires ipc_ids.mutex locked. | 194 | * Requires ipc_ids.mutex locked. |
195 | * Returns the LOCKED pointer to the ipc structure if found or NULL | 195 | * Returns the LOCKED pointer to the ipc structure if found or NULL |
196 | * if not. | 196 | * if not. |
197 | * If key is found ipc contains its ipc structure | 197 | * If key is found ipc points to the owning ipc structure |
198 | */ | 198 | */ |
199 | 199 | ||
200 | static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) | 200 | static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) |
@@ -258,10 +258,10 @@ int ipc_get_maxid(struct ipc_ids *ids) | |||
258 | * @new: new IPC permission set | 258 | * @new: new IPC permission set |
259 | * @size: limit for the number of used ids | 259 | * @size: limit for the number of used ids |
260 | * | 260 | * |
261 | * Add an entry 'new' to the IPC idr. The permissions object is | 261 | * Add an entry 'new' to the IPC ids idr. The permissions object is |
262 | * initialised and the first free entry is set up and the id assigned | 262 | * initialised and the first free entry is set up and the id assigned |
263 | * is returned. The list is returned in a locked state on success. | 263 | * is returned. The 'new' entry is returned in a locked state on success. |
264 | * On failure the list is not locked and -1 is returned. | 264 | * On failure the entry is not locked and -1 is returned. |
265 | * | 265 | * |
266 | * Called with ipc_ids.mutex held. | 266 | * Called with ipc_ids.mutex held. |
267 | */ | 267 | */ |
@@ -270,10 +270,6 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
270 | { | 270 | { |
271 | int id, err; | 271 | int id, err; |
272 | 272 | ||
273 | /* | ||
274 | * rcu_dereference()() is not needed here since | ||
275 | * ipc_ids.mutex is held | ||
276 | */ | ||
277 | if (size > IPCMNI) | 273 | if (size > IPCMNI) |
278 | size = IPCMNI; | 274 | size = IPCMNI; |
279 | 275 | ||
@@ -303,12 +299,12 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
303 | /** | 299 | /** |
304 | * ipcget_new - create a new ipc object | 300 | * ipcget_new - create a new ipc object |
305 | * @ns: namespace | 301 | * @ns: namespace |
306 | * @ids: identifer set | 302 | * @ids: IPC identifer set |
307 | * @ops: the actual creation routine to call | 303 | * @ops: the actual creation routine to call |
308 | * @params: its parameters | 304 | * @params: its parameters |
309 | * | 305 | * |
310 | * This routine is called sys_msgget, sys_semget() and sys_shmget() when | 306 | * This routine is called by sys_msgget, sys_semget() and sys_shmget() |
311 | * the key is IPC_PRIVATE | 307 | * when the key is IPC_PRIVATE. |
312 | */ | 308 | */ |
313 | int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, | 309 | int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, |
314 | struct ipc_ops *ops, struct ipc_params *params) | 310 | struct ipc_ops *ops, struct ipc_params *params) |
@@ -330,9 +326,16 @@ int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
330 | /** | 326 | /** |
331 | * ipc_check_perms - check security and permissions for an IPC | 327 | * ipc_check_perms - check security and permissions for an IPC |
332 | * @ipcp: ipc permission set | 328 | * @ipcp: ipc permission set |
333 | * @ids: identifer set | ||
334 | * @ops: the actual security routine to call | 329 | * @ops: the actual security routine to call |
335 | * @params: its parameters | 330 | * @params: its parameters |
331 | * | ||
332 | * This routine is called by sys_msgget(), sys_semget() and sys_shmget() | ||
333 | * when the key is not IPC_PRIVATE and that key already exists in the | ||
334 | * ids IDR. | ||
335 | * | ||
336 | * On success, the IPC id is returned. | ||
337 | * | ||
338 | * It is called with ipc_ids.mutex and ipcp->lock held. | ||
336 | */ | 339 | */ |
337 | static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, | 340 | static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, |
338 | struct ipc_params *params) | 341 | struct ipc_params *params) |
@@ -353,12 +356,16 @@ static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, | |||
353 | /** | 356 | /** |
354 | * ipcget_public - get an ipc object or create a new one | 357 | * ipcget_public - get an ipc object or create a new one |
355 | * @ns: namespace | 358 | * @ns: namespace |
356 | * @ids: identifer set | 359 | * @ids: IPC identifer set |
357 | * @ops: the actual creation routine to call | 360 | * @ops: the actual creation routine to call |
358 | * @params: its parameters | 361 | * @params: its parameters |
359 | * | 362 | * |
360 | * This routine is called sys_msgget, sys_semget() and sys_shmget() when | 363 | * This routine is called by sys_msgget, sys_semget() and sys_shmget() |
361 | * the key is not IPC_PRIVATE | 364 | * when the key is not IPC_PRIVATE. |
365 | * It adds a new entry if the key is not found and does some permission | ||
366 | * / security checkings if the key is found. | ||
367 | * | ||
368 | * On success, the ipc id is returned. | ||
362 | */ | 369 | */ |
363 | int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, | 370 | int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, |
364 | struct ipc_ops *ops, struct ipc_params *params) | 371 | struct ipc_ops *ops, struct ipc_params *params) |
@@ -389,6 +396,10 @@ int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
389 | if (ops->more_checks) | 396 | if (ops->more_checks) |
390 | err = ops->more_checks(ipcp, params); | 397 | err = ops->more_checks(ipcp, params); |
391 | if (!err) | 398 | if (!err) |
399 | /* | ||
400 | * ipc_check_perms returns the IPC id on | ||
401 | * success | ||
402 | */ | ||
392 | err = ipc_check_perms(ipcp, ops, params); | 403 | err = ipc_check_perms(ipcp, ops, params); |
393 | } | 404 | } |
394 | ipc_unlock(ipcp); | 405 | ipc_unlock(ipcp); |
@@ -401,12 +412,9 @@ int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
401 | 412 | ||
402 | /** | 413 | /** |
403 | * ipc_rmid - remove an IPC identifier | 414 | * ipc_rmid - remove an IPC identifier |
404 | * @ids: identifier set | 415 | * @ids: IPC identifier set |
405 | * @id: ipc perm structure containing the identifier to remove | 416 | * @ipcp: ipc perm structure containing the identifier to remove |
406 | * | 417 | * |
407 | * The identifier must be valid, and in use. The kernel will panic if | ||
408 | * fed an invalid identifier. The entry is removed and internal | ||
409 | * variables recomputed. | ||
410 | * ipc_ids.mutex and the spinlock for this ID are held before this | 418 | * ipc_ids.mutex and the spinlock for this ID are held before this |
411 | * function is called, and remain locked on the exit. | 419 | * function is called, and remain locked on the exit. |
412 | */ | 420 | */ |
@@ -558,10 +566,12 @@ static void ipc_do_vfree(struct work_struct *work) | |||
558 | */ | 566 | */ |
559 | static void ipc_schedule_free(struct rcu_head *head) | 567 | static void ipc_schedule_free(struct rcu_head *head) |
560 | { | 568 | { |
561 | struct ipc_rcu_grace *grace = | 569 | struct ipc_rcu_grace *grace; |
562 | container_of(head, struct ipc_rcu_grace, rcu); | 570 | struct ipc_rcu_sched *sched; |
563 | struct ipc_rcu_sched *sched = | 571 | |
564 | container_of(&(grace->data[0]), struct ipc_rcu_sched, data[0]); | 572 | grace = container_of(head, struct ipc_rcu_grace, rcu); |
573 | sched = container_of(&(grace->data[0]), struct ipc_rcu_sched, | ||
574 | data[0]); | ||
565 | 575 | ||
566 | INIT_WORK(&sched->work, ipc_do_vfree); | 576 | INIT_WORK(&sched->work, ipc_do_vfree); |
567 | schedule_work(&sched->work); | 577 | schedule_work(&sched->work); |
@@ -650,7 +660,7 @@ void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out) | |||
650 | } | 660 | } |
651 | 661 | ||
652 | /** | 662 | /** |
653 | * ipc64_perm_to_ipc_perm - convert old ipc permissions to new | 663 | * ipc64_perm_to_ipc_perm - convert new ipc permissions to old |
654 | * @in: new style IPC permissions | 664 | * @in: new style IPC permissions |
655 | * @out: old style IPC permissions | 665 | * @out: old style IPC permissions |
656 | * | 666 | * |
@@ -669,6 +679,18 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out) | |||
669 | out->seq = in->seq; | 679 | out->seq = in->seq; |
670 | } | 680 | } |
671 | 681 | ||
682 | /** | ||
683 | * ipc_lock - Lock an ipc structure | ||
684 | * @ids: IPC identifier set | ||
685 | * @id: ipc id to look for | ||
686 | * | ||
687 | * Look for an id in the ipc ids idr and lock the associated ipc object. | ||
688 | * | ||
689 | * ipc_ids.mutex is not necessarily held before this function is called, | ||
690 | * that's why we enter a RCU read section. | ||
691 | * The ipc object is locked on exit. | ||
692 | */ | ||
693 | |||
672 | struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) | 694 | struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) |
673 | { | 695 | { |
674 | struct kern_ipc_perm *out; | 696 | struct kern_ipc_perm *out; |
@@ -771,8 +793,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) | |||
771 | } | 793 | } |
772 | 794 | ||
773 | /* | 795 | /* |
774 | * File positions: pos 0 -> header, pos n -> ipc id + 1. | 796 | * File positions: pos 0 -> header, pos n -> ipc id = n - 1. |
775 | * SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START. | 797 | * SeqFile iterator: iterator value locked ipc pointer or SEQ_TOKEN_START. |
776 | */ | 798 | */ |
777 | static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) | 799 | static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) |
778 | { | 800 | { |
@@ -807,7 +829,7 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it) | |||
807 | struct ipc_proc_iface *iface = iter->iface; | 829 | struct ipc_proc_iface *iface = iter->iface; |
808 | struct ipc_ids *ids; | 830 | struct ipc_ids *ids; |
809 | 831 | ||
810 | /* If we had a locked segment, release it */ | 832 | /* If we had a locked structure, release it */ |
811 | if (ipc && ipc != SEQ_START_TOKEN) | 833 | if (ipc && ipc != SEQ_START_TOKEN) |
812 | ipc_unlock(ipc); | 834 | ipc_unlock(ipc); |
813 | 835 | ||