diff options
author | Nadia Derbey <Nadia.Derbey@bull.net> | 2007-10-19 02:40:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 14:53:44 -0400 |
commit | 023a53557ea0e987b002e9a844242ef0b0aa1eb3 (patch) | |
tree | 7f3accdd7cb1d801607bf71e56b9b99e9c7ff7ca | |
parent | 637c36634029e4e7c81112796dafc32d56355b4a (diff) |
ipc: integrate ipc_checkid() into ipc_lock()
This patch introduces a new ipc_lock_check() routine interface:
. each time ipc_checkid() is called, this is done after calling ipc_lock().
ipc_checkid() is now called from inside ipc_lock_check().
[akpm@linux-foundation.org: build fix]
[akpm@linux-foundation.org: fix RCU locking]
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | ipc/msg.c | 62 | ||||
-rw-r--r-- | ipc/sem.c | 70 | ||||
-rw-r--r-- | ipc/shm.c | 90 | ||||
-rw-r--r-- | ipc/util.c | 23 | ||||
-rw-r--r-- | ipc/util.h | 43 |
5 files changed, 152 insertions, 136 deletions
@@ -73,10 +73,7 @@ static struct ipc_ids init_msg_ids; | |||
73 | 73 | ||
74 | #define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS])) | 74 | #define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS])) |
75 | 75 | ||
76 | #define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id)) | ||
77 | #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) | 76 | #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) |
78 | #define msg_checkid(ns, msq, msgid) \ | ||
79 | ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid) | ||
80 | #define msg_buildid(ns, id, seq) \ | 77 | #define msg_buildid(ns, id, seq) \ |
81 | ipc_buildid(&msg_ids(ns), id, seq) | 78 | ipc_buildid(&msg_ids(ns), id, seq) |
82 | 79 | ||
@@ -139,6 +136,17 @@ void __init msg_init(void) | |||
139 | IPC_MSG_IDS, sysvipc_msg_proc_show); | 136 | IPC_MSG_IDS, sysvipc_msg_proc_show); |
140 | } | 137 | } |
141 | 138 | ||
139 | static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id) | ||
140 | { | ||
141 | return (struct msg_queue *) ipc_lock(&msg_ids(ns), id); | ||
142 | } | ||
143 | |||
144 | static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns, | ||
145 | int id) | ||
146 | { | ||
147 | return (struct msg_queue *) ipc_lock_check(&msg_ids(ns), id); | ||
148 | } | ||
149 | |||
142 | static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s) | 150 | static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s) |
143 | { | 151 | { |
144 | ipc_rmid(&msg_ids(ns), &s->q_perm); | 152 | ipc_rmid(&msg_ids(ns), &s->q_perm); |
@@ -445,18 +453,15 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
445 | if (!buf) | 453 | if (!buf) |
446 | return -EFAULT; | 454 | return -EFAULT; |
447 | 455 | ||
448 | memset(&tbuf, 0, sizeof(tbuf)); | ||
449 | |||
450 | msq = msg_lock(ns, msqid); | ||
451 | if (msq == NULL) | ||
452 | return -EINVAL; | ||
453 | |||
454 | if (cmd == MSG_STAT) { | 456 | if (cmd == MSG_STAT) { |
457 | msq = msg_lock(ns, msqid); | ||
458 | if (IS_ERR(msq)) | ||
459 | return PTR_ERR(msq); | ||
455 | success_return = msq->q_perm.id; | 460 | success_return = msq->q_perm.id; |
456 | } else { | 461 | } else { |
457 | err = -EIDRM; | 462 | msq = msg_lock_check(ns, msqid); |
458 | if (msg_checkid(ns, msq, msqid)) | 463 | if (IS_ERR(msq)) |
459 | goto out_unlock; | 464 | return PTR_ERR(msq); |
460 | success_return = 0; | 465 | success_return = 0; |
461 | } | 466 | } |
462 | err = -EACCES; | 467 | err = -EACCES; |
@@ -467,6 +472,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
467 | if (err) | 472 | if (err) |
468 | goto out_unlock; | 473 | goto out_unlock; |
469 | 474 | ||
475 | memset(&tbuf, 0, sizeof(tbuf)); | ||
476 | |||
470 | kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); | 477 | kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); |
471 | tbuf.msg_stime = msq->q_stime; | 478 | tbuf.msg_stime = msq->q_stime; |
472 | tbuf.msg_rtime = msq->q_rtime; | 479 | tbuf.msg_rtime = msq->q_rtime; |
@@ -494,14 +501,12 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
494 | } | 501 | } |
495 | 502 | ||
496 | mutex_lock(&msg_ids(ns).mutex); | 503 | mutex_lock(&msg_ids(ns).mutex); |
497 | msq = msg_lock(ns, msqid); | 504 | msq = msg_lock_check(ns, msqid); |
498 | err = -EINVAL; | 505 | if (IS_ERR(msq)) { |
499 | if (msq == NULL) | 506 | err = PTR_ERR(msq); |
500 | goto out_up; | 507 | goto out_up; |
508 | } | ||
501 | 509 | ||
502 | err = -EIDRM; | ||
503 | if (msg_checkid(ns, msq, msqid)) | ||
504 | goto out_unlock_up; | ||
505 | ipcp = &msq->q_perm; | 510 | ipcp = &msq->q_perm; |
506 | 511 | ||
507 | err = audit_ipc_obj(ipcp); | 512 | err = audit_ipc_obj(ipcp); |
@@ -644,14 +649,11 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
644 | msg->m_type = mtype; | 649 | msg->m_type = mtype; |
645 | msg->m_ts = msgsz; | 650 | msg->m_ts = msgsz; |
646 | 651 | ||
647 | msq = msg_lock(ns, msqid); | 652 | msq = msg_lock_check(ns, msqid); |
648 | err = -EINVAL; | 653 | if (IS_ERR(msq)) { |
649 | if (msq == NULL) | 654 | err = PTR_ERR(msq); |
650 | goto out_free; | 655 | goto out_free; |
651 | 656 | } | |
652 | err= -EIDRM; | ||
653 | if (msg_checkid(ns, msq, msqid)) | ||
654 | goto out_unlock_free; | ||
655 | 657 | ||
656 | for (;;) { | 658 | for (;;) { |
657 | struct msg_sender s; | 659 | struct msg_sender s; |
@@ -758,13 +760,9 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext, | |||
758 | mode = convert_mode(&msgtyp, msgflg); | 760 | mode = convert_mode(&msgtyp, msgflg); |
759 | ns = current->nsproxy->ipc_ns; | 761 | ns = current->nsproxy->ipc_ns; |
760 | 762 | ||
761 | msq = msg_lock(ns, msqid); | 763 | msq = msg_lock_check(ns, msqid); |
762 | if (msq == NULL) | 764 | if (IS_ERR(msq)) |
763 | return -EINVAL; | 765 | return PTR_ERR(msq); |
764 | |||
765 | msg = ERR_PTR(-EIDRM); | ||
766 | if (msg_checkid(ns, msq, msqid)) | ||
767 | goto out_unlock; | ||
768 | 766 | ||
769 | for (;;) { | 767 | for (;;) { |
770 | struct msg_receiver msr_d; | 768 | struct msg_receiver msr_d; |
@@ -88,7 +88,6 @@ | |||
88 | 88 | ||
89 | #define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) | 89 | #define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) |
90 | 90 | ||
91 | #define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id)) | ||
92 | #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) | 91 | #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) |
93 | #define sem_checkid(ns, sma, semid) \ | 92 | #define sem_checkid(ns, sma, semid) \ |
94 | ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid) | 93 | ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid) |
@@ -175,6 +174,17 @@ void __init sem_init (void) | |||
175 | IPC_SEM_IDS, sysvipc_sem_proc_show); | 174 | IPC_SEM_IDS, sysvipc_sem_proc_show); |
176 | } | 175 | } |
177 | 176 | ||
177 | static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id) | ||
178 | { | ||
179 | return (struct sem_array *) ipc_lock(&sem_ids(ns), id); | ||
180 | } | ||
181 | |||
182 | static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns, | ||
183 | int id) | ||
184 | { | ||
185 | return (struct sem_array *) ipc_lock_check(&sem_ids(ns), id); | ||
186 | } | ||
187 | |||
178 | static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) | 188 | static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) |
179 | { | 189 | { |
180 | ipc_rmid(&sem_ids(ns), &s->sem_perm); | 190 | ipc_rmid(&sem_ids(ns), &s->sem_perm); |
@@ -599,11 +609,9 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, | |||
599 | struct semid64_ds tbuf; | 609 | struct semid64_ds tbuf; |
600 | int id; | 610 | int id; |
601 | 611 | ||
602 | memset(&tbuf,0,sizeof(tbuf)); | ||
603 | |||
604 | sma = sem_lock(ns, semid); | 612 | sma = sem_lock(ns, semid); |
605 | if(sma == NULL) | 613 | if (IS_ERR(sma)) |
606 | return -EINVAL; | 614 | return PTR_ERR(sma); |
607 | 615 | ||
608 | err = -EACCES; | 616 | err = -EACCES; |
609 | if (ipcperms (&sma->sem_perm, S_IRUGO)) | 617 | if (ipcperms (&sma->sem_perm, S_IRUGO)) |
@@ -615,6 +623,8 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, | |||
615 | 623 | ||
616 | id = sma->sem_perm.id; | 624 | id = sma->sem_perm.id; |
617 | 625 | ||
626 | memset(&tbuf, 0, sizeof(tbuf)); | ||
627 | |||
618 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); | 628 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); |
619 | tbuf.sem_otime = sma->sem_otime; | 629 | tbuf.sem_otime = sma->sem_otime; |
620 | tbuf.sem_ctime = sma->sem_ctime; | 630 | tbuf.sem_ctime = sma->sem_ctime; |
@@ -643,16 +653,12 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
643 | ushort* sem_io = fast_sem_io; | 653 | ushort* sem_io = fast_sem_io; |
644 | int nsems; | 654 | int nsems; |
645 | 655 | ||
646 | sma = sem_lock(ns, semid); | 656 | sma = sem_lock_check(ns, semid); |
647 | if(sma==NULL) | 657 | if (IS_ERR(sma)) |
648 | return -EINVAL; | 658 | return PTR_ERR(sma); |
649 | 659 | ||
650 | nsems = sma->sem_nsems; | 660 | nsems = sma->sem_nsems; |
651 | 661 | ||
652 | err=-EIDRM; | ||
653 | if (sem_checkid(ns,sma,semid)) | ||
654 | goto out_unlock; | ||
655 | |||
656 | err = -EACCES; | 662 | err = -EACCES; |
657 | if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) | 663 | if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) |
658 | goto out_unlock; | 664 | goto out_unlock; |
@@ -864,14 +870,10 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, | |||
864 | if(copy_semid_from_user (&setbuf, arg.buf, version)) | 870 | if(copy_semid_from_user (&setbuf, arg.buf, version)) |
865 | return -EFAULT; | 871 | return -EFAULT; |
866 | } | 872 | } |
867 | sma = sem_lock(ns, semid); | 873 | sma = sem_lock_check(ns, semid); |
868 | if(sma==NULL) | 874 | if (IS_ERR(sma)) |
869 | return -EINVAL; | 875 | return PTR_ERR(sma); |
870 | 876 | ||
871 | if (sem_checkid(ns,sma,semid)) { | ||
872 | err=-EIDRM; | ||
873 | goto out_unlock; | ||
874 | } | ||
875 | ipcp = &sma->sem_perm; | 877 | ipcp = &sma->sem_perm; |
876 | 878 | ||
877 | err = audit_ipc_obj(ipcp); | 879 | err = audit_ipc_obj(ipcp); |
@@ -1055,15 +1057,10 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) | |||
1055 | goto out; | 1057 | goto out; |
1056 | 1058 | ||
1057 | /* no undo structure around - allocate one. */ | 1059 | /* no undo structure around - allocate one. */ |
1058 | sma = sem_lock(ns, semid); | 1060 | sma = sem_lock_check(ns, semid); |
1059 | un = ERR_PTR(-EINVAL); | 1061 | if (IS_ERR(sma)) |
1060 | if(sma==NULL) | 1062 | return ERR_PTR(PTR_ERR(sma)); |
1061 | goto out; | 1063 | |
1062 | un = ERR_PTR(-EIDRM); | ||
1063 | if (sem_checkid(ns,sma,semid)) { | ||
1064 | sem_unlock(sma); | ||
1065 | goto out; | ||
1066 | } | ||
1067 | nsems = sma->sem_nsems; | 1064 | nsems = sma->sem_nsems; |
1068 | ipc_rcu_getref(sma); | 1065 | ipc_rcu_getref(sma); |
1069 | sem_unlock(sma); | 1066 | sem_unlock(sma); |
@@ -1169,15 +1166,14 @@ retry_undos: | |||
1169 | } else | 1166 | } else |
1170 | un = NULL; | 1167 | un = NULL; |
1171 | 1168 | ||
1172 | sma = sem_lock(ns, semid); | 1169 | sma = sem_lock_check(ns, semid); |
1173 | error=-EINVAL; | 1170 | if (IS_ERR(sma)) { |
1174 | if(sma==NULL) | 1171 | error = PTR_ERR(sma); |
1175 | goto out_free; | 1172 | goto out_free; |
1176 | error = -EIDRM; | 1173 | } |
1177 | if (sem_checkid(ns,sma,semid)) | 1174 | |
1178 | goto out_unlock_free; | ||
1179 | /* | 1175 | /* |
1180 | * semid identifies are not unique - find_undo may have | 1176 | * semid identifiers are not unique - find_undo may have |
1181 | * allocated an undo structure, it was invalidated by an RMID | 1177 | * allocated an undo structure, it was invalidated by an RMID |
1182 | * and now a new array with received the same id. Check and retry. | 1178 | * and now a new array with received the same id. Check and retry. |
1183 | */ | 1179 | */ |
@@ -1243,7 +1239,7 @@ retry_undos: | |||
1243 | } | 1239 | } |
1244 | 1240 | ||
1245 | sma = sem_lock(ns, semid); | 1241 | sma = sem_lock(ns, semid); |
1246 | if(sma==NULL) { | 1242 | if (IS_ERR(sma)) { |
1247 | BUG_ON(queue.prev != NULL); | 1243 | BUG_ON(queue.prev != NULL); |
1248 | error = -EIDRM; | 1244 | error = -EIDRM; |
1249 | goto out_free; | 1245 | goto out_free; |
@@ -1343,7 +1339,7 @@ void exit_sem(struct task_struct *tsk) | |||
1343 | if(semid == -1) | 1339 | if(semid == -1) |
1344 | continue; | 1340 | continue; |
1345 | sma = sem_lock(ns, semid); | 1341 | sma = sem_lock(ns, semid); |
1346 | if (sma == NULL) | 1342 | if (IS_ERR(sma)) |
1347 | continue; | 1343 | continue; |
1348 | 1344 | ||
1349 | if (u->semid == -1) | 1345 | if (u->semid == -1) |
@@ -59,8 +59,6 @@ static struct ipc_ids init_shm_ids; | |||
59 | 59 | ||
60 | #define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) | 60 | #define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) |
61 | 61 | ||
62 | #define shm_lock(ns, id) \ | ||
63 | ((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id)) | ||
64 | #define shm_unlock(shp) \ | 62 | #define shm_unlock(shp) \ |
65 | ipc_unlock(&(shp)->shm_perm) | 63 | ipc_unlock(&(shp)->shm_perm) |
66 | #define shm_buildid(ns, id, seq) \ | 64 | #define shm_buildid(ns, id, seq) \ |
@@ -139,12 +137,15 @@ void __init shm_init (void) | |||
139 | IPC_SHM_IDS, sysvipc_shm_proc_show); | 137 | IPC_SHM_IDS, sysvipc_shm_proc_show); |
140 | } | 138 | } |
141 | 139 | ||
142 | static inline int shm_checkid(struct ipc_namespace *ns, | 140 | static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) |
143 | struct shmid_kernel *s, int id) | ||
144 | { | 141 | { |
145 | if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id)) | 142 | return (struct shmid_kernel *) ipc_lock(&shm_ids(ns), id); |
146 | return -EIDRM; | 143 | } |
147 | return 0; | 144 | |
145 | static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, | ||
146 | int id) | ||
147 | { | ||
148 | return (struct shmid_kernel *) ipc_lock_check(&shm_ids(ns), id); | ||
148 | } | 149 | } |
149 | 150 | ||
150 | static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s) | 151 | static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s) |
@@ -167,7 +168,7 @@ static void shm_open(struct vm_area_struct *vma) | |||
167 | struct shmid_kernel *shp; | 168 | struct shmid_kernel *shp; |
168 | 169 | ||
169 | shp = shm_lock(sfd->ns, sfd->id); | 170 | shp = shm_lock(sfd->ns, sfd->id); |
170 | BUG_ON(!shp); | 171 | BUG_ON(IS_ERR(shp)); |
171 | shp->shm_atim = get_seconds(); | 172 | shp->shm_atim = get_seconds(); |
172 | shp->shm_lprid = task_tgid_vnr(current); | 173 | shp->shm_lprid = task_tgid_vnr(current); |
173 | shp->shm_nattch++; | 174 | shp->shm_nattch++; |
@@ -213,7 +214,7 @@ static void shm_close(struct vm_area_struct *vma) | |||
213 | mutex_lock(&shm_ids(ns).mutex); | 214 | mutex_lock(&shm_ids(ns).mutex); |
214 | /* remove from the list of attaches of the shm segment */ | 215 | /* remove from the list of attaches of the shm segment */ |
215 | shp = shm_lock(ns, sfd->id); | 216 | shp = shm_lock(ns, sfd->id); |
216 | BUG_ON(!shp); | 217 | BUG_ON(IS_ERR(shp)); |
217 | shp->shm_lprid = task_tgid_vnr(current); | 218 | shp->shm_lprid = task_tgid_vnr(current); |
218 | shp->shm_dtim = get_seconds(); | 219 | shp->shm_dtim = get_seconds(); |
219 | shp->shm_nattch--; | 220 | shp->shm_nattch--; |
@@ -662,17 +663,25 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
662 | { | 663 | { |
663 | struct shmid64_ds tbuf; | 664 | struct shmid64_ds tbuf; |
664 | int result; | 665 | int result; |
665 | memset(&tbuf, 0, sizeof(tbuf)); | 666 | |
666 | shp = shm_lock(ns, shmid); | 667 | if (!buf) { |
667 | if(shp==NULL) { | 668 | err = -EFAULT; |
668 | err = -EINVAL; | ||
669 | goto out; | 669 | goto out; |
670 | } else if (cmd == SHM_STAT) { | 670 | } |
671 | |||
672 | if (cmd == SHM_STAT) { | ||
673 | shp = shm_lock(ns, shmid); | ||
674 | if (IS_ERR(shp)) { | ||
675 | err = PTR_ERR(shp); | ||
676 | goto out; | ||
677 | } | ||
671 | result = shp->shm_perm.id; | 678 | result = shp->shm_perm.id; |
672 | } else { | 679 | } else { |
673 | err = shm_checkid(ns, shp,shmid); | 680 | shp = shm_lock_check(ns, shmid); |
674 | if(err) | 681 | if (IS_ERR(shp)) { |
675 | goto out_unlock; | 682 | err = PTR_ERR(shp); |
683 | goto out; | ||
684 | } | ||
676 | result = 0; | 685 | result = 0; |
677 | } | 686 | } |
678 | err=-EACCES; | 687 | err=-EACCES; |
@@ -681,6 +690,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
681 | err = security_shm_shmctl(shp, cmd); | 690 | err = security_shm_shmctl(shp, cmd); |
682 | if (err) | 691 | if (err) |
683 | goto out_unlock; | 692 | goto out_unlock; |
693 | memset(&tbuf, 0, sizeof(tbuf)); | ||
684 | kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm); | 694 | kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm); |
685 | tbuf.shm_segsz = shp->shm_segsz; | 695 | tbuf.shm_segsz = shp->shm_segsz; |
686 | tbuf.shm_atime = shp->shm_atim; | 696 | tbuf.shm_atime = shp->shm_atim; |
@@ -699,14 +709,11 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
699 | case SHM_LOCK: | 709 | case SHM_LOCK: |
700 | case SHM_UNLOCK: | 710 | case SHM_UNLOCK: |
701 | { | 711 | { |
702 | shp = shm_lock(ns, shmid); | 712 | shp = shm_lock_check(ns, shmid); |
703 | if(shp==NULL) { | 713 | if (IS_ERR(shp)) { |
704 | err = -EINVAL; | 714 | err = PTR_ERR(shp); |
705 | goto out; | 715 | goto out; |
706 | } | 716 | } |
707 | err = shm_checkid(ns, shp,shmid); | ||
708 | if(err) | ||
709 | goto out_unlock; | ||
710 | 717 | ||
711 | err = audit_ipc_obj(&(shp->shm_perm)); | 718 | err = audit_ipc_obj(&(shp->shm_perm)); |
712 | if (err) | 719 | if (err) |
@@ -756,13 +763,11 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
756 | * the name away when the usage hits zero. | 763 | * the name away when the usage hits zero. |
757 | */ | 764 | */ |
758 | mutex_lock(&shm_ids(ns).mutex); | 765 | mutex_lock(&shm_ids(ns).mutex); |
759 | shp = shm_lock(ns, shmid); | 766 | shp = shm_lock_check(ns, shmid); |
760 | err = -EINVAL; | 767 | if (IS_ERR(shp)) { |
761 | if (shp == NULL) | 768 | err = PTR_ERR(shp); |
762 | goto out_up; | 769 | goto out_up; |
763 | err = shm_checkid(ns, shp, shmid); | 770 | } |
764 | if(err) | ||
765 | goto out_unlock_up; | ||
766 | 771 | ||
767 | err = audit_ipc_obj(&(shp->shm_perm)); | 772 | err = audit_ipc_obj(&(shp->shm_perm)); |
768 | if (err) | 773 | if (err) |
@@ -786,18 +791,21 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
786 | 791 | ||
787 | case IPC_SET: | 792 | case IPC_SET: |
788 | { | 793 | { |
794 | if (!buf) { | ||
795 | err = -EFAULT; | ||
796 | goto out; | ||
797 | } | ||
798 | |||
789 | if (copy_shmid_from_user (&setbuf, buf, version)) { | 799 | if (copy_shmid_from_user (&setbuf, buf, version)) { |
790 | err = -EFAULT; | 800 | err = -EFAULT; |
791 | goto out; | 801 | goto out; |
792 | } | 802 | } |
793 | mutex_lock(&shm_ids(ns).mutex); | 803 | mutex_lock(&shm_ids(ns).mutex); |
794 | shp = shm_lock(ns, shmid); | 804 | shp = shm_lock_check(ns, shmid); |
795 | err=-EINVAL; | 805 | if (IS_ERR(shp)) { |
796 | if(shp==NULL) | 806 | err = PTR_ERR(shp); |
797 | goto out_up; | 807 | goto out_up; |
798 | err = shm_checkid(ns, shp,shmid); | 808 | } |
799 | if(err) | ||
800 | goto out_unlock_up; | ||
801 | err = audit_ipc_obj(&(shp->shm_perm)); | 809 | err = audit_ipc_obj(&(shp->shm_perm)); |
802 | if (err) | 810 | if (err) |
803 | goto out_unlock_up; | 811 | goto out_unlock_up; |
@@ -903,13 +911,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
903 | * additional creator id... | 911 | * additional creator id... |
904 | */ | 912 | */ |
905 | ns = current->nsproxy->ipc_ns; | 913 | ns = current->nsproxy->ipc_ns; |
906 | shp = shm_lock(ns, shmid); | 914 | shp = shm_lock_check(ns, shmid); |
907 | if(shp == NULL) | 915 | if (IS_ERR(shp)) { |
916 | err = PTR_ERR(shp); | ||
908 | goto out; | 917 | goto out; |
909 | 918 | } | |
910 | err = shm_checkid(ns, shp,shmid); | ||
911 | if (err) | ||
912 | goto out_unlock; | ||
913 | 919 | ||
914 | err = -EACCES; | 920 | err = -EACCES; |
915 | if (ipcperms(&shp->shm_perm, acc_mode)) | 921 | if (ipcperms(&shp->shm_perm, acc_mode)) |
@@ -970,7 +976,7 @@ invalid: | |||
970 | out_nattch: | 976 | out_nattch: |
971 | mutex_lock(&shm_ids(ns).mutex); | 977 | mutex_lock(&shm_ids(ns).mutex); |
972 | shp = shm_lock(ns, shmid); | 978 | shp = shm_lock(ns, shmid); |
973 | BUG_ON(!shp); | 979 | BUG_ON(IS_ERR(shp)); |
974 | shp->shm_nattch--; | 980 | shp->shm_nattch--; |
975 | if(shp->shm_nattch == 0 && | 981 | if(shp->shm_nattch == 0 && |
976 | shp->shm_perm.mode & SHM_DEST) | 982 | shp->shm_perm.mode & SHM_DEST) |
diff --git a/ipc/util.c b/ipc/util.c index e72865f677a7..9b0c4e7753af 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -678,7 +678,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) | |||
678 | out = idr_find(&ids->ipcs_idr, lid); | 678 | out = idr_find(&ids->ipcs_idr, lid); |
679 | if (out == NULL) { | 679 | if (out == NULL) { |
680 | rcu_read_unlock(); | 680 | rcu_read_unlock(); |
681 | return NULL; | 681 | return ERR_PTR(-EINVAL); |
682 | } | 682 | } |
683 | 683 | ||
684 | spin_lock(&out->lock); | 684 | spin_lock(&out->lock); |
@@ -689,36 +689,17 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) | |||
689 | if (out->deleted) { | 689 | if (out->deleted) { |
690 | spin_unlock(&out->lock); | 690 | spin_unlock(&out->lock); |
691 | rcu_read_unlock(); | 691 | rcu_read_unlock(); |
692 | return NULL; | 692 | return ERR_PTR(-EINVAL); |
693 | } | 693 | } |
694 | 694 | ||
695 | return out; | 695 | return out; |
696 | } | 696 | } |
697 | 697 | ||
698 | void ipc_lock_by_ptr(struct kern_ipc_perm *perm) | ||
699 | { | ||
700 | rcu_read_lock(); | ||
701 | spin_lock(&perm->lock); | ||
702 | } | ||
703 | |||
704 | void ipc_unlock(struct kern_ipc_perm* perm) | ||
705 | { | ||
706 | spin_unlock(&perm->lock); | ||
707 | rcu_read_unlock(); | ||
708 | } | ||
709 | |||
710 | int ipc_buildid(struct ipc_ids* ids, int id, int seq) | 698 | int ipc_buildid(struct ipc_ids* ids, int id, int seq) |
711 | { | 699 | { |
712 | return SEQ_MULTIPLIER*seq + id; | 700 | return SEQ_MULTIPLIER*seq + id; |
713 | } | 701 | } |
714 | 702 | ||
715 | int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) | ||
716 | { | ||
717 | if(uid/SEQ_MULTIPLIER != ipcp->seq) | ||
718 | return 1; | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | #ifdef __ARCH_WANT_IPC_PARSE_VERSION | 703 | #ifdef __ARCH_WANT_IPC_PARSE_VERSION |
723 | 704 | ||
724 | 705 | ||
diff --git a/ipc/util.h b/ipc/util.h index 1546eda7d99e..c4b0a9865bf5 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #define _IPC_UTIL_H | 11 | #define _IPC_UTIL_H |
12 | 12 | ||
13 | #include <linux/idr.h> | 13 | #include <linux/idr.h> |
14 | #include <linux/err.h> | ||
14 | 15 | ||
15 | #define USHRT_MAX 0xffff | 16 | #define USHRT_MAX 0xffff |
16 | #define SEQ_MULTIPLIER (IPCMNI) | 17 | #define SEQ_MULTIPLIER (IPCMNI) |
@@ -103,11 +104,8 @@ void* ipc_rcu_alloc(int size); | |||
103 | void ipc_rcu_getref(void *ptr); | 104 | void ipc_rcu_getref(void *ptr); |
104 | void ipc_rcu_putref(void *ptr); | 105 | void ipc_rcu_putref(void *ptr); |
105 | 106 | ||
106 | struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id); | 107 | struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); |
107 | void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp); | ||
108 | void ipc_unlock(struct kern_ipc_perm* perm); | ||
109 | int ipc_buildid(struct ipc_ids* ids, int id, int seq); | 108 | int ipc_buildid(struct ipc_ids* ids, int id, int seq); |
110 | int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid); | ||
111 | 109 | ||
112 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); | 110 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); |
113 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); | 111 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); |
@@ -127,6 +125,43 @@ extern int ipcget_new(struct ipc_namespace *, struct ipc_ids *, | |||
127 | extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *, | 125 | extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *, |
128 | struct ipc_ops *, struct ipc_params *); | 126 | struct ipc_ops *, struct ipc_params *); |
129 | 127 | ||
128 | static inline int ipc_checkid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp, | ||
129 | int uid) | ||
130 | { | ||
131 | if (uid / SEQ_MULTIPLIER != ipcp->seq) | ||
132 | return 1; | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm) | ||
137 | { | ||
138 | rcu_read_lock(); | ||
139 | spin_lock(&perm->lock); | ||
140 | } | ||
141 | |||
142 | static inline void ipc_unlock(struct kern_ipc_perm *perm) | ||
143 | { | ||
144 | spin_unlock(&perm->lock); | ||
145 | rcu_read_unlock(); | ||
146 | } | ||
147 | |||
148 | static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, | ||
149 | int id) | ||
150 | { | ||
151 | struct kern_ipc_perm *out; | ||
152 | |||
153 | out = ipc_lock(ids, id); | ||
154 | if (IS_ERR(out)) | ||
155 | return out; | ||
156 | |||
157 | if (ipc_checkid(ids, out, id)) { | ||
158 | ipc_unlock(out); | ||
159 | return ERR_PTR(-EIDRM); | ||
160 | } | ||
161 | |||
162 | return out; | ||
163 | } | ||
164 | |||
130 | static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, | 165 | static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, |
131 | struct ipc_ops *ops, struct ipc_params *params) | 166 | struct ipc_ops *ops, struct ipc_params *params) |
132 | { | 167 | { |