diff options
author | dchagin <dchagin@FreeBSD.org> | 2016-07-18 16:34:11 +0000 |
---|---|---|
committer | dchagin <dchagin@FreeBSD.org> | 2016-07-18 16:34:11 +0000 |
commit | 4c3b9b3d0b1440c023947795378d4f6aa8463c36 (patch) | |
tree | 82b72b3a2abc8bf74cf6e4650b0f40d3bda56328 | |
parent | 2749f7898c6b59dc0d15b6388dc5e3256e8400fb (diff) | |
download | FreeBSD-src-4c3b9b3d0b1440c023947795378d4f6aa8463c36.zip FreeBSD-src-4c3b9b3d0b1440c023947795378d4f6aa8463c36.tar.gz |
MFC r302515:
Implement Linux personality() system call mainly due to READ_IMPLIES_EXEC flag.
In Linux if this flag is set, PROT_READ implies PROT_EXEC for mmap().
Linux/i386 set this flag automatically if the binary requires executable stack.
READ_IMPLIES_EXEC flag will be used in the next Linux mmap() commit.
Approved by: re (gjb)
-rw-r--r-- | sys/amd64/linux/syscalls.master | 2 | ||||
-rw-r--r-- | sys/amd64/linux32/syscalls.master | 2 | ||||
-rw-r--r-- | sys/compat/linux/linux_emul.c | 17 | ||||
-rw-r--r-- | sys/compat/linux/linux_emul.h | 1 | ||||
-rw-r--r-- | sys/compat/linux/linux_misc.c | 18 | ||||
-rw-r--r-- | sys/compat/linux/linux_persona.h | 56 | ||||
-rw-r--r-- | sys/i386/linux/syscalls.master | 2 |
7 files changed, 89 insertions, 9 deletions
diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master index 5ed098a..d4544f8 100644 --- a/sys/amd64/linux/syscalls.master +++ b/sys/amd64/linux/syscalls.master @@ -270,7 +270,7 @@ 133 AUE_MKNOD STD { int linux_mknod(char *path, l_int mode, \ l_dev_t dev); } 134 AUE_USELIB UNIMPL uselib -135 AUE_PERSONALITY STD { int linux_personality(l_ulong per); } +135 AUE_PERSONALITY STD { int linux_personality(l_uint per); } 136 AUE_NULL STD { int linux_ustat(l_dev_t dev, \ struct l_ustat *ubuf); } 137 AUE_STATFS STD { int linux_statfs(char *path, \ diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master index 79cd2c8..20aa3c4 100644 --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -238,7 +238,7 @@ 134 AUE_BDFLUSH STD { int linux_bdflush(void); } 135 AUE_NULL STD { int linux_sysfs(l_int option, \ l_ulong arg1, l_ulong arg2); } -136 AUE_PERSONALITY STD { int linux_personality(l_ulong per); } +136 AUE_PERSONALITY STD { int linux_personality(l_uint per); } 137 AUE_NULL UNIMPL afs_syscall 138 AUE_SETFSUID STD { int linux_setfsuid16(l_uid16_t uid); } 139 AUE_SETFSGID STD { int linux_setfsgid16(l_gid16_t gid); } diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c index c2bf3ae..b244eea 100644 --- a/sys/compat/linux/linux_emul.c +++ b/sys/compat/linux/linux_emul.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <compat/linux/linux_emul.h> #include <compat/linux/linux_misc.h> +#include <compat/linux/linux_persona.h> #include <compat/linux/linux_util.h> @@ -127,7 +128,7 @@ linux_proc_init(struct thread *td, struct thread *newtd, int flags) /* epoll should be destroyed in a case of exec. */ pem = pem_find(p); KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n")); - + pem->persona = 0; if (pem->epoll != NULL) { emd = pem->epoll; pem->epoll = NULL; @@ -220,6 +221,9 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) { struct thread *td = curthread; struct thread *othertd; +#if defined(__amd64__) + struct linux_pemuldata *pem; +#endif /* * In a case of execing from linux binary properly detach @@ -243,6 +247,17 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) linux_proc_init(td, NULL, 0); else linux_proc_init(td, td, 0); +#if defined(__amd64__) + /* + * An IA32 executable which has executable stack will have the + * READ_IMPLIES_EXEC personality flag set automatically. + */ + if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && + imgp->stack_prot & VM_PROT_EXECUTE) { + pem = pem_find(p); + pem->persona |= LINUX_READ_IMPLIES_EXEC; + } +#endif } } diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h index 7262093..9a5a667 100644 --- a/sys/compat/linux/linux_emul.h +++ b/sys/compat/linux/linux_emul.h @@ -67,6 +67,7 @@ struct linux_pemuldata { uint32_t flags; /* process emuldata flags */ struct sx pem_sx; /* lock for this struct */ void *epoll; /* epoll data */ + uint32_t persona; /* process execution domain */ }; #define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx) diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 01fd25a..e61d363 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1200,15 +1200,23 @@ linux_mknodat(struct thread *td, struct linux_mknodat_args *args) int linux_personality(struct thread *td, struct linux_personality_args *args) { + struct linux_pemuldata *pem; + struct proc *p = td->td_proc; + uint32_t old; + #ifdef DEBUG if (ldebug(personality)) - printf(ARGS(personality, "%lu"), (unsigned long)args->per); + printf(ARGS(personality, "%u"), args->per); #endif - if (args->per != 0) - return (EINVAL); - /* Yes Jim, it's still a Linux... */ - td->td_retval[0] = 0; + PROC_LOCK(p); + pem = pem_find(p); + old = pem->persona; + if (args->per != 0xffffffff) + pem->persona = args->per; + PROC_UNLOCK(p); + + td->td_retval[0] = old; return (0); } diff --git a/sys/compat/linux/linux_persona.h b/sys/compat/linux/linux_persona.h new file mode 100644 index 0000000..8d84134 --- /dev/null +++ b/sys/compat/linux/linux_persona.h @@ -0,0 +1,56 @@ +/* + * $FreeBSD$ + */ + +#ifndef LINUX_PERSONALITY_H +#define LINUX_PERSONALITY_H + +/* + * Flags for bug emulation. + * + * These occupy the top three bytes. + */ +enum { + LINUX_UNAME26 = 0x0020000, + LINUX_ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization + * of VA space + */ + LINUX_FDPIC_FUNCPTRS = 0x0080000, /* userspace function + * ptrs point to descriptors + * (signal handling) + */ + LINUX_MMAP_PAGE_ZERO = 0x0100000, + LINUX_ADDR_COMPAT_LAYOUT = 0x0200000, + LINUX_READ_IMPLIES_EXEC = 0x0400000, + LINUX_ADDR_LIMIT_32BIT = 0x0800000, + LINUX_SHORT_INODE = 0x1000000, + LINUX_WHOLE_SECONDS = 0x2000000, + LINUX_STICKY_TIMEOUTS = 0x4000000, + LINUX_ADDR_LIMIT_3GB = 0x8000000, +}; + +/* + * Security-relevant compatibility flags that must be + * cleared upon setuid or setgid exec: + */ +#define LINUX_PER_CLEAR_ON_SETID (LINUX_READ_IMPLIES_EXEC | \ + LINUX_ADDR_NO_RANDOMIZE | \ + LINUX_ADDR_COMPAT_LAYOUT | \ + LINUX_MMAP_PAGE_ZERO) + +/* + * Personality types. + * + * These go in the low byte. Avoid using the top bit, it will + * conflict with error returns. + */ +enum { + LINUX_PER_LINUX = 0x0000, + LINUX_PER_LINUX_32BIT = 0x0000 | LINUX_ADDR_LIMIT_32BIT, + LINUX_PER_LINUX_FDPIC = 0x0000 | LINUX_FDPIC_FUNCPTRS, + LINUX_PER_LINUX32 = 0x0008, + LINUX_PER_LINUX32_3GB = 0x0008 | LINUX_ADDR_LIMIT_3GB, + LINUX_PER_MASK = 0x00ff, +}; + +#endif /* LINUX_PERSONALITY_H */ diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master index 7ec3154..5899adb 100644 --- a/sys/i386/linux/syscalls.master +++ b/sys/i386/linux/syscalls.master @@ -240,7 +240,7 @@ 134 AUE_BDFLUSH STD { int linux_bdflush(void); } 135 AUE_NULL STD { int linux_sysfs(l_int option, \ l_ulong arg1, l_ulong arg2); } -136 AUE_PERSONALITY STD { int linux_personality(l_ulong per); } +136 AUE_PERSONALITY STD { int linux_personality(l_uint per); } 137 AUE_NULL UNIMPL afs_syscall 138 AUE_SETFSUID STD { int linux_setfsuid16(l_uid16_t uid); } 139 AUE_SETFSGID STD { int linux_setfsgid16(l_gid16_t gid); } |