aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-09-11 17:26:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 18:59:41 -0400
commit2caacaa82a51b78fc0c800e206473874094287ed (patch)
tree07dfe1f340d35d907de80f4a80296c72896cef2c
parentc97cb9ccab8c85428ec21eff690642ad2ce1fa8a (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>
-rw-r--r--ipc/shm.c49
1 files changed, 25 insertions, 24 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index a493639550d9..8ec381085dec 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -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
1018out_unlock: 1018out_unlock0:
1019 shm_unlock(shp); 1019 ipc_unlock_object(&shp->shm_perm);
1020out: 1020out_unlock1:
1021 rcu_read_unlock();
1021 return err; 1022 return err;
1022} 1023}
1023 1024