ipc/shm: Fix shmat mmap nil-page protection (CVE-2017-5669)

This commit is contained in:
Ben Hutchings 2017-02-26 20:51:00 +00:00
parent 003300166a
commit f32a03523e
3 changed files with 72 additions and 0 deletions

1
debian/changelog vendored
View File

@ -92,6 +92,7 @@ linux (4.9.13-1) UNRELEASED; urgency=medium
* udeb: Add more USB host and dual-role drivers to usb-modules
(Closes: #856111)
* [x86] kvm: fix page struct leak in handle_vmon (CVE-2017-2596)
* ipc/shm: Fix shmat mmap nil-page protection (CVE-2017-5669)
-- Ben Hutchings <ben@decadent.org.uk> Sat, 18 Feb 2017 00:38:10 +0000

View File

@ -0,0 +1,70 @@
From: Davidlohr Bueso <dave@stgolabs.net>
Date: Thu, 23 Feb 2017 11:41:32 +1100
Subject: ipc/shm: Fix shmat mmap nil-page protection
Origin: https://marc.info/?l=linux-mm&m=148605021927245&w=2
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-5669
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>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
ipc/shm.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1085,8 +1085,8 @@ out_unlock1:
* "raddr" thing points to kernel space, and there has to be a wrapper around
* this.
*/
-long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
- unsigned long shmlba)
+long do_shmat(int shmid, char __user *shmaddr, int shmflg,
+ ulong *raddr, unsigned long shmlba)
{
struct shmid_kernel *shp;
unsigned long addr;
@@ -1107,8 +1107,13 @@ long do_shmat(int shmid, char __user *sh
goto out;
else if ((addr = (ulong)shmaddr)) {
if (addr & (shmlba - 1)) {
- if (shmflg & SHM_RND)
- addr &= ~(shmlba - 1); /* round down */
+ /*
+ * Round down to the nearest multiple of shmlba.
+ * For sane do_mmap_pgoff() parameters, avoid
+ * round downs that trigger nil-page and MAP_FIXED.
+ */
+ if ((shmflg & SHM_RND) && addr >= shmlba)
+ addr &= ~(shmlba - 1);
else
#ifndef __ARCH_FORCE_SHMLBA
if (addr & ~PAGE_MASK)

View File

@ -109,6 +109,7 @@ features/all/securelevel/arm64-add-kernel-config-option-to-set-securelevel-wh.pa
# Security fixes
debian/i386-686-pae-pci-set-pci-nobios-by-default.patch
bugfix/x86/kvm-fix-page-struct-leak-in-handle_vmon.patch
bugfix/all/ipc-shm-fix-shmat-mmap-nil-page-protection.patch
# Fix exported symbol versions
bugfix/ia64/revert-ia64-move-exports-to-definitions.patch