Skip to content

Commit

Permalink
CHROMIUM: alt-syscall: Support permissive whitelist
Browse files Browse the repository at this point in the history
Add support for permissive whitelists which intercept and log blocked
syscalls, but allow the syscall anyway.

BUG=b:22226964
TEST=Run programs with "android_permissive" whitelist and observe that
non-whitelisted syscalls are logged, but still allowed.

Change-Id: If012a29078335ad2a9e5c6cb8918a9f568952ae4
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/321957
Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
  • Loading branch information
Andrew Bresticker authored and chrome-bot committed Jan 15, 2016
1 parent 28cd654 commit 2484f55
Showing 1 changed file with 77 additions and 7 deletions.
84 changes: 77 additions & 7 deletions security/chromiumos/alt-syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ struct syscall_whitelist {
const struct syscall_whitelist_entry *compat_whitelist;
unsigned int nr_compat_whitelist;
#endif
bool permissive;
};

static struct alt_sys_call_table default_table;

/* Intercept and log blocked syscalls. */
static asmlinkage long alt_sys_ni_syscall(void)
static asmlinkage long block_syscall(void)
{
struct task_struct *task = current;
struct pt_regs *regs = task_pt_regs(task);
Expand All @@ -45,6 +48,54 @@ static asmlinkage long alt_sys_ni_syscall(void)
return -ENOSYS;
}

typedef asmlinkage long (*raw_sys_call_ptr_t)(unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned long, unsigned long);

/*
* In permissive mode, warn that the syscall was blocked, but still allow
* it to go through. Note that since we don't have an easy way to map from
* syscall to number of arguments, we pass the maximum (6).
*/
static long do_syscall(raw_sys_call_ptr_t fn)
{
struct task_struct *task = current;
struct pt_regs *regs = task_pt_regs(task);
unsigned long args[6];

syscall_get_arguments(task, regs, 0, ARRAY_SIZE(args), args);

return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
}

static asmlinkage long warn_syscall(void)
{
struct task_struct *task = current;
struct pt_regs *regs = task_pt_regs(task);
int nr = syscall_get_nr(task, regs);
raw_sys_call_ptr_t fn = (raw_sys_call_ptr_t)default_table.table[nr];

pr_warn_ratelimited("[%d] %s: syscall %d not whitelisted\n",
task_pid_nr(task), task->comm, nr);

return do_syscall(fn);
}

#ifdef CONFIG_COMPAT
static asmlinkage long warn_compat_syscall(void)
{
struct task_struct *task = current;
struct pt_regs *regs = task_pt_regs(task);
int nr = syscall_get_nr(task, regs);
raw_sys_call_ptr_t fn = (raw_sys_call_ptr_t)default_table.compat_table[nr];

pr_warn_ratelimited("[%d] %s: compat syscall %d not whitelisted\n",
task_pid_nr(task), task->comm, nr);

return do_syscall(fn);
}
#endif

/*
* If an alt_syscall table allows prctl(), override it to prevent a process
* from changing its syscall table.
Expand Down Expand Up @@ -76,6 +127,15 @@ static asmlinkage long alt_sys_prctl(int option, unsigned long arg2,
SYSCALL_WHITELIST_COMPAT(x) \
}

#define PERMISSIVE_SYSCALL_WHITELIST(x) \
{ \
.name = #x "_permissive", \
.permissive = true, \
.whitelist = x ## _whitelist, \
.nr_whitelist = ARRAY_SIZE(x ## _whitelist), \
SYSCALL_WHITELIST_COMPAT(x) \
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_X86_64
#define __NR_compat_brk __NR_ia32_brk
Expand Down Expand Up @@ -608,6 +668,7 @@ static struct syscall_whitelist_entry android_compat_whitelist[] = {
static struct syscall_whitelist whitelists[] = {
SYSCALL_WHITELIST(read_write_test),
SYSCALL_WHITELIST(android),
PERMISSIVE_SYSCALL_WHITELIST(android),
};

static int alt_syscall_apply_whitelist(const struct syscall_whitelist *wl,
Expand All @@ -628,8 +689,11 @@ static int alt_syscall_apply_whitelist(const struct syscall_whitelist *wl,
}

for (i = 0; i < t->size; i++) {
if (!test_bit(i, whitelist))
t->table[i] = (sys_call_ptr_t)alt_sys_ni_syscall;
if (!test_bit(i, whitelist)) {
t->table[i] = wl->permissive ?
(sys_call_ptr_t)warn_syscall :
(sys_call_ptr_t)block_syscall;
}
}

return 0;
Expand All @@ -655,8 +719,11 @@ alt_syscall_apply_compat_whitelist(const struct syscall_whitelist *wl,
}

for (i = 0; i < t->compat_size; i++) {
if (!test_bit(i, whitelist))
t->compat_table[i] = (sys_call_ptr_t)alt_sys_ni_syscall;
if (!test_bit(i, whitelist)) {
t->compat_table[i] = wl->permissive ?
(sys_call_ptr_t)warn_compat_syscall :
(sys_call_ptr_t)block_syscall;
}
}

return 0;
Expand Down Expand Up @@ -704,10 +771,13 @@ static int alt_syscall_init_one(const struct syscall_whitelist *wl)
static int chromiumos_alt_syscall_init(void)
{
unsigned int i;
int err;

for (i = 0; i < ARRAY_SIZE(whitelists); i++) {
int err;
err = arch_dup_sys_call_table(&default_table);
if (err)
return err;

for (i = 0; i < ARRAY_SIZE(whitelists); i++) {
err = alt_syscall_init_one(&whitelists[i]);
if (err)
pr_warn("Failed to register syscall table %s: %d\n",
Expand Down

0 comments on commit 2484f55

Please sign in to comment.