diff options
-rw-r--r-- | include/linux/capability.h | 2 | ||||
-rw-r--r-- | kernel/ptrace.c | 27 | ||||
-rw-r--r-- | security/commoncap.c | 40 |
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; | ||
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); |
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 | */ |
133 | int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) | 139 | int 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; | ||
153 | out: | ||
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 | */ |
153 | int cap_ptrace_traceme(struct task_struct *parent) | 171 | int 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; | ||
185 | out: | ||
162 | rcu_read_unlock(); | 186 | rcu_read_unlock(); |
163 | return ret; | 187 | return ret; |
164 | } | 188 | } |