Skip to content

Commit e1d35d4

Browse files
Davidlohr Buesosfrothwell
Davidlohr Bueso
authored andcommitted
ipc/shm: Fix shmat mmap nil-page protection
The issue is described here, with a nice testcase: https://bugzilla.kernel.org/show_bug.cgi?id=192931 The problem is that shmat() calls do_mmap_pgoff() with MAP_FIXED, and the address rounded down to 0. For the regular mmap case, the protection mentioned above is that the kernel gets to generate the address -- arch_get_unmapped_area() will always check for MAP_FIXED and return that address. So by the time we do security_mmap_addr(0) things get funky for shmat(). The testcase itself shows that while a regular user crashes, root will not have a problem attaching a nil-page. There are two possible fixes to this. The first, and which this patch does, is to simply allow root to crash as well -- this is also regular mmap behavior, ie when hacking up the testcase and adding mmap(... |MAP_FIXED). While this approach is the safer option, the second alternative is to ignore SHM_RND if the rounded address is 0, thus only having MAP_SHARED flags. This makes the behavior of shmat() identical to the mmap() case. The downside of this is obviously user visible, but does make sense in that it maintains semantics after the round-down wrt 0 address and mmap. Passes shm related ltp tests. Link: http://lkml.kernel.org/r/1486050195-18629-1-git-send-email-dave@stgolabs.net Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Reported-by: Gareth Evans <gareth.evans@contextis.co.uk> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Michael Kerrisk <mtk.manpages@googlemail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 21e1bae commit e1d35d4

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

Diff for: ipc/shm.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -1091,8 +1091,8 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
10911091
* "raddr" thing points to kernel space, and there has to be a wrapper around
10921092
* this.
10931093
*/
1094-
long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
1095-
unsigned long shmlba)
1094+
long do_shmat(int shmid, char __user *shmaddr, int shmflg,
1095+
ulong *raddr, unsigned long shmlba)
10961096
{
10971097
struct shmid_kernel *shp;
10981098
unsigned long addr;
@@ -1113,8 +1113,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
11131113
goto out;
11141114
else if ((addr = (ulong)shmaddr)) {
11151115
if (addr & (shmlba - 1)) {
1116-
if (shmflg & SHM_RND)
1117-
addr &= ~(shmlba - 1); /* round down */
1116+
/*
1117+
* Round down to the nearest multiple of shmlba.
1118+
* For sane do_mmap_pgoff() parameters, avoid
1119+
* round downs that trigger nil-page and MAP_FIXED.
1120+
*/
1121+
if ((shmflg & SHM_RND) && addr >= shmlba)
1122+
addr &= ~(shmlba - 1);
11181123
else
11191124
#ifndef __ARCH_FORCE_SHMLBA
11201125
if (addr & ~PAGE_MASK)

0 commit comments

Comments
 (0)