aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Peiffer <pierre.peiffer@bull.net>2008-04-29 04:00:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:14 -0400
commita5f75e7f256f75759ec3d6dbef0ba932f1b397d2 (patch)
tree89b2ed22547a9fca11f87eb6cba68bb84fcf1b8a
parent8f4a3809c18ff3107bdbb1fabe3f4e5d2a928321 (diff)
IPC: consolidate all xxxctl_down() functions
semctl_down(), msgctl_down() and shmctl_down() are used to handle the same set of commands for each kind of IPC. They all start to do the same job (they retrieve the ipc and do some permission checks) before handling the commands on their own. This patch proposes to consolidate this by moving these same pieces of code into one common function called ipcctl_pre_down(). It simplifies a little these xxxctl_down() functions and increases a little the maintainability. Signed-off-by: Pierre Peiffer <pierre.peiffer@bull.net> Acked-by: Serge Hallyn <serue@us.ibm.com> Cc: 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.c48
-rw-r--r--ipc/sem.c42
-rw-r--r--ipc/shm.c42
-rw-r--r--ipc/util.c51
-rw-r--r--ipc/util.h2
5 files changed, 66 insertions, 119 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 87d8b3852300..4a858f98a760 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -142,21 +142,6 @@ void __init msg_init(void)
142} 142}
143 143
144/* 144/*
145 * This routine is called in the paths where the rw_mutex is held to protect
146 * access to the idr tree.
147 */
148static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns,
149 int id)
150{
151 struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
152
153 if (IS_ERR(ipcp))
154 return (struct msg_queue *)ipcp;
155
156 return container_of(ipcp, struct msg_queue, q_perm);
157}
158
159/*
160 * msg_lock_(check_) routines are called in the paths where the rw_mutex 145 * msg_lock_(check_) routines are called in the paths where the rw_mutex
161 * is not held. 146 * is not held.
162 */ 147 */
@@ -437,35 +422,12 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
437 return -EFAULT; 422 return -EFAULT;
438 } 423 }
439 424
440 down_write(&msg_ids(ns).rw_mutex); 425 ipcp = ipcctl_pre_down(&msg_ids(ns), msqid, cmd,
441 msq = msg_lock_check_down(ns, msqid); 426 &msqid64.msg_perm, msqid64.msg_qbytes);
442 if (IS_ERR(msq)) { 427 if (IS_ERR(ipcp))
443 err = PTR_ERR(msq); 428 return PTR_ERR(ipcp);
444 goto out_up;
445 }
446
447 ipcp = &msq->q_perm;
448
449 err = audit_ipc_obj(ipcp);
450 if (err)
451 goto out_unlock;
452
453 if (cmd == IPC_SET) {
454 err = audit_ipc_set_perm(msqid64.msg_qbytes,
455 msqid64.msg_perm.uid,
456 msqid64.msg_perm.gid,
457 msqid64.msg_perm.mode);
458 if (err)
459 goto out_unlock;
460 }
461 429
462 if (current->euid != ipcp->cuid && 430 msq = container_of(ipcp, struct msg_queue, q_perm);
463 current->euid != ipcp->uid &&
464 !capable(CAP_SYS_ADMIN)) {
465 /* We _could_ check for CAP_CHOWN above, but we don't */
466 err = -EPERM;
467 goto out_unlock;
468 }
469 431
470 err = security_msg_queue_msgctl(msq, cmd); 432 err = security_msg_queue_msgctl(msq, cmd);
471 if (err) 433 if (err)
diff --git a/ipc/sem.c b/ipc/sem.c
index e803abec2b08..d56d3ab6bb8a 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -141,21 +141,6 @@ void __init sem_init (void)
141} 141}
142 142
143/* 143/*
144 * This routine is called in the paths where the rw_mutex is held to protect
145 * access to the idr tree.
146 */
147static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns,
148 int id)
149{
150 struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id);
151
152 if (IS_ERR(ipcp))
153 return (struct sem_array *)ipcp;
154
155 return container_of(ipcp, struct sem_array, sem_perm);
156}
157
158/*
159 * sem_lock_(check_) routines are called in the paths where the rw_mutex 144 * sem_lock_(check_) routines are called in the paths where the rw_mutex
160 * is not held. 145 * is not held.
161 */ 146 */
@@ -878,31 +863,12 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
878 if (copy_semid_from_user(&semid64, arg.buf, version)) 863 if (copy_semid_from_user(&semid64, arg.buf, version))
879 return -EFAULT; 864 return -EFAULT;
880 } 865 }
881 down_write(&sem_ids(ns).rw_mutex);
882 sma = sem_lock_check_down(ns, semid);
883 if (IS_ERR(sma)) {
884 err = PTR_ERR(sma);
885 goto out_up;
886 }
887
888 ipcp = &sma->sem_perm;
889 866
890 err = audit_ipc_obj(ipcp); 867 ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0);
891 if (err) 868 if (IS_ERR(ipcp))
892 goto out_unlock; 869 return PTR_ERR(ipcp);
893 870
894 if (cmd == IPC_SET) { 871 sma = container_of(ipcp, struct sem_array, sem_perm);
895 err = audit_ipc_set_perm(0, semid64.sem_perm.uid,
896 semid64.sem_perm.gid,
897 semid64.sem_perm.mode);
898 if (err)
899 goto out_unlock;
900 }
901 if (current->euid != ipcp->cuid &&
902 current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
903 err=-EPERM;
904 goto out_unlock;
905 }
906 872
907 err = security_sem_semctl(sma, cmd); 873 err = security_sem_semctl(sma, cmd);
908 if (err) 874 if (err)
diff --git a/ipc/shm.c b/ipc/shm.c
index 20e03dfc6adb..554429ade079 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -126,18 +126,6 @@ static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
126 return container_of(ipcp, struct shmid_kernel, shm_perm); 126 return container_of(ipcp, struct shmid_kernel, shm_perm);
127} 127}
128 128
129static inline struct shmid_kernel *shm_lock_check_down(
130 struct ipc_namespace *ns,
131 int id)
132{
133 struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
134
135 if (IS_ERR(ipcp))
136 return (struct shmid_kernel *)ipcp;
137
138 return container_of(ipcp, struct shmid_kernel, shm_perm);
139}
140
141/* 129/*
142 * shm_lock_(check_) routines are called in the paths where the rw_mutex 130 * shm_lock_(check_) routines are called in the paths where the rw_mutex
143 * is not held. 131 * is not held.
@@ -620,33 +608,11 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
620 return -EFAULT; 608 return -EFAULT;
621 } 609 }
622 610
623 down_write(&shm_ids(ns).rw_mutex); 611 ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0);
624 shp = shm_lock_check_down(ns, shmid); 612 if (IS_ERR(ipcp))
625 if (IS_ERR(shp)) { 613 return PTR_ERR(ipcp);
626 err = PTR_ERR(shp);
627 goto out_up;
628 }
629
630 ipcp = &shp->shm_perm;
631
632 err = audit_ipc_obj(ipcp);
633 if (err)
634 goto out_unlock;
635
636 if (cmd == IPC_SET) {
637 err = audit_ipc_set_perm(0, shmid64.shm_perm.uid,
638 shmid64.shm_perm.gid,
639 shmid64.shm_perm.mode);
640 if (err)
641 goto out_unlock;
642 }
643 614
644 if (current->euid != ipcp->uid && 615 shp = container_of(ipcp, struct shmid_kernel, shm_perm);
645 current->euid != ipcp->cuid &&
646 !capable(CAP_SYS_ADMIN)) {
647 err = -EPERM;
648 goto out_unlock;
649 }
650 616
651 err = security_shm_shmctl(shp, cmd); 617 err = security_shm_shmctl(shp, cmd);
652 if (err) 618 if (err)
diff --git a/ipc/util.c b/ipc/util.c
index dc8943aa9719..c4f1d33b89e4 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -824,6 +824,57 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
824 | (in->mode & S_IRWXUGO); 824 | (in->mode & S_IRWXUGO);
825} 825}
826 826
827/**
828 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
829 * @ids: the table of ids where to look for the ipc
830 * @id: the id of the ipc to retrieve
831 * @cmd: the cmd to check
832 * @perm: the permission to set
833 * @extra_perm: one extra permission parameter used by msq
834 *
835 * This function does some common audit and permissions check for some IPC_XXX
836 * cmd and is called from semctl_down, shmctl_down and msgctl_down.
837 * It must be called without any lock held and
838 * - retrieves the ipc with the given id in the given table.
839 * - performs some audit and permission check, depending on the given cmd
840 * - returns the ipc with both ipc and rw_mutex locks held in case of success
841 * or an err-code without any lock held otherwise.
842 */
843struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
844 struct ipc64_perm *perm, int extra_perm)
845{
846 struct kern_ipc_perm *ipcp;
847 int err;
848
849 down_write(&ids->rw_mutex);
850 ipcp = ipc_lock_check_down(ids, id);
851 if (IS_ERR(ipcp)) {
852 err = PTR_ERR(ipcp);
853 goto out_up;
854 }
855
856 err = audit_ipc_obj(ipcp);
857 if (err)
858 goto out_unlock;
859
860 if (cmd == IPC_SET) {
861 err = audit_ipc_set_perm(extra_perm, perm->uid,
862 perm->gid, perm->mode);
863 if (err)
864 goto out_unlock;
865 }
866 if (current->euid == ipcp->cuid ||
867 current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
868 return ipcp;
869
870 err = -EPERM;
871out_unlock:
872 ipc_unlock(ipcp);
873out_up:
874 up_write(&ids->rw_mutex);
875 return ERR_PTR(err);
876}
877
827#ifdef __ARCH_WANT_IPC_PARSE_VERSION 878#ifdef __ARCH_WANT_IPC_PARSE_VERSION
828 879
829 880
diff --git a/ipc/util.h b/ipc/util.h
index 12966913ebc6..791c5c012718 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -113,6 +113,8 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
113void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); 113void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
114void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); 114void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
115void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); 115void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
116struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
117 struct ipc64_perm *perm, int extra_perm);
116 118
117#if defined(__ia64__) || defined(__x86_64__) || defined(__hppa__) || defined(__XTENSA__) 119#if defined(__ia64__) || defined(__x86_64__) || defined(__hppa__) || defined(__XTENSA__)
118 /* On IA-64, we always use the "64-bit version" of the IPC structures. */ 120 /* On IA-64, we always use the "64-bit version" of the IPC structures. */