diff options
| author | Davidlohr Bueso <davidlohr.bueso@hp.com> | 2013-09-11 17:26:21 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-11 18:59:41 -0400 |
| commit | 2caacaa82a51b78fc0c800e206473874094287ed (patch) | |
| tree | 07dfe1f340d35d907de80f4a80296c72896cef2c /ipc | |
| parent | c97cb9ccab8c85428ec21eff690642ad2ce1fa8a (diff) | |
ipc,shm: shorten critical region for shmctl
With the *_INFO, *_STAT, IPC_RMID and IPC_SET commands already optimized,
deal with the remaining SHM_LOCK and SHM_UNLOCK commands. Take the
shm_perm lock after doing the initial auditing and security checks. The
rest of the logic remains unchanged.
Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/shm.c | 49 |
1 files changed, 25 insertions, 24 deletions
| @@ -940,10 +940,8 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 940 | int err, version; | 940 | int err, version; |
| 941 | struct ipc_namespace *ns; | 941 | struct ipc_namespace *ns; |
| 942 | 942 | ||
| 943 | if (cmd < 0 || shmid < 0) { | 943 | if (cmd < 0 || shmid < 0) |
| 944 | err = -EINVAL; | 944 | return -EINVAL; |
| 945 | goto out; | ||
| 946 | } | ||
| 947 | 945 | ||
| 948 | version = ipc_parse_version(&cmd); | 946 | version = ipc_parse_version(&cmd); |
| 949 | ns = current->nsproxy->ipc_ns; | 947 | ns = current->nsproxy->ipc_ns; |
| @@ -954,36 +952,40 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 954 | case SHM_STAT: | 952 | case SHM_STAT: |
| 955 | case IPC_STAT: | 953 | case IPC_STAT: |
| 956 | return shmctl_nolock(ns, shmid, cmd, version, buf); | 954 | return shmctl_nolock(ns, shmid, cmd, version, buf); |
| 955 | case IPC_RMID: | ||
| 956 | case IPC_SET: | ||
| 957 | return shmctl_down(ns, shmid, cmd, buf, version); | ||
| 957 | case SHM_LOCK: | 958 | case SHM_LOCK: |
| 958 | case SHM_UNLOCK: | 959 | case SHM_UNLOCK: |
| 959 | { | 960 | { |
| 960 | struct file *shm_file; | 961 | struct file *shm_file; |
| 961 | 962 | ||
| 962 | shp = shm_lock_check(ns, shmid); | 963 | rcu_read_lock(); |
| 964 | shp = shm_obtain_object_check(ns, shmid); | ||
| 963 | if (IS_ERR(shp)) { | 965 | if (IS_ERR(shp)) { |
| 964 | err = PTR_ERR(shp); | 966 | err = PTR_ERR(shp); |
| 965 | goto out; | 967 | goto out_unlock1; |
| 966 | } | 968 | } |
| 967 | 969 | ||
| 968 | audit_ipc_obj(&(shp->shm_perm)); | 970 | audit_ipc_obj(&(shp->shm_perm)); |
| 971 | err = security_shm_shmctl(shp, cmd); | ||
| 972 | if (err) | ||
| 973 | goto out_unlock1; | ||
| 969 | 974 | ||
| 975 | ipc_lock_object(&shp->shm_perm); | ||
| 970 | if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { | 976 | if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { |
| 971 | kuid_t euid = current_euid(); | 977 | kuid_t euid = current_euid(); |
| 972 | err = -EPERM; | 978 | err = -EPERM; |
| 973 | if (!uid_eq(euid, shp->shm_perm.uid) && | 979 | if (!uid_eq(euid, shp->shm_perm.uid) && |
| 974 | !uid_eq(euid, shp->shm_perm.cuid)) | 980 | !uid_eq(euid, shp->shm_perm.cuid)) |
| 975 | goto out_unlock; | 981 | goto out_unlock0; |
| 976 | if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) | 982 | if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) |
| 977 | goto out_unlock; | 983 | goto out_unlock0; |
| 978 | } | 984 | } |
| 979 | 985 | ||
| 980 | err = security_shm_shmctl(shp, cmd); | ||
| 981 | if (err) | ||
| 982 | goto out_unlock; | ||
| 983 | |||
| 984 | shm_file = shp->shm_file; | 986 | shm_file = shp->shm_file; |
| 985 | if (is_file_hugepages(shm_file)) | 987 | if (is_file_hugepages(shm_file)) |
| 986 | goto out_unlock; | 988 | goto out_unlock0; |
| 987 | 989 | ||
| 988 | if (cmd == SHM_LOCK) { | 990 | if (cmd == SHM_LOCK) { |
| 989 | struct user_struct *user = current_user(); | 991 | struct user_struct *user = current_user(); |
| @@ -992,32 +994,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 992 | shp->shm_perm.mode |= SHM_LOCKED; | 994 | shp->shm_perm.mode |= SHM_LOCKED; |
| 993 | shp->mlock_user = user; | 995 | shp->mlock_user = user; |
| 994 | } | 996 | } |
| 995 | goto out_unlock; | 997 | goto out_unlock0; |
| 996 | } | 998 | } |
| 997 | 999 | ||
| 998 | /* SHM_UNLOCK */ | 1000 | /* SHM_UNLOCK */ |
| 999 | if (!(shp->shm_perm.mode & SHM_LOCKED)) | 1001 | if (!(shp->shm_perm.mode & SHM_LOCKED)) |
| 1000 | goto out_unlock; | 1002 | goto out_unlock0; |
| 1001 | shmem_lock(shm_file, 0, shp->mlock_user); | 1003 | shmem_lock(shm_file, 0, shp->mlock_user); |
| 1002 | shp->shm_perm.mode &= ~SHM_LOCKED; | 1004 | shp->shm_perm.mode &= ~SHM_LOCKED; |
| 1003 | shp->mlock_user = NULL; | 1005 | shp->mlock_user = NULL; |
| 1004 | get_file(shm_file); | 1006 | get_file(shm_file); |
| 1005 | shm_unlock(shp); | 1007 | ipc_unlock_object(&shp->shm_perm); |
| 1008 | rcu_read_unlock(); | ||
| 1006 | shmem_unlock_mapping(shm_file->f_mapping); | 1009 | shmem_unlock_mapping(shm_file->f_mapping); |
| 1010 | |||
| 1007 | fput(shm_file); | 1011 | fput(shm_file); |
| 1008 | goto out; | ||
| 1009 | } | ||
| 1010 | case IPC_RMID: | ||
| 1011 | case IPC_SET: | ||
| 1012 | err = shmctl_down(ns, shmid, cmd, buf, version); | ||
| 1013 | return err; | 1012 | return err; |
| 1013 | } | ||
| 1014 | default: | 1014 | default: |
| 1015 | return -EINVAL; | 1015 | return -EINVAL; |
| 1016 | } | 1016 | } |
| 1017 | 1017 | ||
| 1018 | out_unlock: | 1018 | out_unlock0: |
| 1019 | shm_unlock(shp); | 1019 | ipc_unlock_object(&shp->shm_perm); |
| 1020 | out: | 1020 | out_unlock1: |
| 1021 | rcu_read_unlock(); | ||
| 1021 | return err; | 1022 | return err; |
| 1022 | } | 1023 | } |
| 1023 | 1024 | ||
