Re: [PATCH] ASLRv3: randomize_va_space=3 preventing offset2lib attack

From: Hector Marco Gisbert
Date: Tue Dec 23 2014 - 15:08:17 EST


[PATCH] ASLRv3: inter-mmap ASLR (IM-ASLR).


The following is a patch that implements the inter-mmap (IM-ASLR)
which randomizes all mmaps. All the discussion about the current
implementation (offset2lib and vdso) shall be solved by fixing
the current implementation (randomize_va_space =2).

While we were working in the offset2lib we realized that
a complete solution would to randomize each mmap independently.
(as reno has suggested). Here is patch to achieve that and I
discussion about it.

First of all, I think that IM-ASLR is not mandatory, considering
current attacks and technology. Note that it very risky to make any
sound claim about what is secure and what is not. So, take the first
claim with caution.

IM-ASLR requires a large virtual memory space to avoid fragmentation
problems (see below), therefore, I think that it is only practical on
64 bit systems.

IM-ASLR will be the most advanced ASLR implementation overpassing
PaX ASLR. The present patch will prevent future threats (or current
threats, but unknown to me). It would be nice have it in Linux, but
a trade-off between security and performance shall be done before
adopting it as a default option.

Since the implementation is very simple and straight forward, I
suggest to include it as randomize_va_space=3. This way, it may
be enabled on a per process basis (personality).

Another aspect to think about is: Does this code adds or opens a new
backdoor or weakness? I don't think so. The code and the operation is
really simple, and it does not have side effects as far as I see.

Current implementations are based on the basic idea of "zones" of
similar or comparable criticality. Now we are discussing about where
the VDSO shall be placed, and if it shall be close to the stack zone
or on the mmap zone. Well, IM-ASLR solves this problem at once: all
objects are located on its own isolated "zone". In this sense, the
IM-ASLR removes most of the philosophical or subjective
arguments... which are always hard to justify.

Eventually, if the IM-ASLR is effective, we will set it by default for
all apps.



Regarding fragmentation:

2^46 is a huge virtual space, it is so large that fragmentation will
not be a problem. Just doing some numbers, you can understand the
extremely low probability of having problems due to fragmentation.

Let's suppose that the largest mmaped request is 1Gb. The worst case
scenario to fail a request is when the memory is fragmented in such a
way that all the free areas are of size (1Gb-4kb).

free busy free busy free busy .....free
[1Gb-4kb][4kb][1G-4kb][4kb][1Gb-4kb][4kb].....[1Gb-4kb]..

This is a perfectly doomsday case.

Well, in this case the number of allocated (busy) mmaped areas of 4kb
needed to fragment the memory is:

2^46/2^30= 2^16.

That is, an application shall request > 64000 mmaps of one page
(4kb). And then, if it is extremely unlucky, the next mmap of 1Gb will
fail.

Obviously, we assume that all the 64000 request are "perfectly" placed
at 1Gb distance of each other. The probability that such a perfectly
space allocs occur is less than one out of (2^46)^(2^16). This is a
fairly "impossible" event.

Conclusion: Fragmentation is not a issue. We shall be more worried
about hitting a comet our city than running out of memory because of
fragmentation.

Signed-off-by: Hector Marco-Gisbert <hecmargi@xxxxxx>
Signed-off-by: Ismael Ripoll <iripoll@xxxxxx>

diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 75511ef..dde92ee 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -704,6 +704,18 @@ that support this feature.
with CONFIG_COMPAT_BRK enabled, which excludes the heap from process
address space randomization.

+3 - Inter-mmap randomization and extended entropy. Randomizes all
+ mmap requests when the addr is NULL.
+
+ This is an improvement of the previous ASLR option which:
+ a) extend the number of random bits on the addresses and
+ b) add randomness to the offset between mmapped objects.
+
+ This feature is only available on architectures which implement
+ large virtual memory space (i.e. 64bit systems). In 32bits, the
+ fragmentation can be a problem for applications which use large
+ memory areas.
+
==============================================================

reboot-cmd: (Sparc only)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..380873f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,6 +1,7 @@
config ARM64
def_bool y
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
+ select RANDOMIZE_ALL_MMAPS
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SG_CHAIN
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index fde9923..2b54bbe 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -43,6 +43,9 @@
#include <linux/hw_breakpoint.h>
#include <linux/personality.h>
#include <linux/notifier.h>
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+#include <linux/security.h>
+#endif

#include <asm/compat.h>
#include <asm/cacheflush.h>
@@ -376,5 +379,16 @@ static unsigned long randomize_base(unsigned long base)

unsigned long arch_randomize_brk(struct mm_struct *mm)
{
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+ unsigned long brk;
+ unsigned long min_addr = PAGE_ALIGN(mmap_min_addr);
+ unsigned long max_addr = PAGE_ALIGN(current->mm->mmap_base);
+
+ if ( (randomize_va_space > 2) && !is_compat_task() ){
+ brk = (get_random_long() << PAGE_SHIFT) % (max_addr - min_addr);
+ brk += min_addr;
+ return brk;
+ }
+#endif
return randomize_base(mm->brk);
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ba397bd..2607ce9 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -86,6 +86,7 @@ config X86
select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
+ select RANDOMIZE_ALL_MMAPS if X86_64
select HAVE_ARCH_JUMP_LABEL
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select SPARSE_IRQ
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e127dda..7b7745d 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -19,6 +19,9 @@
#include <linux/cpuidle.h>
#include <trace/events/power.h>
#include <linux/hw_breakpoint.h>
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+#include <linux/security.h>
+#endif
#include <asm/cpu.h>
#include <asm/apic.h>
#include <asm/syscalls.h>
@@ -465,7 +468,18 @@ unsigned long arch_align_stack(unsigned long sp)

unsigned long arch_randomize_brk(struct mm_struct *mm)
{
- unsigned long range_end = mm->brk + 0x02000000;
- return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+ unsigned long brk;
+ unsigned long min_addr = PAGE_ALIGN(mmap_min_addr);
+ unsigned long max_addr = PAGE_ALIGN(current->mm->mmap_base);
+
+ if ( (randomize_va_space > 2) && !is_compat_task() ){
+ brk = (get_random_long() << PAGE_SHIFT) % (max_addr - min_addr);
+ brk += min_addr;
+ return brk;
+ }
+#endif
+
+ return randomize_range(mm->brk, mm->brk + 0x02000000, 0) ? : mm->brk;
}

diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 009495b..205f1a3 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -19,6 +19,9 @@
#include <asm/page.h>
#include <asm/hpet.h>
#include <asm/desc.h>
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+#include <asm/compat.h>
+#endif

#if defined(CONFIG_X86_64)
unsigned int __read_mostly vdso64_enabled = 1;
@@ -54,6 +57,11 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
#else
unsigned long addr, end;
unsigned offset;
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+ if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 2)
+ && !is_compat_task())
+ return 0;
+#endif
end = (start + PMD_SIZE - 1) & PMD_MASK;
if (end >= TASK_SIZE_MAX)
end = TASK_SIZE_MAX;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 04645c0..f6a231f 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1740,6 +1740,13 @@ unsigned int get_random_int(void)
}
EXPORT_SYMBOL(get_random_int);

+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+unsigned long get_random_long(void)
+{
+ return get_random_int() + (sizeof(long) > 4 ? (unsigned long)get_random_int() << 32 : 0);
+}
+EXPORT_SYMBOL(get_random_long);
+#endif
/*
* randomize_range() returns a start address such that
*
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index c055d56..2839124 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -30,6 +30,9 @@ config COMPAT_BINFMT_ELF
config ARCH_BINFMT_ELF_RANDOMIZE_PIE
bool

+config RANDOMIZE_ALL_MMAPS
+ bool
+
config ARCH_BINFMT_ELF_STATE
bool

diff --git a/include/linux/random.h b/include/linux/random.h
index b05856e..8ea61e1 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -23,6 +23,9 @@ extern const struct file_operations random_fops, urandom_fops;
#endif

unsigned int get_random_int(void);
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+unsigned long get_random_long(void);
+#endif
unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);

u32 prandom_u32(void);
diff --git a/mm/mmap.c b/mm/mmap.c
index 7b36aa7..8c9c3c7 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -41,6 +41,10 @@
#include <linux/notifier.h>
#include <linux/memory.h>
#include <linux/printk.h>
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+#include <linux/random.h>
+#include <asm/compat.h>
+#endif

#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -2005,7 +2009,19 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long (*get_area)(struct file *, unsigned long,
unsigned long, unsigned long, unsigned long);

- unsigned long error = arch_mmap_check(addr, len, flags);
+ unsigned long error;
+#ifdef CONFIG_RANDOMIZE_ALL_MMAPS
+ unsigned long min_addr = PAGE_ALIGN(mmap_min_addr);
+ unsigned long max_addr = PAGE_ALIGN(current->mm->mmap_base);
+
+ /* ASRLv3: If addr is NULL then randomize the mmap */
+ if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 2)
+ && !is_compat_task() && !addr ){
+ addr = (get_random_long() << PAGE_SHIFT) % (max_addr - min_addr);
+ addr += min_addr;
+ }
+#endif
+ error = arch_mmap_check(addr, len, flags);
if (error)
return error;



Hector Marco.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/