On Thu, Dec 24, 2015 at 7:30 AM, Jann Horn <jann@xxxxxxxxx> wrote: > This adds a new ptrace_may_access_file() method that extracts > the caller credentials from the supplied file instead of the > current task. (However, the current task may still be > inspected for auditing purposes, e.g. by the Smack LSM.) > > procfs used the caller's creds for a few ptrace_may_access() > checks at read() time, which made a confused deputy attack > by passing an FD to a procfs file to a setuid program > possible. Therefore, the following was a local userspace > ASLR bypass: > > rm -f /tmp/foobar > procmail <(echo 'DEFAULT=/tmp/foobar') </proc/1/stat > ( > echo 'obase=16' > cut -d' ' -f26-30,45-51 </tmp/foobar | tr ' ' '\n' > ) | bc > rm /tmp/foobar We keep poking around the edges of all these /proc permission-check corner-cases, and I get more and more nervous the more complex we make it. I'd really love it if there was tools/testing/selftests/proc/ set of tests to check all these corner cases. We need to have a single place where we call out all the specific details of what behaviors are expected, and that we have a useful regression test for it as well. Would you be willing to design these tests? -Kees > > procmail is installed setuid root on Debian and read()s > data from stdin before dropping privs, so the > ptrace_may_access() check in the VFS read handler of > /proc/1/stat passes. Procmail then dumps the read data > to a user-accessible file (/tmp/foobar here). > > I know that this is way larger than 100 lines, but is it > possible to get a stable backport for it anyway? > > The hole in the PTRACE_MODE_... constants is intentional, > it should reduce the merge conflicts with abc5df4106 a bit. > > If this is backported, ab5931b90b also needs to be > backported. > > checkpatch throws a ton of warnings about overlong lines. > Should I split all those lines? > > Can anyone tell me whether I violated the locking rules > somewhere? > > CC: Stable <stable@xxxxxxxxxxxxxxx> > Signed-off-by: Jann Horn <jann@xxxxxxxxx> > --- > fs/file_table.c | 2 ++ > fs/proc/array.c | 2 +- > fs/proc/base.c | 29 +++++++++++++++++------------ > fs/seq_file.c | 1 + > include/linux/fs.h | 2 ++ > include/linux/lsm_hooks.h | 3 ++- > include/linux/ptrace.h | 2 ++ > include/linux/security.h | 8 ++++---- > include/linux/seq_file.h | 1 + > kernel/ptrace.c | 35 +++++++++++++++++++++++------------ > security/apparmor/include/ipc.h | 2 +- > security/apparmor/ipc.c | 4 +--- > security/apparmor/lsm.c | 12 +++++++++--- > security/commoncap.c | 7 +++---- > security/security.c | 4 ++-- > security/selinux/hooks.c | 4 ++-- > security/smack/smack_lsm.c | 16 ++++++++++------ > security/yama/yama_lsm.c | 8 +++++--- > 18 files changed, 88 insertions(+), 54 deletions(-) > > diff --git a/fs/file_table.c b/fs/file_table.c > index ad17e05..671033e 100644 > --- a/fs/file_table.c > +++ b/fs/file_table.c > @@ -125,6 +125,7 @@ struct file *get_empty_filp(void) > > percpu_counter_inc(&nr_files); > f->f_cred = get_cred(cred); > + f->f_tgid = get_pid(task_tgid(current)); > error = security_file_alloc(f); > if (unlikely(error)) { > file_free(f); > @@ -222,6 +223,7 @@ static void __fput(struct file *file) > file->f_path.dentry = NULL; > file->f_path.mnt = NULL; > file->f_inode = NULL; > + put_pid(file->f_tgid); > file_free(file); > dput(dentry); > mntput(mnt); > diff --git a/fs/proc/array.c b/fs/proc/array.c > index d73291f..db5aeb7 100644 > --- a/fs/proc/array.c > +++ b/fs/proc/array.c > @@ -395,7 +395,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, > > state = *get_task_state(task); > vsize = eip = esp = 0; > - permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT); > + permitted = ptrace_may_access_file(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT, m->file); > mm = get_task_mm(task); > if (mm) { > vsize = task_vsize(mm); > diff --git a/fs/proc/base.c b/fs/proc/base.c > index 4bd5d31..2d0ce7a 100644 > --- a/fs/proc/base.c > +++ b/fs/proc/base.c > @@ -430,7 +430,8 @@ static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns, > > wchan = get_wchan(task); > > - if (wchan && ptrace_may_access(task, PTRACE_MODE_READ) && !lookup_symbol_name(wchan, symname)) > + if (wchan && ptrace_may_access_file(task, PTRACE_MODE_READ, m->file) && > + !lookup_symbol_name(wchan, symname)) > seq_printf(m, "%s", symname); > else > seq_putc(m, '0'); > @@ -439,12 +440,12 @@ static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns, > } > #endif /* CONFIG_KALLSYMS */ > > -static int lock_trace(struct task_struct *task) > +static int lock_trace(struct seq_file *m, struct task_struct *task) > { > int err = mutex_lock_killable(&task->signal->cred_guard_mutex); > if (err) > return err; > - if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) { > + if (!ptrace_may_access_file(task, PTRACE_MODE_ATTACH, m->file)) { > mutex_unlock(&task->signal->cred_guard_mutex); > return -EPERM; > } > @@ -477,7 +478,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, > trace.entries = entries; > trace.skip = 0; > > - err = lock_trace(task); > + err = lock_trace(m, task); > if (!err) { > save_stack_trace_tsk(task, &trace); > > @@ -662,7 +663,7 @@ static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, > unsigned long args[6], sp, pc; > int res; > > - res = lock_trace(task); > + res = lock_trace(m, task); > if (res) > return res; > > @@ -726,13 +727,17 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) > */ > static bool has_pid_permissions(struct pid_namespace *pid, > struct task_struct *task, > + struct file *cred_file, > int hide_pid_min) > { > if (pid->hide_pid < hide_pid_min) > return true; > if (in_group_p(pid->pid_gid)) > return true; > - return ptrace_may_access(task, PTRACE_MODE_READ); > + if (cred_file == NULL) > + return ptrace_may_access(task, PTRACE_MODE_READ); > + else > + return ptrace_may_access_file(task, PTRACE_MODE_READ, cred_file); > } > > > @@ -745,7 +750,7 @@ static int proc_pid_permission(struct inode *inode, int mask) > task = get_proc_task(inode); > if (!task) > return -ESRCH; > - has_perms = has_pid_permissions(pid, task, 1); > + has_perms = has_pid_permissions(pid, task, NULL, 1); > put_task_struct(task); > > if (!has_perms) { > @@ -1693,7 +1698,7 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) > stat->gid = GLOBAL_ROOT_GID; > task = pid_task(proc_pid(inode), PIDTYPE_PID); > if (task) { > - if (!has_pid_permissions(pid, task, 2)) { > + if (!has_pid_permissions(pid, task, NULL, 2)) { > rcu_read_unlock(); > /* > * This doesn't prevent learning whether PID exists, > @@ -2060,7 +2065,7 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx) > goto out; > > ret = -EACCES; > - if (!ptrace_may_access(task, PTRACE_MODE_READ)) > + if (!ptrace_may_access_file(task, PTRACE_MODE_READ, file)) > goto out_put_task; > > ret = 0; > @@ -2530,7 +2535,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh > if (result) > return result; > > - if (!ptrace_may_access(task, PTRACE_MODE_READ)) { > + if (!ptrace_may_access_file(task, PTRACE_MODE_READ, m->file)) { > result = -EACCES; > goto out_unlock; > } > @@ -2714,7 +2719,7 @@ static const struct file_operations proc_setgroups_operations = { > static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, > struct pid *pid, struct task_struct *task) > { > - int err = lock_trace(task); > + int err = lock_trace(m, task); > if (!err) { > seq_printf(m, "%08x\n", task->personality); > unlock_trace(task); > @@ -3061,7 +3066,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) > iter.tgid += 1, iter = next_tgid(ns, iter)) { > char name[PROC_NUMBUF]; > int len; > - if (!has_pid_permissions(ns, iter.task, 2)) > + if (!has_pid_permissions(ns, iter.task, file, 2)) > continue; > > len = snprintf(name, sizeof(name), "%d", iter.tgid); > diff --git a/fs/seq_file.c b/fs/seq_file.c > index e85664b..32a070e 100644 > --- a/fs/seq_file.c > +++ b/fs/seq_file.c > @@ -68,6 +68,7 @@ int seq_open(struct file *file, const struct seq_operations *op) > if (!p) > return -ENOMEM; > > + p->file = file; > file->private_data = p; > > mutex_init(&p->lock); > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 3aa5142..9be60d4 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -857,6 +857,8 @@ struct file { > loff_t f_pos; > struct fown_struct f_owner; > const struct cred *f_cred; > + /* for opener-based access checks, mostly in procfs */ > + struct pid *f_tgid; > struct file_ra_state f_ra; > > u64 f_version; > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h > index ec3a6ba..d2995cb 100644 > --- a/include/linux/lsm_hooks.h > +++ b/include/linux/lsm_hooks.h > @@ -1148,6 +1148,7 @@ > * attributes would be changed by the execve. > * @child contains the task_struct structure for the target process. > * @mode contains the PTRACE_MODE flags indicating the form of access. > + * @cred contains the caller's credentials > * Return 0 if permission is granted. > * @ptrace_traceme: > * Check that the @parent process has sufficient permission to trace the > @@ -1311,7 +1312,7 @@ union security_list_options { > struct file *file); > > int (*ptrace_access_check)(struct task_struct *child, > - unsigned int mode); > + unsigned int mode, const struct cred *cred); > int (*ptrace_traceme)(struct task_struct *parent); > int (*capget)(struct task_struct *target, kernel_cap_t *effective, > kernel_cap_t *inheritable, kernel_cap_t *permitted); > diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h > index 061265f..f29390a 100644 > --- a/include/linux/ptrace.h > +++ b/include/linux/ptrace.h > @@ -57,8 +57,10 @@ extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead); > #define PTRACE_MODE_READ 0x01 > #define PTRACE_MODE_ATTACH 0x02 > #define PTRACE_MODE_NOAUDIT 0x04 > +#define PTRACE_MODE_NON_CURRENT 0x20 /* don't use privs of current task */ > /* Returns true on success, false on denial. */ > extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); > +bool ptrace_may_access_file(struct task_struct *task, unsigned int mode, struct file *f); > > static inline int ptrace_reparented(struct task_struct *child) > { > diff --git a/include/linux/security.h b/include/linux/security.h > index 2f4c1f7..d3eec58 100644 > --- a/include/linux/security.h > +++ b/include/linux/security.h > @@ -70,7 +70,7 @@ struct timezone; > extern int cap_capable(const struct cred *cred, struct user_namespace *ns, > int cap, int audit); > extern int cap_settime(const struct timespec *ts, const struct timezone *tz); > -extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); > +extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode, const struct cred *cred); > extern int cap_ptrace_traceme(struct task_struct *parent); > extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); > extern int cap_capset(struct cred *new, const struct cred *old, > @@ -189,7 +189,7 @@ int security_binder_transfer_binder(struct task_struct *from, > struct task_struct *to); > int security_binder_transfer_file(struct task_struct *from, > struct task_struct *to, struct file *file); > -int security_ptrace_access_check(struct task_struct *child, unsigned int mode); > +int security_ptrace_access_check(struct task_struct *child, unsigned int mode, const struct cred *cred); > int security_ptrace_traceme(struct task_struct *parent); > int security_capget(struct task_struct *target, > kernel_cap_t *effective, > @@ -403,9 +403,9 @@ static inline int security_binder_transfer_file(struct task_struct *from, > } > > static inline int security_ptrace_access_check(struct task_struct *child, > - unsigned int mode) > + unsigned int mode, const struct cred *cred) > { > - return cap_ptrace_access_check(child, mode); > + return cap_ptrace_access_check(child, mode, cred); > } > > static inline int security_ptrace_traceme(struct task_struct *parent) > diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h > index dde00de..55ab0d8 100644 > --- a/include/linux/seq_file.h > +++ b/include/linux/seq_file.h > @@ -30,6 +30,7 @@ struct seq_file { > #ifdef CONFIG_USER_NS > struct user_namespace *user_ns; > #endif > + struct file *file; > void *private; > }; > > diff --git a/kernel/ptrace.c b/kernel/ptrace.c > index b760bae..3ee70e9 100644 > --- a/kernel/ptrace.c > +++ b/kernel/ptrace.c > @@ -207,18 +207,18 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state) > return ret; > } > > -static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) > +static int ptrace_has_cap(const struct cred *cred, struct user_namespace *ns, unsigned int mode) > { > if (mode & PTRACE_MODE_NOAUDIT) > - return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); > + return security_capable_noaudit(cred, ns, CAP_SYS_PTRACE) == 0; > else > - return has_ns_capability(current, ns, CAP_SYS_PTRACE); > + return security_capable(cred, ns, CAP_SYS_PTRACE) == 0; > } > > /* Returns 0 on success, -errno on denial. */ > -static int __ptrace_may_access(struct task_struct *task, unsigned int mode) > +static int __ptrace_may_access(struct task_struct *task, unsigned int mode, const struct cred *cred, struct pid *caller_tgid) > { > - const struct cred *cred = current_cred(), *tcred; > + const struct cred *tcred; > > /* May we inspect the given task? > * This check is used both for attaching with ptrace > @@ -229,10 +229,12 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) > * or halting the specified task is impossible. > */ > int dumpable = 0; > + rcu_read_lock(); > /* Don't let security modules deny introspection */ > - if (same_thread_group(task, current)) > + if (task_tgid(task) == caller_tgid) { > + rcu_read_unlock(); > return 0; > - rcu_read_lock(); > + } > tcred = __task_cred(task); > if (uid_eq(cred->uid, tcred->euid) && > uid_eq(cred->uid, tcred->suid) && > @@ -241,7 +243,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) > gid_eq(cred->gid, tcred->sgid) && > gid_eq(cred->gid, tcred->gid)) > goto ok; > - if (ptrace_has_cap(tcred->user_ns, mode)) > + if (ptrace_has_cap(cred, tcred->user_ns, mode)) > goto ok; > rcu_read_unlock(); > return -EPERM; > @@ -252,20 +254,29 @@ ok: > dumpable = get_dumpable(task->mm); > rcu_read_lock(); > if (dumpable != SUID_DUMP_USER && > - !ptrace_has_cap(__task_cred(task)->user_ns, mode)) { > + !ptrace_has_cap(cred, __task_cred(task)->user_ns, mode)) { > rcu_read_unlock(); > return -EPERM; > } > rcu_read_unlock(); > > - return security_ptrace_access_check(task, mode); > + return security_ptrace_access_check(task, mode, cred); > } > > bool ptrace_may_access(struct task_struct *task, unsigned int mode) > { > int err; > task_lock(task); > - err = __ptrace_may_access(task, mode); > + err = __ptrace_may_access(task, mode, current_cred(), task_tgid(current)); > + task_unlock(task); > + return !err; > +} > + > +bool ptrace_may_access_file(struct task_struct *task, unsigned int mode, struct file *f) > +{ > + int err; > + task_lock(task); > + err = __ptrace_may_access(task, mode | PTRACE_MODE_NON_CURRENT, f->f_cred, f->f_tgid); > task_unlock(task); > return !err; > } > @@ -306,7 +317,7 @@ static int ptrace_attach(struct task_struct *task, long request, > goto out; > > task_lock(task); > - retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); > + retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH, current_cred(), task_tgid(current)); > task_unlock(task); > if (retval) > goto unlock_creds; > diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h > index 288ca76..eb685c1 100644 > --- a/security/apparmor/include/ipc.h > +++ b/security/apparmor/include/ipc.h > @@ -22,7 +22,7 @@ struct aa_profile; > int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, > unsigned int mode); > > -int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, > +int aa_ptrace(struct aa_profile *tracer_p, struct task_struct *tracee, > unsigned int mode); > > #endif /* __AA_IPC_H */ > diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c > index 777ac1c..c60b374 100644 > --- a/security/apparmor/ipc.c > +++ b/security/apparmor/ipc.c > @@ -82,7 +82,7 @@ int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, > * > * Returns: %0 else error code if permission denied or error > */ > -int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, > +int aa_ptrace(struct aa_profile *tracer_p, struct task_struct *tracee, > unsigned int mode) > { > /* > @@ -94,7 +94,6 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, > * - tracer profile has CAP_SYS_PTRACE > */ > > - struct aa_profile *tracer_p = aa_get_task_profile(tracer); > int error = 0; > > if (!unconfined(tracer_p)) { > @@ -105,7 +104,6 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, > > aa_put_profile(tracee_p); > } > - aa_put_profile(tracer_p); > > return error; > } > diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c > index dec607c..a4f3f40 100644 > --- a/security/apparmor/lsm.c > +++ b/security/apparmor/lsm.c > @@ -94,14 +94,20 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) > } > > static int apparmor_ptrace_access_check(struct task_struct *child, > - unsigned int mode) > + unsigned int mode, const struct cred *cred) > { > - return aa_ptrace(current, child, mode); > + struct aa_profile *tracer_p = aa_get_profile(aa_cred_profile(cred)); > + int res = aa_ptrace(tracer_p, child, mode); > + aa_put_profile(tracer_p); > + return res; > } > > static int apparmor_ptrace_traceme(struct task_struct *parent) > { > - return aa_ptrace(parent, current, PTRACE_MODE_ATTACH); > + struct aa_profile *tracer_p = aa_get_task_profile(tracer); > + int res = aa_ptrace(tracer_p, current, PTRACE_MODE_ATTACH); > + aa_put_profile(tracer_p); > + return res; > } > > /* Derived from security/commoncap.c:cap_capget */ > diff --git a/security/commoncap.c b/security/commoncap.c > index 1832cf7..7a385b2 100644 > --- a/security/commoncap.c > +++ b/security/commoncap.c > @@ -133,18 +133,17 @@ int cap_settime(const struct timespec *ts, const struct timezone *tz) > * Determine whether a process may access another, returning 0 if permission > * granted, -ve if denied. > */ > -int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) > +int cap_ptrace_access_check(struct task_struct *child, unsigned int mode, const struct cred *cred) > { > int ret = 0; > - const struct cred *cred, *child_cred; > + const struct cred *child_cred; > > rcu_read_lock(); > - cred = current_cred(); > child_cred = __task_cred(child); > if (cred->user_ns == child_cred->user_ns && > cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) > goto out; > - if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE)) > + if (security_capable(cred, child_cred->user_ns, CAP_SYS_PTRACE) == 0) > goto out; > ret = -EPERM; > out: > diff --git a/security/security.c b/security/security.c > index 46f405c..e01899b 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -153,9 +153,9 @@ int security_binder_transfer_file(struct task_struct *from, > return call_int_hook(binder_transfer_file, 0, from, to, file); > } > > -int security_ptrace_access_check(struct task_struct *child, unsigned int mode) > +int security_ptrace_access_check(struct task_struct *child, unsigned int mode, const struct cred *cred) > { > - return call_int_hook(ptrace_access_check, 0, child, mode); > + return call_int_hook(ptrace_access_check, 0, child, mode, cred); > } > > int security_ptrace_traceme(struct task_struct *parent) > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c > index d0cfaa9..0e45c89 100644 > --- a/security/selinux/hooks.c > +++ b/security/selinux/hooks.c > @@ -2036,10 +2036,10 @@ static int selinux_binder_transfer_file(struct task_struct *from, > } > > static int selinux_ptrace_access_check(struct task_struct *child, > - unsigned int mode) > + unsigned int mode, const struct cred *cred) > { > if (mode & PTRACE_MODE_READ) { > - u32 sid = current_sid(); > + u32 sid = cred_sid(cred); > u32 csid = task_sid(child); > return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); > } > diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c > index ff81026..866ebf5 100644 > --- a/security/smack/smack_lsm.c > +++ b/security/smack/smack_lsm.c > @@ -410,7 +410,8 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) > > /** > * smk_ptrace_rule_check - helper for ptrace access > - * @tracer: tracer process > + * @tracer: tracer process - only used for auditing if @tracer_cred is set > + * @tracer_cred: creds for checks, may be different from @tracer's creds > * @tracee_known: label entry of the process that's about to be traced > * @mode: ptrace attachment mode (PTRACE_MODE_*) > * @func: name of the function that called us, used for audit > @@ -418,6 +419,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) > * Returns 0 on access granted, -error on error > */ > static int smk_ptrace_rule_check(struct task_struct *tracer, > + const struct cred *tracer_cred, > struct smack_known *tracee_known, > unsigned int mode, const char *func) > { > @@ -433,7 +435,9 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, > } > > rcu_read_lock(); > - tsp = __task_cred(tracer)->security; > + if (tracer_cred == NULL) > + tracer_cred = __task_cred(tracer); > + tsp = tracer_cred->security; > tracer_known = smk_of_task(tsp); > > if ((mode & PTRACE_MODE_ATTACH) && > @@ -478,13 +482,13 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, > * > * Do the capability checks. > */ > -static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) > +static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode, const struct cred *cred) > { > struct smack_known *skp; > > skp = smk_of_task_struct(ctp); > > - return smk_ptrace_rule_check(current, skp, mode, __func__); > + return smk_ptrace_rule_check(current, cred, skp, mode, __func__); > } > > /** > @@ -502,7 +506,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) > > skp = smk_of_task(current_security()); > > - rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); > + rc = smk_ptrace_rule_check(ptp, NULL, skp, PTRACE_MODE_ATTACH, __func__); > return rc; > } > > @@ -926,7 +930,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) > rcu_read_lock(); > tracer = ptrace_parent(current); > if (likely(tracer != NULL)) > - rc = smk_ptrace_rule_check(tracer, > + rc = smk_ptrace_rule_check(tracer, NULL, > isp->smk_task, > PTRACE_MODE_ATTACH, > __func__); > diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c > index d3c19c9..4300181 100644 > --- a/security/yama/yama_lsm.c > +++ b/security/yama/yama_lsm.c > @@ -276,7 +276,7 @@ static int ptracer_exception_found(struct task_struct *tracer, > * Returns 0 if following the ptrace is allowed, -ve on error. > */ > static int yama_ptrace_access_check(struct task_struct *child, > - unsigned int mode) > + unsigned int mode, const struct cred *cred) > { > int rc = 0; > > @@ -288,7 +288,9 @@ static int yama_ptrace_access_check(struct task_struct *child, > break; > case YAMA_SCOPE_RELATIONAL: > rcu_read_lock(); > - if (!task_is_descendant(current, child) && > + /* fail open for some procfs-based ATTACH accesses! */ > + if ((mode & PTRACE_MODE_NON_CURRENT) == 0 && > + !task_is_descendant(current, child) && > !ptracer_exception_found(current, child) && > !ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE)) > rc = -EPERM; > @@ -296,7 +298,7 @@ static int yama_ptrace_access_check(struct task_struct *child, > break; > case YAMA_SCOPE_CAPABILITY: > rcu_read_lock(); > - if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE)) > + if (security_capable(cred, __task_cred(child)->user_ns, CAP_SYS_PTRACE) != 0) > rc = -EPERM; > rcu_read_unlock(); > break; > -- > 2.1.4 > -- Kees Cook Chrome OS & Brillo Security -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html