Skip to content

Commit

Permalink
seccomp: hoist out filter resolving logic
Browse files Browse the repository at this point in the history
Hoist out the nth filter resolving logic that ptrace uses into a new
function. We'll use this in the next patch to implement the new
PTRACE_SECCOMP_GET_FILTER_FLAGS command.

Signed-off-by: Tycho Andersen <[email protected]>
CC: Kees Cook <[email protected]>
CC: Andy Lutomirski <[email protected]>
CC: Oleg Nesterov <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
  • Loading branch information
Tycho Andersen authored and kees committed Nov 28, 2017
1 parent 4fbd8d1 commit f06eae8
Showing 1 changed file with 45 additions and 32 deletions.
77 changes: 45 additions & 32 deletions kernel/seccomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,49 +978,68 @@ long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
}

#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE)
long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
void __user *data)
static struct seccomp_filter *get_nth_filter(struct task_struct *task,
unsigned long filter_off)
{
struct seccomp_filter *filter;
struct sock_fprog_kern *fprog;
long ret;
unsigned long count = 0;

if (!capable(CAP_SYS_ADMIN) ||
current->seccomp.mode != SECCOMP_MODE_DISABLED) {
return -EACCES;
}
struct seccomp_filter *orig, *filter;
unsigned long count;

/*
* Note: this is only correct because the caller should be the (ptrace)
* tracer of the task, otherwise lock_task_sighand is needed.
*/
spin_lock_irq(&task->sighand->siglock);

if (task->seccomp.mode != SECCOMP_MODE_FILTER) {
ret = -EINVAL;
goto out;
spin_unlock_irq(&task->sighand->siglock);
return ERR_PTR(-EINVAL);
}

filter = task->seccomp.filter;
while (filter) {
filter = filter->prev;
orig = task->seccomp.filter;
__get_seccomp_filter(orig);
spin_unlock_irq(&task->sighand->siglock);

count = 0;
for (filter = orig; filter; filter = filter->prev)
count++;
}

if (filter_off >= count) {
ret = -ENOENT;
filter = ERR_PTR(-ENOENT);
goto out;
}
count -= filter_off;

filter = task->seccomp.filter;
while (filter && count > 1) {
filter = filter->prev;
count -= filter_off;
for (filter = orig; filter && count > 1; filter = filter->prev)
count--;
}

if (WARN_ON(count != 1 || !filter)) {
/* The filter tree shouldn't shrink while we're using it. */
ret = -ENOENT;
filter = ERR_PTR(-ENOENT);
goto out;
}

__get_seccomp_filter(filter);

out:
__put_seccomp_filter(orig);
return filter;
}

long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
void __user *data)
{
struct seccomp_filter *filter;
struct sock_fprog_kern *fprog;
long ret;

if (!capable(CAP_SYS_ADMIN) ||
current->seccomp.mode != SECCOMP_MODE_DISABLED) {
return -EACCES;
}

filter = get_nth_filter(task, filter_off);
if (IS_ERR(filter))
return PTR_ERR(filter);

fprog = filter->prog->orig_prog;
if (!fprog) {
/* This must be a new non-cBPF filter, since we save
Expand All @@ -1035,17 +1054,11 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
if (!data)
goto out;

__get_seccomp_filter(filter);
spin_unlock_irq(&task->sighand->siglock);

if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
ret = -EFAULT;

__put_seccomp_filter(filter);
return ret;

out:
spin_unlock_irq(&task->sighand->siglock);
__put_seccomp_filter(filter);
return ret;
}
#endif
Expand Down

0 comments on commit f06eae8

Please sign in to comment.