diff options
| author | Kirill Korotaev <dev@openvz.org> | 2006-10-02 05:18:22 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:22 -0400 |
| commit | e38935341a3105471848220b5750e1ea8722d197 (patch) | |
| tree | feeb5e650b3391963dc1290cfde3d6ecf37e0345 /ipc/sem.c | |
| parent | 1e78693738b71da037d0df340f38e919e8227c2b (diff) | |
[PATCH] IPC namespace - sem
IPC namespace support for IPC sem code.
Signed-off-by: Pavel Emelianiov <xemul@openvz.org>
Signed-off-by: Kirill Korotaev <dev@openvz.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'ipc/sem.c')
| -rw-r--r-- | ipc/sem.c | 201 |
1 files changed, 130 insertions, 71 deletions
| @@ -64,6 +64,10 @@ | |||
| 64 | * | 64 | * |
| 65 | * support for audit of ipc object properties and permission changes | 65 | * support for audit of ipc object properties and permission changes |
| 66 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> | 66 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
| 67 | * | ||
| 68 | * namespaces support | ||
| 69 | * OpenVZ, SWsoft Inc. | ||
| 70 | * Pavel Emelianov <xemul@openvz.org> | ||
| 67 | */ | 71 | */ |
| 68 | 72 | ||
| 69 | #include <linux/slab.h> | 73 | #include <linux/slab.h> |
| @@ -78,22 +82,25 @@ | |||
| 78 | #include <linux/capability.h> | 82 | #include <linux/capability.h> |
| 79 | #include <linux/seq_file.h> | 83 | #include <linux/seq_file.h> |
| 80 | #include <linux/mutex.h> | 84 | #include <linux/mutex.h> |
| 85 | #include <linux/nsproxy.h> | ||
| 81 | 86 | ||
| 82 | #include <asm/uaccess.h> | 87 | #include <asm/uaccess.h> |
| 83 | #include "util.h" | 88 | #include "util.h" |
| 84 | 89 | ||
| 90 | #define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) | ||
| 91 | |||
| 92 | #define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id)) | ||
| 93 | #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) | ||
| 94 | #define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id)) | ||
| 95 | #define sem_checkid(ns, sma, semid) \ | ||
| 96 | ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid) | ||
| 97 | #define sem_buildid(ns, id, seq) \ | ||
| 98 | ipc_buildid(&sem_ids(ns), id, seq) | ||
| 85 | 99 | ||
| 86 | #define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id)) | 100 | static struct ipc_ids init_sem_ids; |
| 87 | #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) | ||
| 88 | #define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id)) | ||
| 89 | #define sem_checkid(sma, semid) \ | ||
| 90 | ipc_checkid(&sem_ids,&sma->sem_perm,semid) | ||
| 91 | #define sem_buildid(id, seq) \ | ||
| 92 | ipc_buildid(&sem_ids, id, seq) | ||
| 93 | static struct ipc_ids sem_ids; | ||
| 94 | 101 | ||
| 95 | static int newary (key_t, int, int); | 102 | static int newary(struct ipc_namespace *, key_t, int, int); |
| 96 | static void freeary (struct sem_array *sma, int id); | 103 | static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id); |
| 97 | #ifdef CONFIG_PROC_FS | 104 | #ifdef CONFIG_PROC_FS |
| 98 | static int sysvipc_sem_proc_show(struct seq_file *s, void *it); | 105 | static int sysvipc_sem_proc_show(struct seq_file *s, void *it); |
| 99 | #endif | 106 | #endif |
| @@ -110,22 +117,61 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it); | |||
| 110 | * | 117 | * |
| 111 | */ | 118 | */ |
| 112 | 119 | ||
| 113 | int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI}; | 120 | #define sc_semmsl sem_ctls[0] |
| 114 | #define sc_semmsl (sem_ctls[0]) | 121 | #define sc_semmns sem_ctls[1] |
| 115 | #define sc_semmns (sem_ctls[1]) | 122 | #define sc_semopm sem_ctls[2] |
| 116 | #define sc_semopm (sem_ctls[2]) | 123 | #define sc_semmni sem_ctls[3] |
| 117 | #define sc_semmni (sem_ctls[3]) | 124 | |
| 125 | static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) | ||
| 126 | { | ||
| 127 | ns->ids[IPC_SEM_IDS] = ids; | ||
| 128 | ns->sc_semmsl = SEMMSL; | ||
| 129 | ns->sc_semmns = SEMMNS; | ||
| 130 | ns->sc_semopm = SEMOPM; | ||
| 131 | ns->sc_semmni = SEMMNI; | ||
| 132 | ns->used_sems = 0; | ||
| 133 | ipc_init_ids(ids, ns->sc_semmni); | ||
| 134 | } | ||
| 135 | |||
| 136 | #ifdef CONFIG_IPC_NS | ||
| 137 | int sem_init_ns(struct ipc_namespace *ns) | ||
| 138 | { | ||
| 139 | struct ipc_ids *ids; | ||
| 140 | |||
| 141 | ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); | ||
| 142 | if (ids == NULL) | ||
| 143 | return -ENOMEM; | ||
| 144 | |||
| 145 | __sem_init_ns(ns, ids); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | void sem_exit_ns(struct ipc_namespace *ns) | ||
| 150 | { | ||
| 151 | int i; | ||
| 152 | struct sem_array *sma; | ||
| 153 | |||
| 154 | mutex_lock(&sem_ids(ns).mutex); | ||
| 155 | for (i = 0; i <= sem_ids(ns).max_id; i++) { | ||
| 156 | sma = sem_lock(ns, i); | ||
| 157 | if (sma == NULL) | ||
| 158 | continue; | ||
| 159 | |||
| 160 | freeary(ns, sma, i); | ||
| 161 | } | ||
| 162 | mutex_unlock(&sem_ids(ns).mutex); | ||
| 118 | 163 | ||
| 119 | static int used_sems; | 164 | kfree(ns->ids[IPC_SEM_IDS]); |
| 165 | ns->ids[IPC_SEM_IDS] = NULL; | ||
| 166 | } | ||
| 167 | #endif | ||
| 120 | 168 | ||
| 121 | void __init sem_init (void) | 169 | void __init sem_init (void) |
| 122 | { | 170 | { |
| 123 | used_sems = 0; | 171 | __sem_init_ns(&init_ipc_ns, &init_sem_ids); |
| 124 | ipc_init_ids(&sem_ids,sc_semmni); | ||
| 125 | ipc_init_proc_interface("sysvipc/sem", | 172 | ipc_init_proc_interface("sysvipc/sem", |
| 126 | " key semid perms nsems uid gid cuid cgid otime ctime\n", | 173 | " key semid perms nsems uid gid cuid cgid otime ctime\n", |
| 127 | &sem_ids, | 174 | IPC_SEM_IDS, sysvipc_sem_proc_show); |
| 128 | sysvipc_sem_proc_show); | ||
| 129 | } | 175 | } |
| 130 | 176 | ||
| 131 | /* | 177 | /* |
| @@ -162,7 +208,7 @@ void __init sem_init (void) | |||
| 162 | */ | 208 | */ |
| 163 | #define IN_WAKEUP 1 | 209 | #define IN_WAKEUP 1 |
| 164 | 210 | ||
| 165 | static int newary (key_t key, int nsems, int semflg) | 211 | static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg) |
| 166 | { | 212 | { |
| 167 | int id; | 213 | int id; |
| 168 | int retval; | 214 | int retval; |
| @@ -171,7 +217,7 @@ static int newary (key_t key, int nsems, int semflg) | |||
| 171 | 217 | ||
| 172 | if (!nsems) | 218 | if (!nsems) |
| 173 | return -EINVAL; | 219 | return -EINVAL; |
| 174 | if (used_sems + nsems > sc_semmns) | 220 | if (ns->used_sems + nsems > ns->sc_semmns) |
| 175 | return -ENOSPC; | 221 | return -ENOSPC; |
| 176 | 222 | ||
| 177 | size = sizeof (*sma) + nsems * sizeof (struct sem); | 223 | size = sizeof (*sma) + nsems * sizeof (struct sem); |
| @@ -191,15 +237,15 @@ static int newary (key_t key, int nsems, int semflg) | |||
| 191 | return retval; | 237 | return retval; |
| 192 | } | 238 | } |
| 193 | 239 | ||
| 194 | id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); | 240 | id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); |
| 195 | if(id == -1) { | 241 | if(id == -1) { |
| 196 | security_sem_free(sma); | 242 | security_sem_free(sma); |
| 197 | ipc_rcu_putref(sma); | 243 | ipc_rcu_putref(sma); |
| 198 | return -ENOSPC; | 244 | return -ENOSPC; |
| 199 | } | 245 | } |
| 200 | used_sems += nsems; | 246 | ns->used_sems += nsems; |
| 201 | 247 | ||
| 202 | sma->sem_id = sem_buildid(id, sma->sem_perm.seq); | 248 | sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq); |
| 203 | sma->sem_base = (struct sem *) &sma[1]; | 249 | sma->sem_base = (struct sem *) &sma[1]; |
| 204 | /* sma->sem_pending = NULL; */ | 250 | /* sma->sem_pending = NULL; */ |
| 205 | sma->sem_pending_last = &sma->sem_pending; | 251 | sma->sem_pending_last = &sma->sem_pending; |
| @@ -215,29 +261,32 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) | |||
| 215 | { | 261 | { |
| 216 | int id, err = -EINVAL; | 262 | int id, err = -EINVAL; |
| 217 | struct sem_array *sma; | 263 | struct sem_array *sma; |
| 264 | struct ipc_namespace *ns; | ||
| 265 | |||
| 266 | ns = current->nsproxy->ipc_ns; | ||
| 218 | 267 | ||
| 219 | if (nsems < 0 || nsems > sc_semmsl) | 268 | if (nsems < 0 || nsems > ns->sc_semmsl) |
| 220 | return -EINVAL; | 269 | return -EINVAL; |
| 221 | mutex_lock(&sem_ids.mutex); | 270 | mutex_lock(&sem_ids(ns).mutex); |
| 222 | 271 | ||
| 223 | if (key == IPC_PRIVATE) { | 272 | if (key == IPC_PRIVATE) { |
| 224 | err = newary(key, nsems, semflg); | 273 | err = newary(ns, key, nsems, semflg); |
| 225 | } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */ | 274 | } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */ |
| 226 | if (!(semflg & IPC_CREAT)) | 275 | if (!(semflg & IPC_CREAT)) |
| 227 | err = -ENOENT; | 276 | err = -ENOENT; |
| 228 | else | 277 | else |
| 229 | err = newary(key, nsems, semflg); | 278 | err = newary(ns, key, nsems, semflg); |
| 230 | } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { | 279 | } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { |
| 231 | err = -EEXIST; | 280 | err = -EEXIST; |
| 232 | } else { | 281 | } else { |
| 233 | sma = sem_lock(id); | 282 | sma = sem_lock(ns, id); |
| 234 | BUG_ON(sma==NULL); | 283 | BUG_ON(sma==NULL); |
| 235 | if (nsems > sma->sem_nsems) | 284 | if (nsems > sma->sem_nsems) |
| 236 | err = -EINVAL; | 285 | err = -EINVAL; |
| 237 | else if (ipcperms(&sma->sem_perm, semflg)) | 286 | else if (ipcperms(&sma->sem_perm, semflg)) |
| 238 | err = -EACCES; | 287 | err = -EACCES; |
| 239 | else { | 288 | else { |
| 240 | int semid = sem_buildid(id, sma->sem_perm.seq); | 289 | int semid = sem_buildid(ns, id, sma->sem_perm.seq); |
| 241 | err = security_sem_associate(sma, semflg); | 290 | err = security_sem_associate(sma, semflg); |
| 242 | if (!err) | 291 | if (!err) |
| 243 | err = semid; | 292 | err = semid; |
| @@ -245,7 +294,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) | |||
| 245 | sem_unlock(sma); | 294 | sem_unlock(sma); |
| 246 | } | 295 | } |
| 247 | 296 | ||
| 248 | mutex_unlock(&sem_ids.mutex); | 297 | mutex_unlock(&sem_ids(ns).mutex); |
| 249 | return err; | 298 | return err; |
| 250 | } | 299 | } |
| 251 | 300 | ||
| @@ -444,7 +493,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum) | |||
| 444 | * the spinlock for this semaphore set hold. sem_ids.mutex remains locked | 493 | * the spinlock for this semaphore set hold. sem_ids.mutex remains locked |
| 445 | * on exit. | 494 | * on exit. |
| 446 | */ | 495 | */ |
| 447 | static void freeary (struct sem_array *sma, int id) | 496 | static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id) |
| 448 | { | 497 | { |
| 449 | struct sem_undo *un; | 498 | struct sem_undo *un; |
| 450 | struct sem_queue *q; | 499 | struct sem_queue *q; |
| @@ -472,10 +521,10 @@ static void freeary (struct sem_array *sma, int id) | |||
| 472 | } | 521 | } |
| 473 | 522 | ||
| 474 | /* Remove the semaphore set from the ID array*/ | 523 | /* Remove the semaphore set from the ID array*/ |
| 475 | sma = sem_rmid(id); | 524 | sma = sem_rmid(ns, id); |
| 476 | sem_unlock(sma); | 525 | sem_unlock(sma); |
| 477 | 526 | ||
| 478 | used_sems -= sma->sem_nsems; | 527 | ns->used_sems -= sma->sem_nsems; |
| 479 | size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); | 528 | size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); |
| 480 | security_sem_free(sma); | 529 | security_sem_free(sma); |
| 481 | ipc_rcu_putref(sma); | 530 | ipc_rcu_putref(sma); |
| @@ -503,7 +552,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, | |||
| 503 | } | 552 | } |
| 504 | } | 553 | } |
| 505 | 554 | ||
| 506 | static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg) | 555 | static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, |
| 556 | int cmd, int version, union semun arg) | ||
| 507 | { | 557 | { |
| 508 | int err = -EINVAL; | 558 | int err = -EINVAL; |
| 509 | struct sem_array *sma; | 559 | struct sem_array *sma; |
| @@ -520,24 +570,24 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu | |||
| 520 | return err; | 570 | return err; |
| 521 | 571 | ||
| 522 | memset(&seminfo,0,sizeof(seminfo)); | 572 | memset(&seminfo,0,sizeof(seminfo)); |
| 523 | seminfo.semmni = sc_semmni; | 573 | seminfo.semmni = ns->sc_semmni; |
| 524 | seminfo.semmns = sc_semmns; | 574 | seminfo.semmns = ns->sc_semmns; |
| 525 | seminfo.semmsl = sc_semmsl; | 575 | seminfo.semmsl = ns->sc_semmsl; |
| 526 | seminfo.semopm = sc_semopm; | 576 | seminfo.semopm = ns->sc_semopm; |
| 527 | seminfo.semvmx = SEMVMX; | 577 | seminfo.semvmx = SEMVMX; |
| 528 | seminfo.semmnu = SEMMNU; | 578 | seminfo.semmnu = SEMMNU; |
| 529 | seminfo.semmap = SEMMAP; | 579 | seminfo.semmap = SEMMAP; |
| 530 | seminfo.semume = SEMUME; | 580 | seminfo.semume = SEMUME; |
| 531 | mutex_lock(&sem_ids.mutex); | 581 | mutex_lock(&sem_ids(ns).mutex); |
| 532 | if (cmd == SEM_INFO) { | 582 | if (cmd == SEM_INFO) { |
| 533 | seminfo.semusz = sem_ids.in_use; | 583 | seminfo.semusz = sem_ids(ns).in_use; |
| 534 | seminfo.semaem = used_sems; | 584 | seminfo.semaem = ns->used_sems; |
| 535 | } else { | 585 | } else { |
| 536 | seminfo.semusz = SEMUSZ; | 586 | seminfo.semusz = SEMUSZ; |
| 537 | seminfo.semaem = SEMAEM; | 587 | seminfo.semaem = SEMAEM; |
| 538 | } | 588 | } |
| 539 | max_id = sem_ids.max_id; | 589 | max_id = sem_ids(ns).max_id; |
| 540 | mutex_unlock(&sem_ids.mutex); | 590 | mutex_unlock(&sem_ids(ns).mutex); |
| 541 | if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) | 591 | if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) |
| 542 | return -EFAULT; | 592 | return -EFAULT; |
| 543 | return (max_id < 0) ? 0: max_id; | 593 | return (max_id < 0) ? 0: max_id; |
| @@ -547,12 +597,12 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu | |||
| 547 | struct semid64_ds tbuf; | 597 | struct semid64_ds tbuf; |
| 548 | int id; | 598 | int id; |
| 549 | 599 | ||
| 550 | if(semid >= sem_ids.entries->size) | 600 | if(semid >= sem_ids(ns).entries->size) |
| 551 | return -EINVAL; | 601 | return -EINVAL; |
| 552 | 602 | ||
| 553 | memset(&tbuf,0,sizeof(tbuf)); | 603 | memset(&tbuf,0,sizeof(tbuf)); |
| 554 | 604 | ||
| 555 | sma = sem_lock(semid); | 605 | sma = sem_lock(ns, semid); |
| 556 | if(sma == NULL) | 606 | if(sma == NULL) |
| 557 | return -EINVAL; | 607 | return -EINVAL; |
| 558 | 608 | ||
| @@ -564,7 +614,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu | |||
| 564 | if (err) | 614 | if (err) |
| 565 | goto out_unlock; | 615 | goto out_unlock; |
| 566 | 616 | ||
| 567 | id = sem_buildid(semid, sma->sem_perm.seq); | 617 | id = sem_buildid(ns, semid, sma->sem_perm.seq); |
| 568 | 618 | ||
| 569 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); | 619 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); |
| 570 | tbuf.sem_otime = sma->sem_otime; | 620 | tbuf.sem_otime = sma->sem_otime; |
| @@ -584,7 +634,8 @@ out_unlock: | |||
| 584 | return err; | 634 | return err; |
| 585 | } | 635 | } |
| 586 | 636 | ||
| 587 | static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg) | 637 | static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, |
| 638 | int cmd, int version, union semun arg) | ||
| 588 | { | 639 | { |
| 589 | struct sem_array *sma; | 640 | struct sem_array *sma; |
| 590 | struct sem* curr; | 641 | struct sem* curr; |
| @@ -593,14 +644,14 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun | |||
| 593 | ushort* sem_io = fast_sem_io; | 644 | ushort* sem_io = fast_sem_io; |
| 594 | int nsems; | 645 | int nsems; |
| 595 | 646 | ||
| 596 | sma = sem_lock(semid); | 647 | sma = sem_lock(ns, semid); |
| 597 | if(sma==NULL) | 648 | if(sma==NULL) |
| 598 | return -EINVAL; | 649 | return -EINVAL; |
| 599 | 650 | ||
| 600 | nsems = sma->sem_nsems; | 651 | nsems = sma->sem_nsems; |
| 601 | 652 | ||
| 602 | err=-EIDRM; | 653 | err=-EIDRM; |
| 603 | if (sem_checkid(sma,semid)) | 654 | if (sem_checkid(ns,sma,semid)) |
| 604 | goto out_unlock; | 655 | goto out_unlock; |
| 605 | 656 | ||
| 606 | err = -EACCES; | 657 | err = -EACCES; |
| @@ -802,7 +853,8 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __ | |||
| 802 | } | 853 | } |
| 803 | } | 854 | } |
| 804 | 855 | ||
| 805 | static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg) | 856 | static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, |
| 857 | int cmd, int version, union semun arg) | ||
| 806 | { | 858 | { |
| 807 | struct sem_array *sma; | 859 | struct sem_array *sma; |
| 808 | int err; | 860 | int err; |
| @@ -813,11 +865,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
| 813 | if(copy_semid_from_user (&setbuf, arg.buf, version)) | 865 | if(copy_semid_from_user (&setbuf, arg.buf, version)) |
| 814 | return -EFAULT; | 866 | return -EFAULT; |
| 815 | } | 867 | } |
| 816 | sma = sem_lock(semid); | 868 | sma = sem_lock(ns, semid); |
| 817 | if(sma==NULL) | 869 | if(sma==NULL) |
| 818 | return -EINVAL; | 870 | return -EINVAL; |
| 819 | 871 | ||
| 820 | if (sem_checkid(sma,semid)) { | 872 | if (sem_checkid(ns,sma,semid)) { |
| 821 | err=-EIDRM; | 873 | err=-EIDRM; |
| 822 | goto out_unlock; | 874 | goto out_unlock; |
| 823 | } | 875 | } |
| @@ -844,7 +896,7 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
| 844 | 896 | ||
| 845 | switch(cmd){ | 897 | switch(cmd){ |
| 846 | case IPC_RMID: | 898 | case IPC_RMID: |
| 847 | freeary(sma, semid); | 899 | freeary(ns, sma, semid); |
| 848 | err = 0; | 900 | err = 0; |
| 849 | break; | 901 | break; |
| 850 | case IPC_SET: | 902 | case IPC_SET: |
| @@ -872,17 +924,19 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) | |||
| 872 | { | 924 | { |
| 873 | int err = -EINVAL; | 925 | int err = -EINVAL; |
| 874 | int version; | 926 | int version; |
| 927 | struct ipc_namespace *ns; | ||
| 875 | 928 | ||
| 876 | if (semid < 0) | 929 | if (semid < 0) |
| 877 | return -EINVAL; | 930 | return -EINVAL; |
| 878 | 931 | ||
| 879 | version = ipc_parse_version(&cmd); | 932 | version = ipc_parse_version(&cmd); |
| 933 | ns = current->nsproxy->ipc_ns; | ||
| 880 | 934 | ||
| 881 | switch(cmd) { | 935 | switch(cmd) { |
| 882 | case IPC_INFO: | 936 | case IPC_INFO: |
| 883 | case SEM_INFO: | 937 | case SEM_INFO: |
| 884 | case SEM_STAT: | 938 | case SEM_STAT: |
| 885 | err = semctl_nolock(semid,semnum,cmd,version,arg); | 939 | err = semctl_nolock(ns,semid,semnum,cmd,version,arg); |
| 886 | return err; | 940 | return err; |
| 887 | case GETALL: | 941 | case GETALL: |
| 888 | case GETVAL: | 942 | case GETVAL: |
| @@ -892,13 +946,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) | |||
| 892 | case IPC_STAT: | 946 | case IPC_STAT: |
| 893 | case SETVAL: | 947 | case SETVAL: |
| 894 | case SETALL: | 948 | case SETALL: |
| 895 | err = semctl_main(semid,semnum,cmd,version,arg); | 949 | err = semctl_main(ns,semid,semnum,cmd,version,arg); |
| 896 | return err; | 950 | return err; |
| 897 | case IPC_RMID: | 951 | case IPC_RMID: |
| 898 | case IPC_SET: | 952 | case IPC_SET: |
| 899 | mutex_lock(&sem_ids.mutex); | 953 | mutex_lock(&sem_ids(ns).mutex); |
| 900 | err = semctl_down(semid,semnum,cmd,version,arg); | 954 | err = semctl_down(ns,semid,semnum,cmd,version,arg); |
| 901 | mutex_unlock(&sem_ids.mutex); | 955 | mutex_unlock(&sem_ids(ns).mutex); |
| 902 | return err; | 956 | return err; |
| 903 | default: | 957 | default: |
| 904 | return -EINVAL; | 958 | return -EINVAL; |
| @@ -986,7 +1040,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | |||
| 986 | return un; | 1040 | return un; |
| 987 | } | 1041 | } |
| 988 | 1042 | ||
| 989 | static struct sem_undo *find_undo(int semid) | 1043 | static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) |
| 990 | { | 1044 | { |
| 991 | struct sem_array *sma; | 1045 | struct sem_array *sma; |
| 992 | struct sem_undo_list *ulp; | 1046 | struct sem_undo_list *ulp; |
| @@ -1005,12 +1059,12 @@ static struct sem_undo *find_undo(int semid) | |||
| 1005 | goto out; | 1059 | goto out; |
| 1006 | 1060 | ||
| 1007 | /* no undo structure around - allocate one. */ | 1061 | /* no undo structure around - allocate one. */ |
| 1008 | sma = sem_lock(semid); | 1062 | sma = sem_lock(ns, semid); |
| 1009 | un = ERR_PTR(-EINVAL); | 1063 | un = ERR_PTR(-EINVAL); |
| 1010 | if(sma==NULL) | 1064 | if(sma==NULL) |
| 1011 | goto out; | 1065 | goto out; |
| 1012 | un = ERR_PTR(-EIDRM); | 1066 | un = ERR_PTR(-EIDRM); |
| 1013 | if (sem_checkid(sma,semid)) { | 1067 | if (sem_checkid(ns,sma,semid)) { |
| 1014 | sem_unlock(sma); | 1068 | sem_unlock(sma); |
| 1015 | goto out; | 1069 | goto out; |
| 1016 | } | 1070 | } |
| @@ -1070,10 +1124,13 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, | |||
| 1070 | int undos = 0, alter = 0, max; | 1124 | int undos = 0, alter = 0, max; |
| 1071 | struct sem_queue queue; | 1125 | struct sem_queue queue; |
| 1072 | unsigned long jiffies_left = 0; | 1126 | unsigned long jiffies_left = 0; |
| 1127 | struct ipc_namespace *ns; | ||
| 1128 | |||
| 1129 | ns = current->nsproxy->ipc_ns; | ||
| 1073 | 1130 | ||
| 1074 | if (nsops < 1 || semid < 0) | 1131 | if (nsops < 1 || semid < 0) |
| 1075 | return -EINVAL; | 1132 | return -EINVAL; |
| 1076 | if (nsops > sc_semopm) | 1133 | if (nsops > ns->sc_semopm) |
| 1077 | return -E2BIG; | 1134 | return -E2BIG; |
| 1078 | if(nsops > SEMOPM_FAST) { | 1135 | if(nsops > SEMOPM_FAST) { |
| 1079 | sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); | 1136 | sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); |
| @@ -1109,7 +1166,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, | |||
| 1109 | 1166 | ||
| 1110 | retry_undos: | 1167 | retry_undos: |
| 1111 | if (undos) { | 1168 | if (undos) { |
| 1112 | un = find_undo(semid); | 1169 | un = find_undo(ns, semid); |
| 1113 | if (IS_ERR(un)) { | 1170 | if (IS_ERR(un)) { |
| 1114 | error = PTR_ERR(un); | 1171 | error = PTR_ERR(un); |
| 1115 | goto out_free; | 1172 | goto out_free; |
| @@ -1117,12 +1174,12 @@ retry_undos: | |||
| 1117 | } else | 1174 | } else |
| 1118 | un = NULL; | 1175 | un = NULL; |
| 1119 | 1176 | ||
| 1120 | sma = sem_lock(semid); | 1177 | sma = sem_lock(ns, semid); |
| 1121 | error=-EINVAL; | 1178 | error=-EINVAL; |
| 1122 | if(sma==NULL) | 1179 | if(sma==NULL) |
| 1123 | goto out_free; | 1180 | goto out_free; |
| 1124 | error = -EIDRM; | 1181 | error = -EIDRM; |
| 1125 | if (sem_checkid(sma,semid)) | 1182 | if (sem_checkid(ns,sma,semid)) |
| 1126 | goto out_unlock_free; | 1183 | goto out_unlock_free; |
| 1127 | /* | 1184 | /* |
| 1128 | * semid identifies are not unique - find_undo may have | 1185 | * semid identifies are not unique - find_undo may have |
| @@ -1190,7 +1247,7 @@ retry_undos: | |||
| 1190 | goto out_free; | 1247 | goto out_free; |
| 1191 | } | 1248 | } |
| 1192 | 1249 | ||
| 1193 | sma = sem_lock(semid); | 1250 | sma = sem_lock(ns, semid); |
| 1194 | if(sma==NULL) { | 1251 | if(sma==NULL) { |
| 1195 | BUG_ON(queue.prev != NULL); | 1252 | BUG_ON(queue.prev != NULL); |
| 1196 | error = -EIDRM; | 1253 | error = -EIDRM; |
| @@ -1267,6 +1324,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 1267 | { | 1324 | { |
| 1268 | struct sem_undo_list *undo_list; | 1325 | struct sem_undo_list *undo_list; |
| 1269 | struct sem_undo *u, **up; | 1326 | struct sem_undo *u, **up; |
| 1327 | struct ipc_namespace *ns; | ||
| 1270 | 1328 | ||
| 1271 | undo_list = tsk->sysvsem.undo_list; | 1329 | undo_list = tsk->sysvsem.undo_list; |
| 1272 | if (!undo_list) | 1330 | if (!undo_list) |
| @@ -1275,6 +1333,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 1275 | if (!atomic_dec_and_test(&undo_list->refcnt)) | 1333 | if (!atomic_dec_and_test(&undo_list->refcnt)) |
| 1276 | return; | 1334 | return; |
| 1277 | 1335 | ||
| 1336 | ns = tsk->nsproxy->ipc_ns; | ||
| 1278 | /* There's no need to hold the semundo list lock, as current | 1337 | /* There's no need to hold the semundo list lock, as current |
| 1279 | * is the last task exiting for this undo list. | 1338 | * is the last task exiting for this undo list. |
| 1280 | */ | 1339 | */ |
| @@ -1288,14 +1347,14 @@ void exit_sem(struct task_struct *tsk) | |||
| 1288 | 1347 | ||
| 1289 | if(semid == -1) | 1348 | if(semid == -1) |
| 1290 | continue; | 1349 | continue; |
| 1291 | sma = sem_lock(semid); | 1350 | sma = sem_lock(ns, semid); |
| 1292 | if (sma == NULL) | 1351 | if (sma == NULL) |
| 1293 | continue; | 1352 | continue; |
| 1294 | 1353 | ||
| 1295 | if (u->semid == -1) | 1354 | if (u->semid == -1) |
| 1296 | goto next_entry; | 1355 | goto next_entry; |
| 1297 | 1356 | ||
| 1298 | BUG_ON(sem_checkid(sma,u->semid)); | 1357 | BUG_ON(sem_checkid(ns,sma,u->semid)); |
| 1299 | 1358 | ||
| 1300 | /* remove u from the sma->undo list */ | 1359 | /* remove u from the sma->undo list */ |
| 1301 | for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { | 1360 | for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { |
