diff options
Diffstat (limited to 'ipc')
-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) { |