summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2017-11-01 11:36:30 -0400
committerDan Williams <dan.j.williams@intel.com>2017-11-03 09:26:22 -0400
commit1c9725974074a047f6080eecc62c50a8e840d050 (patch)
treeaabeb6444ed1294ed3cf12ce4b34c03abdf2452f
parent592e254502041f953e84d091eae2c68cba04c10b (diff)
mm: introduce MAP_SHARED_VALIDATE, a mechanism to safely define new mmap flags
The mmap(2) syscall suffers from the ABI anti-pattern of not validating unknown flags. However, proposals like MAP_SYNC need a mechanism to define new behavior that is known to fail on older kernels without the support. Define a new MAP_SHARED_VALIDATE flag pattern that is guaranteed to fail on all legacy mmap implementations. It is worth noting that the original proposal was for a standalone MAP_VALIDATE flag. However, when that could not be supported by all archs Linus observed: I see why you *think* you want a bitmap. You think you want a bitmap because you want to make MAP_VALIDATE be part of MAP_SYNC etc, so that people can do ret = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_SYNC, fd, 0); and "know" that MAP_SYNC actually takes. And I'm saying that whole wish is bogus. You're fundamentally depending on special semantics, just make it explicit. It's already not portable, so don't try to make it so. Rename that MAP_VALIDATE as MAP_SHARED_VALIDATE, make it have a value of 0x3, and make people do ret = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED_VALIDATE | MAP_SYNC, fd, 0); and then the kernel side is easier too (none of that random garbage playing games with looking at the "MAP_VALIDATE bit", but just another case statement in that map type thing. Boom. Done. Similar to ->fallocate() we also want the ability to validate the support for new flags on a per ->mmap() 'struct file_operations' instance basis. Towards that end arrange for flags to be generically validated against a mmap_supported_flags exported by 'struct file_operations'. By default all existing flags are implicitly supported, but new flags require MAP_SHARED_VALIDATE and per-instance-opt-in. Cc: Jan Kara <jack@suse.cz> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Andy Lutomirski <luto@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Suggested-by: Christoph Hellwig <hch@lst.de> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--arch/alpha/include/uapi/asm/mman.h1
-rw-r--r--arch/mips/include/uapi/asm/mman.h1
-rw-r--r--arch/parisc/include/uapi/asm/mman.h1
-rw-r--r--arch/xtensa/include/uapi/asm/mman.h1
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/mman.h39
-rw-r--r--include/uapi/asm-generic/mman-common.h1
-rw-r--r--mm/mmap.c15
-rw-r--r--tools/include/uapi/asm-generic/mman-common.h1
9 files changed, 61 insertions, 0 deletions
diff --git a/arch/alpha/include/uapi/asm/mman.h b/arch/alpha/include/uapi/asm/mman.h
index 3b26cc62dadb..f6d118aaedb9 100644
--- a/arch/alpha/include/uapi/asm/mman.h
+++ b/arch/alpha/include/uapi/asm/mman.h
@@ -11,6 +11,7 @@
11 11
12#define MAP_SHARED 0x01 /* Share changes */ 12#define MAP_SHARED 0x01 /* Share changes */
13#define MAP_PRIVATE 0x02 /* Changes are private */ 13#define MAP_PRIVATE 0x02 /* Changes are private */
14#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
14#define MAP_TYPE 0x0f /* Mask for type of mapping (OSF/1 is _wrong_) */ 15#define MAP_TYPE 0x0f /* Mask for type of mapping (OSF/1 is _wrong_) */
15#define MAP_FIXED 0x100 /* Interpret addr exactly */ 16#define MAP_FIXED 0x100 /* Interpret addr exactly */
16#define MAP_ANONYMOUS 0x10 /* don't use a file */ 17#define MAP_ANONYMOUS 0x10 /* don't use a file */
diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h
index da3216007fe0..93268e4cd3c7 100644
--- a/arch/mips/include/uapi/asm/mman.h
+++ b/arch/mips/include/uapi/asm/mman.h
@@ -28,6 +28,7 @@
28 */ 28 */
29#define MAP_SHARED 0x001 /* Share changes */ 29#define MAP_SHARED 0x001 /* Share changes */
30#define MAP_PRIVATE 0x002 /* Changes are private */ 30#define MAP_PRIVATE 0x002 /* Changes are private */
31#define MAP_SHARED_VALIDATE 0x003 /* share + validate extension flags */
31#define MAP_TYPE 0x00f /* Mask for type of mapping */ 32#define MAP_TYPE 0x00f /* Mask for type of mapping */
32#define MAP_FIXED 0x010 /* Interpret addr exactly */ 33#define MAP_FIXED 0x010 /* Interpret addr exactly */
33 34
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
index 775b5d5e41a1..bca652aa1677 100644
--- a/arch/parisc/include/uapi/asm/mman.h
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -11,6 +11,7 @@
11 11
12#define MAP_SHARED 0x01 /* Share changes */ 12#define MAP_SHARED 0x01 /* Share changes */
13#define MAP_PRIVATE 0x02 /* Changes are private */ 13#define MAP_PRIVATE 0x02 /* Changes are private */
14#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
14#define MAP_TYPE 0x03 /* Mask for type of mapping */ 15#define MAP_TYPE 0x03 /* Mask for type of mapping */
15#define MAP_FIXED 0x04 /* Interpret addr exactly */ 16#define MAP_FIXED 0x04 /* Interpret addr exactly */
16#define MAP_ANONYMOUS 0x10 /* don't use a file */ 17#define MAP_ANONYMOUS 0x10 /* don't use a file */
diff --git a/arch/xtensa/include/uapi/asm/mman.h b/arch/xtensa/include/uapi/asm/mman.h
index b15b278aa314..9ab426374714 100644
--- a/arch/xtensa/include/uapi/asm/mman.h
+++ b/arch/xtensa/include/uapi/asm/mman.h
@@ -35,6 +35,7 @@
35 */ 35 */
36#define MAP_SHARED 0x001 /* Share changes */ 36#define MAP_SHARED 0x001 /* Share changes */
37#define MAP_PRIVATE 0x002 /* Changes are private */ 37#define MAP_PRIVATE 0x002 /* Changes are private */
38#define MAP_SHARED_VALIDATE 0x003 /* share + validate extension flags */
38#define MAP_TYPE 0x00f /* Mask for type of mapping */ 39#define MAP_TYPE 0x00f /* Mask for type of mapping */
39#define MAP_FIXED 0x010 /* Interpret addr exactly */ 40#define MAP_FIXED 0x010 /* Interpret addr exactly */
40 41
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 13dab191a23e..57added3201d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1701,6 +1701,7 @@ struct file_operations {
1701 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 1701 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1702 long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 1702 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1703 int (*mmap) (struct file *, struct vm_area_struct *); 1703 int (*mmap) (struct file *, struct vm_area_struct *);
1704 unsigned long mmap_supported_flags;
1704 int (*open) (struct inode *, struct file *); 1705 int (*open) (struct inode *, struct file *);
1705 int (*flush) (struct file *, fl_owner_t id); 1706 int (*flush) (struct file *, fl_owner_t id);
1706 int (*release) (struct inode *, struct file *); 1707 int (*release) (struct inode *, struct file *);
diff --git a/include/linux/mman.h b/include/linux/mman.h
index edb6cf6a81ed..74452e3f2536 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -7,6 +7,45 @@
7#include <linux/atomic.h> 7#include <linux/atomic.h>
8#include <uapi/linux/mman.h> 8#include <uapi/linux/mman.h>
9 9
10/*
11 * Arrange for legacy / undefined architecture specific flags to be
12 * ignored by default in LEGACY_MAP_MASK.
13 */
14#ifndef MAP_32BIT
15#define MAP_32BIT 0
16#endif
17#ifndef MAP_HUGE_2MB
18#define MAP_HUGE_2MB 0
19#endif
20#ifndef MAP_HUGE_1GB
21#define MAP_HUGE_1GB 0
22#endif
23#ifndef MAP_UNINITIALIZED
24#define MAP_UNINITIALIZED 0
25#endif
26
27/*
28 * The historical set of flags that all mmap implementations implicitly
29 * support when a ->mmap_validate() op is not provided in file_operations.
30 */
31#define LEGACY_MAP_MASK (MAP_SHARED \
32 | MAP_PRIVATE \
33 | MAP_FIXED \
34 | MAP_ANONYMOUS \
35 | MAP_DENYWRITE \
36 | MAP_EXECUTABLE \
37 | MAP_UNINITIALIZED \
38 | MAP_GROWSDOWN \
39 | MAP_LOCKED \
40 | MAP_NORESERVE \
41 | MAP_POPULATE \
42 | MAP_NONBLOCK \
43 | MAP_STACK \
44 | MAP_HUGETLB \
45 | MAP_32BIT \
46 | MAP_HUGE_2MB \
47 | MAP_HUGE_1GB)
48
10extern int sysctl_overcommit_memory; 49extern int sysctl_overcommit_memory;
11extern int sysctl_overcommit_ratio; 50extern int sysctl_overcommit_ratio;
12extern unsigned long sysctl_overcommit_kbytes; 51extern unsigned long sysctl_overcommit_kbytes;
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index 203268f9231e..8ce7f5a0800f 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -16,6 +16,7 @@
16 16
17#define MAP_SHARED 0x01 /* Share changes */ 17#define MAP_SHARED 0x01 /* Share changes */
18#define MAP_PRIVATE 0x02 /* Changes are private */ 18#define MAP_PRIVATE 0x02 /* Changes are private */
19#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
19#define MAP_TYPE 0x0f /* Mask for type of mapping */ 20#define MAP_TYPE 0x0f /* Mask for type of mapping */
20#define MAP_FIXED 0x10 /* Interpret addr exactly */ 21#define MAP_FIXED 0x10 /* Interpret addr exactly */
21#define MAP_ANONYMOUS 0x20 /* don't use a file */ 22#define MAP_ANONYMOUS 0x20 /* don't use a file */
diff --git a/mm/mmap.c b/mm/mmap.c
index 680506faceae..924839fac0e6 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1387,9 +1387,24 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
1387 1387
1388 if (file) { 1388 if (file) {
1389 struct inode *inode = file_inode(file); 1389 struct inode *inode = file_inode(file);
1390 unsigned long flags_mask;
1391
1392 flags_mask = LEGACY_MAP_MASK | file->f_op->mmap_supported_flags;
1390 1393
1391 switch (flags & MAP_TYPE) { 1394 switch (flags & MAP_TYPE) {
1392 case MAP_SHARED: 1395 case MAP_SHARED:
1396 /*
1397 * Force use of MAP_SHARED_VALIDATE with non-legacy
1398 * flags. E.g. MAP_SYNC is dangerous to use with
1399 * MAP_SHARED as you don't know which consistency model
1400 * you will get. We silently ignore unsupported flags
1401 * with MAP_SHARED to preserve backward compatibility.
1402 */
1403 flags &= LEGACY_MAP_MASK;
1404 /* fall through */
1405 case MAP_SHARED_VALIDATE:
1406 if (flags & ~flags_mask)
1407 return -EOPNOTSUPP;
1393 if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE)) 1408 if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
1394 return -EACCES; 1409 return -EACCES;
1395 1410
diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h
index 203268f9231e..8ce7f5a0800f 100644
--- a/tools/include/uapi/asm-generic/mman-common.h
+++ b/tools/include/uapi/asm-generic/mman-common.h
@@ -16,6 +16,7 @@
16 16
17#define MAP_SHARED 0x01 /* Share changes */ 17#define MAP_SHARED 0x01 /* Share changes */
18#define MAP_PRIVATE 0x02 /* Changes are private */ 18#define MAP_PRIVATE 0x02 /* Changes are private */
19#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
19#define MAP_TYPE 0x0f /* Mask for type of mapping */ 20#define MAP_TYPE 0x0f /* Mask for type of mapping */
20#define MAP_FIXED 0x10 /* Interpret addr exactly */ 21#define MAP_FIXED 0x10 /* Interpret addr exactly */
21#define MAP_ANONYMOUS 0x20 /* don't use a file */ 22#define MAP_ANONYMOUS 0x20 /* don't use a file */