aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 261ee21e62db..9650e7aee267 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -20,6 +20,7 @@
20#include <linux/uio.h> 20#include <linux/uio.h>
21#include <linux/audit.h> 21#include <linux/audit.h>
22#include <linux/pid_namespace.h> 22#include <linux/pid_namespace.h>
23#include <linux/user_namespace.h>
23#include <linux/syscalls.h> 24#include <linux/syscalls.h>
24#include <linux/uaccess.h> 25#include <linux/uaccess.h>
25#include <linux/regset.h> 26#include <linux/regset.h>
@@ -207,12 +208,34 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
207 return ret; 208 return ret;
208} 209}
209 210
210static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) 211static bool ptrace_has_cap(const struct cred *tcred, unsigned int mode)
211{ 212{
213 struct user_namespace *tns = tcred->user_ns;
214
215 /* When a root-owned process enters a user namespace created by a
216 * malicious user, the user shouldn't be able to execute code under
217 * uid 0 by attaching to the root-owned process via ptrace.
218 * Therefore, similar to the capable_wrt_inode_uidgid() check,
219 * verify that all the uids and gids of the target process are
220 * mapped into a namespace below the current one in which the caller
221 * is capable.
222 * No fsuid/fsgid check because __ptrace_may_access doesn't do it
223 * either.
224 */
225 while (
226 !kuid_has_mapping(tns, tcred->euid) ||
227 !kuid_has_mapping(tns, tcred->suid) ||
228 !kuid_has_mapping(tns, tcred->uid) ||
229 !kgid_has_mapping(tns, tcred->egid) ||
230 !kgid_has_mapping(tns, tcred->sgid) ||
231 !kgid_has_mapping(tns, tcred->gid)) {
232 tns = tns->parent;
233 }
234
212 if (mode & PTRACE_MODE_NOAUDIT) 235 if (mode & PTRACE_MODE_NOAUDIT)
213 return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); 236 return has_ns_capability_noaudit(current, tns, CAP_SYS_PTRACE);
214 else 237 else
215 return has_ns_capability(current, ns, CAP_SYS_PTRACE); 238 return has_ns_capability(current, tns, CAP_SYS_PTRACE);
216} 239}
217 240
218/* Returns 0 on success, -errno on denial. */ 241/* Returns 0 on success, -errno on denial. */
@@ -264,7 +287,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
264 gid_eq(caller_gid, tcred->sgid) && 287 gid_eq(caller_gid, tcred->sgid) &&
265 gid_eq(caller_gid, tcred->gid)) 288 gid_eq(caller_gid, tcred->gid))
266 goto ok; 289 goto ok;
267 if (ptrace_has_cap(tcred->user_ns, mode)) 290 if (ptrace_has_cap(tcred, mode))
268 goto ok; 291 goto ok;
269 rcu_read_unlock(); 292 rcu_read_unlock();
270 return -EPERM; 293 return -EPERM;
@@ -275,7 +298,7 @@ ok:
275 dumpable = get_dumpable(task->mm); 298 dumpable = get_dumpable(task->mm);
276 rcu_read_lock(); 299 rcu_read_lock();
277 if (dumpable != SUID_DUMP_USER && 300 if (dumpable != SUID_DUMP_USER &&
278 !ptrace_has_cap(__task_cred(task)->user_ns, mode)) { 301 !ptrace_has_cap(__task_cred(task), mode)) {
279 rcu_read_unlock(); 302 rcu_read_unlock();
280 return -EPERM; 303 return -EPERM;
281 } 304 }