diff options
-rw-r--r-- | ipc/msg.c | 48 | ||||
-rw-r--r-- | ipc/sem.c | 42 | ||||
-rw-r--r-- | ipc/shm.c | 42 | ||||
-rw-r--r-- | ipc/util.c | 51 | ||||
-rw-r--r-- | ipc/util.h | 2 |
5 files changed, 66 insertions, 119 deletions
@@ -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 | */ | ||
148 | static 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) |
@@ -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 | */ | ||
147 | static 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) |
@@ -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 | ||
129 | static 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 | */ | ||
843 | struct 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; | ||
871 | out_unlock: | ||
872 | ipc_unlock(ipcp); | ||
873 | out_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); | |||
113 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); | 113 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); |
114 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); | 114 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); |
115 | void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); | 115 | void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); |
116 | struct 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. */ |