From: Jie Zhang <jie.zh...@analog.com>

The no-mmu code currently clears all anonymous mmap-ed memory.  While this
is what we want in the default case, all memory allocation from userspace
under no-mmu has to go through this interface, including malloc() which is
allowed to return uninitialized memory.  This can easily be a significant
performance slow down.  So for constrained embedded systems were security
is irrelevant, allow people to avoid unnecessarily clearing memory.

Signed-off-by: Jie Zhang <jie.zh...@analog.com>
Signed-off-by: Robin Getz <rg...@analog.com>
Signed-off-by: Mike Frysinger <vap...@gentoo.org>
---
 Documentation/nommu-mmap.txt      |   21 +++++++++++++++++++++
 fs/binfmt_elf_fdpic.c             |    2 +-
 include/asm-generic/mman-common.h |    5 +++++
 init/Kconfig                      |   16 ++++++++++++++++
 mm/nommu.c                        |    7 ++++---
 5 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt
index b565e82..30d09e8 100644
--- a/Documentation/nommu-mmap.txt
+++ b/Documentation/nommu-mmap.txt
@@ -16,6 +16,27 @@ the CLONE_VM flag.
 The behaviour is similar between the MMU and no-MMU cases, but not identical;
 and it's also much more restricted in the latter case:
 
+ (*) Anonymous mappings - general case
+
+       Anonymous mappings are  not  backed  by any file, and according to the
+       Linux man pages (ver 2.22 or later) contents are initialized to zero.
+
+       In the MMU case, regions are backed by arbitrary virtual pages, and the
+       contents are only mapped with physical pages and initialized to zero
+       when a read or write happens in that specific page. This spreads out
+       the time it takes to initialize the contents depending on the
+       read/write usage of the map.
+
+       In the no-MMU case, anonymous mappings are backed by physical pages,
+       and the entire map is initialized to zero at allocation time. This
+       can cause significant delays in userspace during malloc() as the C
+       library does an anonymous mapping, and the kernel is doing a memset
+       for the entire map. Since malloc's memory is not required to be
+       cleared, an (optional) flag MAP_UNINITIALIZE can be passed to the
+       kernel's do_mmap, which will not initialize the contents to zero.
+
+       uClibc supports this to provide a pretty significant speedup for 
malloc().
+
  (*) Anonymous mapping, MAP_PRIVATE
 
        In the MMU case: VM regions backed by arbitrary pages; copy-on-write
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 38502c6..85db4a4 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -380,7 +380,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
        down_write(&current->mm->mmap_sem);
        current->mm->start_brk = do_mmap(NULL, 0, stack_size,
                                         PROT_READ | PROT_WRITE | PROT_EXEC,
-                                        MAP_PRIVATE | MAP_ANONYMOUS | 
MAP_GROWSDOWN,
+                                        MAP_PRIVATE | MAP_ANONYMOUS | 
MAP_UNINITIALIZE | MAP_GROWSDOWN,
                                         0);
 
        if (IS_ERR_VALUE(current->mm->start_brk)) {
diff --git a/include/asm-generic/mman-common.h 
b/include/asm-generic/mman-common.h
index 5ee13b2..dddf626 100644
--- a/include/asm-generic/mman-common.h
+++ b/include/asm-generic/mman-common.h
@@ -19,6 +19,11 @@
 #define MAP_TYPE       0x0f            /* Mask for type of mapping */
 #define MAP_FIXED      0x10            /* Interpret addr exactly */
 #define MAP_ANONYMOUS  0x20            /* don't use a file */
+#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZE
+# define MAP_UNINITIALIZE 0x4000000    /* For anonymous mmap, memory could be 
uninitialized */
+#else
+# define MAP_UNINITIALIZE 0x0          /* Don't support this flag */
+#endif
 
 #define MS_ASYNC       1               /* sync memory asynchronously */
 #define MS_INVALIDATE  2               /* invalidate the caches */
diff --git a/init/Kconfig b/init/Kconfig
index 09c5c64..ae15849 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1069,6 +1069,22 @@ config SLOB
 
 endchoice
 
+config MMAP_ALLOW_UNINITIALIZE
+       bool "Allow mmaped anonymous memory to be un-initialized"
+       depends on EMBEDDED && ! MMU
+       default n
+       help
+          Normally (and according to the Linux spec) mmap'ed MAP_ANONYMOUS
+          memory has it's contents initialized to zero. This kernel option
+          gives you the option of not doing that by adding a MAP_UNINITIALIZE
+          mmap flag (which uClibc's malloc() takes takes advantage of)
+          which provides a huge performance boost.
+
+          Because of the obvious security issues, this option should only be
+          enabled on embedded devices which you control what is run in
+          userspace. Since that isn't a problem on no-MMU systems, it is
+          normally safe to say Y here.
+
 config PROFILING
        bool "Profiling support (EXPERIMENTAL)"
        help
diff --git a/mm/nommu.c b/mm/nommu.c
index 5189b5a..b62bd9d 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1143,9 +1143,6 @@ static int do_mmap_private(struct vm_area_struct *vma,
                if (ret < rlen)
                        memset(base + ret, 0, rlen - ret);
 
-       } else {
-               /* if it's an anonymous mapping, then just clear it */
-               memset(base, 0, rlen);
        }
 
        return 0;
@@ -1343,6 +1340,10 @@ unsigned long do_mmap_pgoff(struct file *file,
                goto error_just_free;
        add_nommu_region(region);
 
+       /* clear anonymous mappings that don't ask for un-initialized data */
+       if (!(vma->vm_file) && !(flags & MAP_UNINITIALIZE))
+               memset((void *)region->vm_start, 0, region->vm_end - 
region->vm_start);
+
        /* okay... we have a mapping; now we have to register it */
        result = vma->vm_start;
 
-- 
1.6.5

_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to