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.
This commit is contained in:
Dmitry Chagin 2016-07-10 08:15:50 +00:00
parent 51d1f69069
commit 23e8912c60
7 changed files with 89 additions and 9 deletions

View File

@ -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, \

View File

@ -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); }

View File

@ -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
}
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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 */

View File

@ -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); }