diff options
author | Tyler Hicks <tyhicks@canonical.com> | 2016-06-03 00:43:21 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2016-06-06 06:16:18 -0400 |
commit | 98f368e9e2630a3ce3e80fb10fb2e02038cf9578 (patch) | |
tree | ae14325043192683972bc25ca35c8b7ceb8b8241 | |
parent | 2885c1e3e0c29e4a1915214ddc9673925f538299 (diff) |
kernel: Add noaudit variant of ns_capable()
When checking the current cred for a capability in a specific user
namespace, it isn't always desirable to have the LSMs audit the check.
This patch adds a noaudit variant of ns_capable() for when those
situations arise.
The common logic between ns_capable() and the new ns_capable_noaudit()
is moved into a single, shared function to keep duplicated code to a
minimum and ease maintainability.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Signed-off-by: James Morris <james.l.morris@oracle.com>
-rw-r--r-- | include/linux/capability.h | 5 | ||||
-rw-r--r-- | kernel/capability.c | 46 |
2 files changed, 41 insertions, 10 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h index 00690ff92edf..5f3c63dde2d5 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -206,6 +206,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, | |||
206 | struct user_namespace *ns, int cap); | 206 | struct user_namespace *ns, int cap); |
207 | extern bool capable(int cap); | 207 | extern bool capable(int cap); |
208 | extern bool ns_capable(struct user_namespace *ns, int cap); | 208 | extern bool ns_capable(struct user_namespace *ns, int cap); |
209 | extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); | ||
209 | #else | 210 | #else |
210 | static inline bool has_capability(struct task_struct *t, int cap) | 211 | static inline bool has_capability(struct task_struct *t, int cap) |
211 | { | 212 | { |
@@ -233,6 +234,10 @@ static inline bool ns_capable(struct user_namespace *ns, int cap) | |||
233 | { | 234 | { |
234 | return true; | 235 | return true; |
235 | } | 236 | } |
237 | static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) | ||
238 | { | ||
239 | return true; | ||
240 | } | ||
236 | #endif /* CONFIG_MULTIUSER */ | 241 | #endif /* CONFIG_MULTIUSER */ |
237 | extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); | 242 | extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); |
238 | extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); | 243 | extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); |
diff --git a/kernel/capability.c b/kernel/capability.c index 45432b54d5c6..00411c82dac5 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -361,6 +361,24 @@ bool has_capability_noaudit(struct task_struct *t, int cap) | |||
361 | return has_ns_capability_noaudit(t, &init_user_ns, cap); | 361 | return has_ns_capability_noaudit(t, &init_user_ns, cap); |
362 | } | 362 | } |
363 | 363 | ||
364 | static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) | ||
365 | { | ||
366 | int capable; | ||
367 | |||
368 | if (unlikely(!cap_valid(cap))) { | ||
369 | pr_crit("capable() called with invalid cap=%u\n", cap); | ||
370 | BUG(); | ||
371 | } | ||
372 | |||
373 | capable = audit ? security_capable(current_cred(), ns, cap) : | ||
374 | security_capable_noaudit(current_cred(), ns, cap); | ||
375 | if (capable == 0) { | ||
376 | current->flags |= PF_SUPERPRIV; | ||
377 | return true; | ||
378 | } | ||
379 | return false; | ||
380 | } | ||
381 | |||
364 | /** | 382 | /** |
365 | * ns_capable - Determine if the current task has a superior capability in effect | 383 | * ns_capable - Determine if the current task has a superior capability in effect |
366 | * @ns: The usernamespace we want the capability in | 384 | * @ns: The usernamespace we want the capability in |
@@ -374,19 +392,27 @@ bool has_capability_noaudit(struct task_struct *t, int cap) | |||
374 | */ | 392 | */ |
375 | bool ns_capable(struct user_namespace *ns, int cap) | 393 | bool ns_capable(struct user_namespace *ns, int cap) |
376 | { | 394 | { |
377 | if (unlikely(!cap_valid(cap))) { | 395 | return ns_capable_common(ns, cap, true); |
378 | pr_crit("capable() called with invalid cap=%u\n", cap); | ||
379 | BUG(); | ||
380 | } | ||
381 | |||
382 | if (security_capable(current_cred(), ns, cap) == 0) { | ||
383 | current->flags |= PF_SUPERPRIV; | ||
384 | return true; | ||
385 | } | ||
386 | return false; | ||
387 | } | 396 | } |
388 | EXPORT_SYMBOL(ns_capable); | 397 | EXPORT_SYMBOL(ns_capable); |
389 | 398 | ||
399 | /** | ||
400 | * ns_capable_noaudit - Determine if the current task has a superior capability | ||
401 | * (unaudited) in effect | ||
402 | * @ns: The usernamespace we want the capability in | ||
403 | * @cap: The capability to be tested for | ||
404 | * | ||
405 | * Return true if the current task has the given superior capability currently | ||
406 | * available for use, false if not. | ||
407 | * | ||
408 | * This sets PF_SUPERPRIV on the task if the capability is available on the | ||
409 | * assumption that it's about to be used. | ||
410 | */ | ||
411 | bool ns_capable_noaudit(struct user_namespace *ns, int cap) | ||
412 | { | ||
413 | return ns_capable_common(ns, cap, false); | ||
414 | } | ||
415 | EXPORT_SYMBOL(ns_capable_noaudit); | ||
390 | 416 | ||
391 | /** | 417 | /** |
392 | * capable - Determine if the current task has a superior capability in effect | 418 | * capable - Determine if the current task has a superior capability in effect |