aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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. */