]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.8.16/ptrace-capture-the-ptracer-s-creds-not-pt_ptrace_cap.patch
Drop watchdog patch
[thirdparty/kernel/stable-queue.git] / releases / 4.8.16 / ptrace-capture-the-ptracer-s-creds-not-pt_ptrace_cap.patch
CommitLineData
b732247b
GKH
1From 64b875f7ac8a5d60a4e191479299e931ee949b67 Mon Sep 17 00:00:00 2001
2From: "Eric W. Biederman" <ebiederm@xmission.com>
3Date: Mon, 14 Nov 2016 18:48:07 -0600
4Subject: ptrace: Capture the ptracer's creds not PT_PTRACE_CAP
5
6From: Eric W. Biederman <ebiederm@xmission.com>
7
8commit 64b875f7ac8a5d60a4e191479299e931ee949b67 upstream.
9
10When the flag PT_PTRACE_CAP was added the PTRACE_TRACEME path was
11overlooked. This can result in incorrect behavior when an application
12like strace traces an exec of a setuid executable.
13
14Further PT_PTRACE_CAP does not have enough information for making good
15security decisions as it does not report which user namespace the
16capability is in. This has already allowed one mistake through
17insufficient granulariy.
18
19I found this issue when I was testing another corner case of exec and
20discovered that I could not get strace to set PT_PTRACE_CAP even when
21running strace as root with a full set of caps.
22
23This change fixes the above issue with strace allowing stracing as
24root a setuid executable without disabling setuid. More fundamentaly
25this change allows what is allowable at all times, by using the correct
26information in it's decision.
27
28Fixes: 4214e42f96d4 ("v2.4.9.11 -> v2.4.9.12")
29Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
30Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
31
32---
33 fs/exec.c | 2 +-
34 include/linux/capability.h | 1 +
35 include/linux/ptrace.h | 1 -
36 include/linux/sched.h | 1 +
37 kernel/capability.c | 20 ++++++++++++++++++++
38 kernel/ptrace.c | 12 +++++++-----
39 6 files changed, 30 insertions(+), 7 deletions(-)
40
41--- a/fs/exec.c
42+++ b/fs/exec.c
43@@ -1420,7 +1420,7 @@ static void check_unsafe_exec(struct lin
44 unsigned n_fs;
45
46 if (p->ptrace) {
47- if (p->ptrace & PT_PTRACE_CAP)
48+ if (ptracer_capable(p, current_user_ns()))
49 bprm->unsafe |= LSM_UNSAFE_PTRACE_CAP;
50 else
51 bprm->unsafe |= LSM_UNSAFE_PTRACE;
52--- a/include/linux/capability.h
53+++ b/include/linux/capability.h
54@@ -243,6 +243,7 @@ static inline bool ns_capable_noaudit(st
55 extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode);
56 extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
57 extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
58+extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns);
59
60 /* audit system wants to get cap info from files as well */
61 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
62--- a/include/linux/ptrace.h
63+++ b/include/linux/ptrace.h
64@@ -19,7 +19,6 @@
65 #define PT_SEIZED 0x00010000 /* SEIZE used, enable new behavior */
66 #define PT_PTRACED 0x00000001
67 #define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */
68-#define PT_PTRACE_CAP 0x00000004 /* ptracer can follow suid-exec */
69
70 #define PT_OPT_FLAG_SHIFT 3
71 /* PT_TRACE_* event enable flags */
72--- a/include/linux/sched.h
73+++ b/include/linux/sched.h
74@@ -1631,6 +1631,7 @@ struct task_struct {
75 struct list_head cpu_timers[3];
76
77 /* process credentials */
78+ const struct cred __rcu *ptracer_cred; /* Tracer's credentials at attach */
79 const struct cred __rcu *real_cred; /* objective and real subjective task
80 * credentials (COW) */
81 const struct cred __rcu *cred; /* effective (overridable) subjective task
82--- a/kernel/capability.c
83+++ b/kernel/capability.c
84@@ -485,3 +485,23 @@ bool capable_wrt_inode_uidgid(const stru
85 return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
86 }
87 EXPORT_SYMBOL(capable_wrt_inode_uidgid);
88+
89+/**
90+ * ptracer_capable - Determine if the ptracer holds CAP_SYS_PTRACE in the namespace
91+ * @tsk: The task that may be ptraced
92+ * @ns: The user namespace to search for CAP_SYS_PTRACE in
93+ *
94+ * Return true if the task that is ptracing the current task had CAP_SYS_PTRACE
95+ * in the specified user namespace.
96+ */
97+bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
98+{
99+ int ret = 0; /* An absent tracer adds no restrictions */
100+ const struct cred *cred;
101+ rcu_read_lock();
102+ cred = rcu_dereference(tsk->ptracer_cred);
103+ if (cred)
104+ ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE);
105+ rcu_read_unlock();
106+ return (ret == 0);
107+}
108--- a/kernel/ptrace.c
109+++ b/kernel/ptrace.c
110@@ -39,6 +39,9 @@ void __ptrace_link(struct task_struct *c
111 BUG_ON(!list_empty(&child->ptrace_entry));
112 list_add(&child->ptrace_entry, &new_parent->ptraced);
113 child->parent = new_parent;
114+ rcu_read_lock();
115+ child->ptracer_cred = get_cred(__task_cred(new_parent));
116+ rcu_read_unlock();
117 }
118
119 /**
120@@ -71,10 +74,14 @@ void __ptrace_link(struct task_struct *c
121 */
122 void __ptrace_unlink(struct task_struct *child)
123 {
124+ const struct cred *old_cred;
125 BUG_ON(!child->ptrace);
126
127 child->parent = child->real_parent;
128 list_del_init(&child->ptrace_entry);
129+ old_cred = child->ptracer_cred;
130+ child->ptracer_cred = NULL;
131+ put_cred(old_cred);
132
133 spin_lock(&child->sighand->siglock);
134 child->ptrace = 0;
135@@ -324,11 +331,6 @@ static int ptrace_attach(struct task_str
136
137 task_lock(task);
138 retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS);
139- if (!retval) {
140- struct mm_struct *mm = task->mm;
141- if (mm && ns_capable(mm->user_ns, CAP_SYS_PTRACE))
142- flags |= PT_PTRACE_CAP;
143- }
144 task_unlock(task);
145 if (retval)
146 goto unlock_creds;