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