diff options
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 24d04477b257..00ab2ca5ed11 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -96,9 +96,20 @@ void __ptrace_unlink(struct task_struct *child) | |||
96 | */ | 96 | */ |
97 | if (!(child->flags & PF_EXITING) && | 97 | if (!(child->flags & PF_EXITING) && |
98 | (child->signal->flags & SIGNAL_STOP_STOPPED || | 98 | (child->signal->flags & SIGNAL_STOP_STOPPED || |
99 | child->signal->group_stop_count)) | 99 | child->signal->group_stop_count)) { |
100 | child->jobctl |= JOBCTL_STOP_PENDING; | 100 | child->jobctl |= JOBCTL_STOP_PENDING; |
101 | 101 | ||
102 | /* | ||
103 | * This is only possible if this thread was cloned by the | ||
104 | * traced task running in the stopped group, set the signal | ||
105 | * for the future reports. | ||
106 | * FIXME: we should change ptrace_init_task() to handle this | ||
107 | * case. | ||
108 | */ | ||
109 | if (!(child->jobctl & JOBCTL_STOP_SIGMASK)) | ||
110 | child->jobctl |= SIGSTOP; | ||
111 | } | ||
112 | |||
102 | /* | 113 | /* |
103 | * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick | 114 | * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick |
104 | * @child in the butt. Note that @resume should be used iff @child | 115 | * @child in the butt. Note that @resume should be used iff @child |
@@ -161,6 +172,14 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state) | |||
161 | return ret; | 172 | return ret; |
162 | } | 173 | } |
163 | 174 | ||
175 | static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) | ||
176 | { | ||
177 | if (mode & PTRACE_MODE_NOAUDIT) | ||
178 | return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); | ||
179 | else | ||
180 | return has_ns_capability(current, ns, CAP_SYS_PTRACE); | ||
181 | } | ||
182 | |||
164 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) | 183 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
165 | { | 184 | { |
166 | const struct cred *cred = current_cred(), *tcred; | 185 | const struct cred *cred = current_cred(), *tcred; |
@@ -187,7 +206,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
187 | cred->gid == tcred->sgid && | 206 | cred->gid == tcred->sgid && |
188 | cred->gid == tcred->gid)) | 207 | cred->gid == tcred->gid)) |
189 | goto ok; | 208 | goto ok; |
190 | if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) | 209 | if (ptrace_has_cap(tcred->user->user_ns, mode)) |
191 | goto ok; | 210 | goto ok; |
192 | rcu_read_unlock(); | 211 | rcu_read_unlock(); |
193 | return -EPERM; | 212 | return -EPERM; |
@@ -196,7 +215,7 @@ ok: | |||
196 | smp_rmb(); | 215 | smp_rmb(); |
197 | if (task->mm) | 216 | if (task->mm) |
198 | dumpable = get_dumpable(task->mm); | 217 | dumpable = get_dumpable(task->mm); |
199 | if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE)) | 218 | if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode)) |
200 | return -EPERM; | 219 | return -EPERM; |
201 | 220 | ||
202 | return security_ptrace_access_check(task, mode); | 221 | return security_ptrace_access_check(task, mode); |
@@ -266,7 +285,7 @@ static int ptrace_attach(struct task_struct *task, long request, | |||
266 | task->ptrace = PT_PTRACED; | 285 | task->ptrace = PT_PTRACED; |
267 | if (seize) | 286 | if (seize) |
268 | task->ptrace |= PT_SEIZED; | 287 | task->ptrace |= PT_SEIZED; |
269 | if (task_ns_capable(task, CAP_SYS_PTRACE)) | 288 | if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) |
270 | task->ptrace |= PT_PTRACE_CAP; | 289 | task->ptrace |= PT_PTRACE_CAP; |
271 | 290 | ||
272 | __ptrace_link(task, current); | 291 | __ptrace_link(task, current); |