aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/capability.h2
-rw-r--r--kernel/ptrace.c27
-rw-r--r--security/commoncap.c40
3 files changed, 49 insertions, 20 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 7c9c82903012..2ec4a8cc86a5 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -553,6 +553,8 @@ static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a,
553 */ 553 */
554#define has_capability(t, cap) (security_real_capable((t), &init_user_ns, (cap)) == 0) 554#define has_capability(t, cap) (security_real_capable((t), &init_user_ns, (cap)) == 0)
555 555
556#define has_ns_capability(t, ns, cap) (security_real_capable((t), (ns), (cap)) == 0)
557
556/** 558/**
557 * has_capability_noaudit - Determine if a task has a superior capability available (unaudited) 559 * has_capability_noaudit - Determine if a task has a superior capability available (unaudited)
558 * @t: The task in question 560 * @t: The task in question
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;
149ok:
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);
diff --git a/security/commoncap.c b/security/commoncap.c
index 43a205bc7d7c..f20e984ccfb4 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -127,18 +127,30 @@ int cap_settime(const struct timespec *ts, const struct timezone *tz)
127 * @child: The process to be accessed 127 * @child: The process to be accessed
128 * @mode: The mode of attachment. 128 * @mode: The mode of attachment.
129 * 129 *
130 * If we are in the same or an ancestor user_ns and have all the target
131 * task's capabilities, then ptrace access is allowed.
132 * If we have the ptrace capability to the target user_ns, then ptrace
133 * access is allowed.
134 * Else denied.
135 *
130 * Determine whether a process may access another, returning 0 if permission 136 * Determine whether a process may access another, returning 0 if permission
131 * granted, -ve if denied. 137 * granted, -ve if denied.
132 */ 138 */
133int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) 139int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
134{ 140{
135 int ret = 0; 141 int ret = 0;
142 const struct cred *cred, *child_cred;
136 143
137 rcu_read_lock(); 144 rcu_read_lock();
138 if (!cap_issubset(__task_cred(child)->cap_permitted, 145 cred = current_cred();
139 current_cred()->cap_permitted) && 146 child_cred = __task_cred(child);
140 !capable(CAP_SYS_PTRACE)) 147 if (cred->user->user_ns == child_cred->user->user_ns &&
141 ret = -EPERM; 148 cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
149 goto out;
150 if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE))
151 goto out;
152 ret = -EPERM;
153out:
142 rcu_read_unlock(); 154 rcu_read_unlock();
143 return ret; 155 return ret;
144} 156}
@@ -147,18 +159,30 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
147 * cap_ptrace_traceme - Determine whether another process may trace the current 159 * cap_ptrace_traceme - Determine whether another process may trace the current
148 * @parent: The task proposed to be the tracer 160 * @parent: The task proposed to be the tracer
149 * 161 *
162 * If parent is in the same or an ancestor user_ns and has all current's
163 * capabilities, then ptrace access is allowed.
164 * If parent has the ptrace capability to current's user_ns, then ptrace
165 * access is allowed.
166 * Else denied.
167 *
150 * Determine whether the nominated task is permitted to trace the current 168 * Determine whether the nominated task is permitted to trace the current
151 * process, returning 0 if permission is granted, -ve if denied. 169 * process, returning 0 if permission is granted, -ve if denied.
152 */ 170 */
153int cap_ptrace_traceme(struct task_struct *parent) 171int cap_ptrace_traceme(struct task_struct *parent)
154{ 172{
155 int ret = 0; 173 int ret = 0;
174 const struct cred *cred, *child_cred;
156 175
157 rcu_read_lock(); 176 rcu_read_lock();
158 if (!cap_issubset(current_cred()->cap_permitted, 177 cred = __task_cred(parent);
159 __task_cred(parent)->cap_permitted) && 178 child_cred = current_cred();
160 !has_capability(parent, CAP_SYS_PTRACE)) 179 if (cred->user->user_ns == child_cred->user->user_ns &&
161 ret = -EPERM; 180 cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
181 goto out;
182 if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE))
183 goto out;
184 ret = -EPERM;
185out:
162 rcu_read_unlock(); 186 rcu_read_unlock();
163 return ret; 187 return ret;
164} 188}