diff options
| author | Ingo Molnar <mingo@elte.hu> | 2004-07-17 19:08:19 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-07-17 19:08:19 -0700 |
| commit | 1bb0fa189c6ae75cbf440244ae77a8ede9912df1 (patch) | |
| tree | 8f1d4e06906886a4dd5d5705b6bb461957ecf72f /include | |
| parent | 4e8688b284f9c714510be1036c245ce6374018b7 (diff) | |
[PATCH] NX: clean up legacy binary support
This cleans up legacy x86 binary support by introducing a new
personality bit: READ_IMPLIES_EXEC, and implements Linus' suggestion to
add the PROT_EXEC bit on the two affected syscall entry places,
sys_mprotect() and sys_mmap(). If this bit is set then PROT_READ will
also add the PROT_EXEC bit - as expected by legacy x86 binaries. The
ELF loader will automatically set this bit when it encounters a legacy
binary.
This approach avoids the problems the previous ->def_flags solution
caused. In particular this patch fixes the PROT_NONE problem in a
cleaner way (http://lkml.org/lkml/2004/7/12/227), and it should fix the
ia64 PROT_EXEC problem reported by David Mosberger. Also,
mprotect(PROT_READ) done by legacy binaries will do the right thing as
well.
the details:
- the personality bit is added to the personality mask upon exec(),
within the ELF loader, but is not cleared (see the exceptions below).
This means that if an environment that already has the bit exec()s a
new-style binary it will still get the old behavior.
- one exception are setuid/setgid binaries: these will reset the
bit - thus local attackers cannot manually set the bit and circumvent
NX protection. Legacy setuid binaries will still get the bit through
the ELF loader. This gives us maximum flexibility in shaping
compatibility environments.
- selinux also clears the bit when switching SIDs via exec().
- x86 is the only arch making use of READ_IMPLIES_EXEC currently. Other
arches will have the pre-NX-patch protection setup they always had.
I have booted an old distro [RH 7.2] and two new PT_GNU_STACK distros
[SuSE 9.2 and FC2] on an NX-capable CPU - they work just fine and all
the mapping details are right. I've checked the PROT_NONE test-utility
as well and it works as expected. I have checked various setuid
scenarios as well involving legacy and new-style binaries.
an improved setarch utility can be used to set the personality bit
manually:
http://redhat.com/~mingo/nx-patches/setarch-1.4-3.tar.gz
the new '-X' flag does it, e.g.:
./setarch -X linux /bin/cat /proc/self/maps
will trigger the old protection layout even on a new distro.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include')
| -rw-r--r-- | include/asm-i386/elf.h | 8 | ||||
| -rw-r--r-- | include/asm-i386/page.h | 6 | ||||
| -rw-r--r-- | include/linux/personality.h | 7 |
3 files changed, 18 insertions, 3 deletions
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index cda7f174b694..57ecbcf525ac 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h @@ -117,7 +117,13 @@ typedef struct user_fxsr_struct elf_fpxregset_t; #define AT_SYSINFO_EHDR 33 #ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#define SET_PERSONALITY(ex, ibcs2) do { } while (0) + +/* + * A legacy binary, when loaded by the ELF loader, will have the + * READ_IMPLIES_EXEC personality flag set automatically: + */ +#define LEGACY_BINARIES extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index f544cc131b28..eb0e11f10683 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -140,8 +140,10 @@ static __inline__ int get_order(unsigned long size) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #endif /* __KERNEL__ */ diff --git a/include/linux/personality.h b/include/linux/personality.h index 14b91221d3e8..9b009b6754f6 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -30,6 +30,7 @@ extern int abi_fake_utsname; */ enum { MMAP_PAGE_ZERO = 0x0100000, + READ_IMPLIES_EXEC = 0x0400000, ADDR_LIMIT_32BIT = 0x0800000, SHORT_INODE = 0x1000000, WHOLE_SECONDS = 0x2000000, @@ -38,6 +39,12 @@ enum { }; /* + * Security-relevant compatibility flags that must be + * cleared upon setuid or setgid exec: + */ +#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC) + +/* * Personality types. * * These go in the low byte. Avoid using the top bit, it will |
