Well, introduce utrace_set_caps() and utrace_get_caps(). See the next patch which converts ptrace to use these helpers.
Note that these helpers are xxx_caps(int caps), not xxx_cred(struct cred*). This is ugly, but capable() can't use cred* and always assumes current. --- include/linux/utrace.h | 3 +++ kernel/utrace.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) --- RHEL6/include/linux/utrace.h~4_SET_CREDS 2010-07-07 00:48:09.000000000 +0200 +++ RHEL6/include/linux/utrace.h 2010-07-07 02:37:10.000000000 +0200 @@ -624,6 +624,9 @@ int __must_check utrace_finish_examine(s struct utrace_engine *, struct utrace_examiner *); +int utrace_set_caps(struct task_struct *, struct utrace_engine *, int); +int utrace_get_caps(struct utrace_engine *); + /** * utrace_control_pid - control a thread being traced by a tracing engine * @pid: thread to affect --- RHEL6/kernel/utrace.c~4_SET_CREDS 2010-07-07 00:48:09.000000000 +0200 +++ RHEL6/kernel/utrace.c 2010-07-07 02:41:31.000000000 +0200 @@ -2457,10 +2457,38 @@ void task_utrace_proc_status(struct seq_ seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); } +/* + * The caller must ensure we can't race with exec. + */ +int utrace_set_caps(struct task_struct *target, struct utrace_engine *engine, + int caps) +{ + struct utrace *utrace = get_utrace_lock(target, engine, true); + + if (unlikely(IS_ERR(utrace))) + return PTR_ERR(utrace); + + engine->flags &= ~ENGINE_LSM_MASK; + engine->flags |= caps ? ENGINE_LSM_TRACE_CAP : ENGINE_LSM_TRACE; + spin_unlock(&utrace->lock); + + return 0; +} + +int utrace_get_caps(struct utrace_engine *engine) +{ + return engine->flags & ENGINE_LSM_TRACE_CAP; +} + int utrace_unsafe_exec(struct task_struct *task) { + struct utrace *utrace = task_utrace_struct(task); int unsafe = 0; + /* Recalc ->utrace_flags. We can optimize this later */ + spin_lock(&utrace->lock); + utrace_reset(task, utrace); + if (task->utrace_flags & ENGINE_LSM_TRACE) unsafe = LSM_UNSAFE_PTRACE; else if (task->utrace_flags & ENGINE_LSM_TRACE_CAP)