diff options
author | Serge E. Hallyn <serge@hallyn.com> | 2011-03-23 19:43:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 22:47:05 -0400 |
commit | 8409cca7056113bee3236cb6a8e4d8d4d1eef102 (patch) | |
tree | d9f1ced0d47070fcdf8b399021f33770c150b1ec /kernel/ptrace.c | |
parent | 39fd33933b0209e4b6254743f2cede07c5ad4c52 (diff) |
userns: allow ptrace from non-init user namespaces
ptrace is allowed to tasks in the same user namespace according to the
usual rules (i.e. the same rules as for two tasks in the init user
namespace). ptrace is also allowed to a user namespace to which the
current task the has CAP_SYS_PTRACE capability.
Changelog:
Dec 31: Address feedback by Eric:
. Correct ptrace uid check
. Rename may_ptrace_ns to ptrace_capable
. Also fix the cap_ptrace checks.
Jan 1: Use const cred struct
Jan 11: use task_ns_capable() in place of ptrace_capable().
Feb 23: same_or_ancestore_user_ns() was not an appropriate
check to constrain cap_issubset. Rather, cap_issubset()
only is meaningful when both capsets are in the same
user_ns.
Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Acked-by: David Howells <dhowells@redhat.com>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e2302e40b360..0fc1eed28d27 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -134,21 +134,24 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
134 | return 0; | 134 | return 0; |
135 | rcu_read_lock(); | 135 | rcu_read_lock(); |
136 | tcred = __task_cred(task); | 136 | tcred = __task_cred(task); |
137 | if ((cred->uid != tcred->euid || | 137 | if (cred->user->user_ns == tcred->user->user_ns && |
138 | cred->uid != tcred->suid || | 138 | (cred->uid == tcred->euid && |
139 | cred->uid != tcred->uid || | 139 | cred->uid == tcred->suid && |
140 | cred->gid != tcred->egid || | 140 | cred->uid == tcred->uid && |
141 | cred->gid != tcred->sgid || | 141 | cred->gid == tcred->egid && |
142 | cred->gid != tcred->gid) && | 142 | cred->gid == tcred->sgid && |
143 | !capable(CAP_SYS_PTRACE)) { | 143 | cred->gid == tcred->gid)) |
144 | rcu_read_unlock(); | 144 | goto ok; |
145 | return -EPERM; | 145 | if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) |
146 | } | 146 | goto ok; |
147 | rcu_read_unlock(); | ||
148 | return -EPERM; | ||
149 | ok: | ||
147 | rcu_read_unlock(); | 150 | rcu_read_unlock(); |
148 | smp_rmb(); | 151 | smp_rmb(); |
149 | if (task->mm) | 152 | if (task->mm) |
150 | dumpable = get_dumpable(task->mm); | 153 | dumpable = get_dumpable(task->mm); |
151 | if (!dumpable && !capable(CAP_SYS_PTRACE)) | 154 | if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE)) |
152 | return -EPERM; | 155 | return -EPERM; |
153 | 156 | ||
154 | return security_ptrace_access_check(task, mode); | 157 | return security_ptrace_access_check(task, mode); |
@@ -198,7 +201,7 @@ static int ptrace_attach(struct task_struct *task) | |||
198 | goto unlock_tasklist; | 201 | goto unlock_tasklist; |
199 | 202 | ||
200 | task->ptrace = PT_PTRACED; | 203 | task->ptrace = PT_PTRACED; |
201 | if (capable(CAP_SYS_PTRACE)) | 204 | if (task_ns_capable(task, CAP_SYS_PTRACE)) |
202 | task->ptrace |= PT_PTRACE_CAP; | 205 | task->ptrace |= PT_PTRACE_CAP; |
203 | 206 | ||
204 | __ptrace_link(task, current); | 207 | __ptrace_link(task, current); |