|
@@ -127,18 +127,30 @@ int cap_settime(const struct timespec *ts, const struct timezone *tz)
|
|
|
* @child: The process to be accessed
|
|
|
* @mode: The mode of attachment.
|
|
|
*
|
|
|
+ * If we are in the same or an ancestor user_ns and have all the target
|
|
|
+ * task's capabilities, then ptrace access is allowed.
|
|
|
+ * If we have the ptrace capability to the target user_ns, then ptrace
|
|
|
+ * access is allowed.
|
|
|
+ * Else denied.
|
|
|
+ *
|
|
|
* Determine whether a process may access another, returning 0 if permission
|
|
|
* granted, -ve if denied.
|
|
|
*/
|
|
|
int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
+ const struct cred *cred, *child_cred;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- if (!cap_issubset(__task_cred(child)->cap_permitted,
|
|
|
- current_cred()->cap_permitted) &&
|
|
|
- !capable(CAP_SYS_PTRACE))
|
|
|
- ret = -EPERM;
|
|
|
+ cred = current_cred();
|
|
|
+ child_cred = __task_cred(child);
|
|
|
+ if (cred->user->user_ns == child_cred->user->user_ns &&
|
|
|
+ cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
|
|
|
+ goto out;
|
|
|
+ if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE))
|
|
|
+ goto out;
|
|
|
+ ret = -EPERM;
|
|
|
+out:
|
|
|
rcu_read_unlock();
|
|
|
return ret;
|
|
|
}
|
|
@@ -147,18 +159,30 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
|
|
|
* cap_ptrace_traceme - Determine whether another process may trace the current
|
|
|
* @parent: The task proposed to be the tracer
|
|
|
*
|
|
|
+ * If parent is in the same or an ancestor user_ns and has all current's
|
|
|
+ * capabilities, then ptrace access is allowed.
|
|
|
+ * If parent has the ptrace capability to current's user_ns, then ptrace
|
|
|
+ * access is allowed.
|
|
|
+ * Else denied.
|
|
|
+ *
|
|
|
* Determine whether the nominated task is permitted to trace the current
|
|
|
* process, returning 0 if permission is granted, -ve if denied.
|
|
|
*/
|
|
|
int cap_ptrace_traceme(struct task_struct *parent)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
+ const struct cred *cred, *child_cred;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- if (!cap_issubset(current_cred()->cap_permitted,
|
|
|
- __task_cred(parent)->cap_permitted) &&
|
|
|
- !has_capability(parent, CAP_SYS_PTRACE))
|
|
|
- ret = -EPERM;
|
|
|
+ cred = __task_cred(parent);
|
|
|
+ child_cred = current_cred();
|
|
|
+ if (cred->user->user_ns == child_cred->user->user_ns &&
|
|
|
+ cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
|
|
|
+ goto out;
|
|
|
+ if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE))
|
|
|
+ goto out;
|
|
|
+ ret = -EPERM;
|
|
|
+out:
|
|
|
rcu_read_unlock();
|
|
|
return ret;
|
|
|
}
|