diff options
author | Pavel Emelianov <xemul@openvz.org> | 2007-07-31 03:38:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 18:39:40 -0400 |
commit | 7be77e20d59fc3dd3fdde31641e0bc821114d26b (patch) | |
tree | 558507e6fe540d1deddb2dbce9b3a7cca855a57e | |
parent | ad0b142772eb1f88f0e77cb63c38b0005e83c2bd (diff) |
Fix user struct leakage with locked IPC shem segment
When user locks an ipc shmem segmant with SHM_LOCK ctl and the segment is
already locked the shmem_lock() function returns 0. After this the
subsequent code leaks the existing user struct:
== ipc/shm.c: sys_shmctl() ==
...
err = shmem_lock(shp->shm_file, 1, user);
if (!err) {
shp->shm_perm.mode |= SHM_LOCKED;
shp->mlock_user = user;
}
...
==
Other results of this are:
1. the new shp->mlock_user is not get-ed and will point to freed
memory when the task dies.
2. the RLIMIT_MEMLOCK is screwed on both user structs.
The exploit looks like this:
==
id = shmget(...);
setresuid(uid, 0, 0);
shmctl(id, SHM_LOCK, NULL);
setresuid(uid + 1, 0, 0);
shmctl(id, SHM_LOCK, NULL);
==
My solution is to return 0 to the userspace and do not change the
segment's user.
Signed-off-by: Pavel Emelianov <xemul@openvz.org>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | ipc/shm.c | 2 |
1 files changed, 1 insertions, 1 deletions
@@ -716,7 +716,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
716 | struct user_struct * user = current->user; | 716 | struct user_struct * user = current->user; |
717 | if (!is_file_hugepages(shp->shm_file)) { | 717 | if (!is_file_hugepages(shp->shm_file)) { |
718 | err = shmem_lock(shp->shm_file, 1, user); | 718 | err = shmem_lock(shp->shm_file, 1, user); |
719 | if (!err) { | 719 | if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){ |
720 | shp->shm_perm.mode |= SHM_LOCKED; | 720 | shp->shm_perm.mode |= SHM_LOCKED; |
721 | shp->mlock_user = user; | 721 | shp->mlock_user = user; |
722 | } | 722 | } |