Skip to content

Commit 2caacaa

Browse files
Davidlohr Buesotorvalds
authored andcommitted
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>
1 parent c97cb9c commit 2caacaa

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

ipc/shm.c

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -940,10 +940,8 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
940940
int err, version;
941941
struct ipc_namespace *ns;
942942

943-
if (cmd < 0 || shmid < 0) {
944-
err = -EINVAL;
945-
goto out;
946-
}
943+
if (cmd < 0 || shmid < 0)
944+
return -EINVAL;
947945

948946
version = ipc_parse_version(&cmd);
949947
ns = current->nsproxy->ipc_ns;
@@ -954,36 +952,40 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
954952
case SHM_STAT:
955953
case IPC_STAT:
956954
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);
957958
case SHM_LOCK:
958959
case SHM_UNLOCK:
959960
{
960961
struct file *shm_file;
961962

962-
shp = shm_lock_check(ns, shmid);
963+
rcu_read_lock();
964+
shp = shm_obtain_object_check(ns, shmid);
963965
if (IS_ERR(shp)) {
964966
err = PTR_ERR(shp);
965-
goto out;
967+
goto out_unlock1;
966968
}
967969

968970
audit_ipc_obj(&(shp->shm_perm));
971+
err = security_shm_shmctl(shp, cmd);
972+
if (err)
973+
goto out_unlock1;
969974

975+
ipc_lock_object(&shp->shm_perm);
970976
if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
971977
kuid_t euid = current_euid();
972978
err = -EPERM;
973979
if (!uid_eq(euid, shp->shm_perm.uid) &&
974980
!uid_eq(euid, shp->shm_perm.cuid))
975-
goto out_unlock;
981+
goto out_unlock0;
976982
if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
977-
goto out_unlock;
983+
goto out_unlock0;
978984
}
979985

980-
err = security_shm_shmctl(shp, cmd);
981-
if (err)
982-
goto out_unlock;
983-
984986
shm_file = shp->shm_file;
985987
if (is_file_hugepages(shm_file))
986-
goto out_unlock;
988+
goto out_unlock0;
987989

988990
if (cmd == SHM_LOCK) {
989991
struct user_struct *user = current_user();
@@ -992,32 +994,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
992994
shp->shm_perm.mode |= SHM_LOCKED;
993995
shp->mlock_user = user;
994996
}
995-
goto out_unlock;
997+
goto out_unlock0;
996998
}
997999

9981000
/* SHM_UNLOCK */
9991001
if (!(shp->shm_perm.mode & SHM_LOCKED))
1000-
goto out_unlock;
1002+
goto out_unlock0;
10011003
shmem_lock(shm_file, 0, shp->mlock_user);
10021004
shp->shm_perm.mode &= ~SHM_LOCKED;
10031005
shp->mlock_user = NULL;
10041006
get_file(shm_file);
1005-
shm_unlock(shp);
1007+
ipc_unlock_object(&shp->shm_perm);
1008+
rcu_read_unlock();
10061009
shmem_unlock_mapping(shm_file->f_mapping);
1010+
10071011
fput(shm_file);
1008-
goto out;
1009-
}
1010-
case IPC_RMID:
1011-
case IPC_SET:
1012-
err = shmctl_down(ns, shmid, cmd, buf, version);
10131012
return err;
1013+
}
10141014
default:
10151015
return -EINVAL;
10161016
}
10171017

1018-
out_unlock:
1019-
shm_unlock(shp);
1020-
out:
1018+
out_unlock0:
1019+
ipc_unlock_object(&shp->shm_perm);
1020+
out_unlock1:
1021+
rcu_read_unlock();
10211022
return err;
10221023
}
10231024

0 commit comments

Comments
 (0)