Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

LSM: generalize flag passing to security_capable

This patch provides a general mechanism for passing flags to the
security_capable LSM hook. It replaces the specific 'audit' flag that is
used to tell security_capable whether it should log an audit message for
the given capability check. The reason for generalizing this flag
passing is so we can add an additional flag that signifies whether
security_capable is being called by a setid syscall (which is needed by
the proposed SafeSetID LSM).

Signed-off-by: Micah Morton <mortonm@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: James Morris <james.morris@microsoft.com>

authored by

Micah Morton and committed by
James Morris
c1a85a00 2233975c

+71 -67
+5 -3
include/linux/lsm_hooks.h
··· 1270 1270 * @cred contains the credentials to use. 1271 1271 * @ns contains the user namespace we want the capability in 1272 1272 * @cap contains the capability <include/linux/capability.h>. 1273 - * @audit contains whether to write an audit message or not 1273 + * @opts contains options for the capable check <include/linux/security.h> 1274 1274 * Return 0 if the capability is granted for @tsk. 1275 1275 * @syslog: 1276 1276 * Check permission before accessing the kernel message ring or changing ··· 1446 1446 const kernel_cap_t *effective, 1447 1447 const kernel_cap_t *inheritable, 1448 1448 const kernel_cap_t *permitted); 1449 - int (*capable)(const struct cred *cred, struct user_namespace *ns, 1450 - int cap, int audit); 1449 + int (*capable)(const struct cred *cred, 1450 + struct user_namespace *ns, 1451 + int cap, 1452 + unsigned int opts); 1451 1453 int (*quotactl)(int cmds, int type, int id, struct super_block *sb); 1452 1454 int (*quota_on)(struct dentry *dentry); 1453 1455 int (*syslog)(int type);
+14 -14
include/linux/security.h
··· 54 54 struct xfrm_sec_ctx; 55 55 struct mm_struct; 56 56 57 + /* Default (no) options for the capable function */ 58 + #define CAP_OPT_NONE 0x0 57 59 /* If capable should audit the security request */ 58 - #define SECURITY_CAP_NOAUDIT 0 59 - #define SECURITY_CAP_AUDIT 1 60 + #define CAP_OPT_NOAUDIT BIT(1) 61 + /* If capable is being called by a setid function */ 62 + #define CAP_OPT_INSETID BIT(2) 60 63 61 64 /* LSM Agnostic defines for sb_set_mnt_opts */ 62 65 #define SECURITY_LSM_NATIVE_LABELS 1 ··· 75 72 76 73 /* These functions are in security/commoncap.c */ 77 74 extern int cap_capable(const struct cred *cred, struct user_namespace *ns, 78 - int cap, int audit); 75 + int cap, unsigned int opts); 79 76 extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz); 80 77 extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); 81 78 extern int cap_ptrace_traceme(struct task_struct *parent); ··· 210 207 const kernel_cap_t *effective, 211 208 const kernel_cap_t *inheritable, 212 209 const kernel_cap_t *permitted); 213 - int security_capable(const struct cred *cred, struct user_namespace *ns, 214 - int cap); 215 - int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, 216 - int cap); 210 + int security_capable(const struct cred *cred, 211 + struct user_namespace *ns, 212 + int cap, 213 + unsigned int opts); 217 214 int security_quotactl(int cmds, int type, int id, struct super_block *sb); 218 215 int security_quota_on(struct dentry *dentry); 219 216 int security_syslog(int type); ··· 467 464 } 468 465 469 466 static inline int security_capable(const struct cred *cred, 470 - struct user_namespace *ns, int cap) 467 + struct user_namespace *ns, 468 + int cap, 469 + unsigned int opts) 471 470 { 472 - return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); 473 - } 474 - 475 - static inline int security_capable_noaudit(const struct cred *cred, 476 - struct user_namespace *ns, int cap) { 477 - return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); 471 + return cap_capable(cred, ns, cap, opts); 478 472 } 479 473 480 474 static inline int security_quotactl(int cmds, int type, int id,
+13 -9
kernel/capability.c
··· 299 299 int ret; 300 300 301 301 rcu_read_lock(); 302 - ret = security_capable(__task_cred(t), ns, cap); 302 + ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE); 303 303 rcu_read_unlock(); 304 304 305 305 return (ret == 0); ··· 340 340 int ret; 341 341 342 342 rcu_read_lock(); 343 - ret = security_capable_noaudit(__task_cred(t), ns, cap); 343 + ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT); 344 344 rcu_read_unlock(); 345 345 346 346 return (ret == 0); ··· 363 363 return has_ns_capability_noaudit(t, &init_user_ns, cap); 364 364 } 365 365 366 - static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) 366 + static bool ns_capable_common(struct user_namespace *ns, 367 + int cap, 368 + unsigned int opts) 367 369 { 368 370 int capable; 369 371 ··· 374 372 BUG(); 375 373 } 376 374 377 - capable = audit ? security_capable(current_cred(), ns, cap) : 378 - security_capable_noaudit(current_cred(), ns, cap); 375 + capable = security_capable(current_cred(), ns, cap, opts); 379 376 if (capable == 0) { 380 377 current->flags |= PF_SUPERPRIV; 381 378 return true; ··· 395 394 */ 396 395 bool ns_capable(struct user_namespace *ns, int cap) 397 396 { 398 - return ns_capable_common(ns, cap, true); 397 + return ns_capable_common(ns, cap, CAP_OPT_NONE); 399 398 } 400 399 EXPORT_SYMBOL(ns_capable); 401 400 ··· 413 412 */ 414 413 bool ns_capable_noaudit(struct user_namespace *ns, int cap) 415 414 { 416 - return ns_capable_common(ns, cap, false); 415 + return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT); 417 416 } 418 417 EXPORT_SYMBOL(ns_capable_noaudit); 419 418 ··· 449 448 bool file_ns_capable(const struct file *file, struct user_namespace *ns, 450 449 int cap) 451 450 { 451 + 452 452 if (WARN_ON_ONCE(!cap_valid(cap))) 453 453 return false; 454 454 455 - if (security_capable(file->f_cred, ns, cap) == 0) 455 + if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE) == 0) 456 456 return true; 457 457 458 458 return false; ··· 502 500 { 503 501 int ret = 0; /* An absent tracer adds no restrictions */ 504 502 const struct cred *cred; 503 + 505 504 rcu_read_lock(); 506 505 cred = rcu_dereference(tsk->ptracer_cred); 507 506 if (cred) 508 - ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE); 507 + ret = security_capable(cred, ns, CAP_SYS_PTRACE, 508 + CAP_OPT_NOAUDIT); 509 509 rcu_read_unlock(); 510 510 return (ret == 0); 511 511 }
+2 -2
kernel/seccomp.c
··· 443 443 * behavior of privileged children. 444 444 */ 445 445 if (!task_no_new_privs(current) && 446 - security_capable_noaudit(current_cred(), current_user_ns(), 447 - CAP_SYS_ADMIN) != 0) 446 + security_capable(current_cred(), current_user_ns(), 447 + CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0) 448 448 return ERR_PTR(-EACCES); 449 449 450 450 /* Allocate a new seccomp_filter */
+7 -7
security/apparmor/capability.c
··· 110 110 * profile_capable - test if profile allows use of capability @cap 111 111 * @profile: profile being enforced (NOT NULL, NOT unconfined) 112 112 * @cap: capability to test if allowed 113 - * @audit: whether an audit record should be generated 113 + * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 114 114 * @sa: audit data (MAY BE NULL indicating no auditing) 115 115 * 116 116 * Returns: 0 if allowed else -EPERM 117 117 */ 118 - static int profile_capable(struct aa_profile *profile, int cap, int audit, 119 - struct common_audit_data *sa) 118 + static int profile_capable(struct aa_profile *profile, int cap, 119 + unsigned int opts, struct common_audit_data *sa) 120 120 { 121 121 int error; 122 122 ··· 126 126 else 127 127 error = -EPERM; 128 128 129 - if (audit == SECURITY_CAP_NOAUDIT) { 129 + if (opts & CAP_OPT_NOAUDIT) { 130 130 if (!COMPLAIN_MODE(profile)) 131 131 return error; 132 132 /* audit the cap request in complain mode but note that it ··· 142 142 * aa_capable - test permission to use capability 143 143 * @label: label being tested for capability (NOT NULL) 144 144 * @cap: capability to be tested 145 - * @audit: whether an audit record should be generated 145 + * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 146 146 * 147 147 * Look up capability in profile capability set. 148 148 * 149 149 * Returns: 0 on success, or else an error code. 150 150 */ 151 - int aa_capable(struct aa_label *label, int cap, int audit) 151 + int aa_capable(struct aa_label *label, int cap, unsigned int opts) 152 152 { 153 153 struct aa_profile *profile; 154 154 int error = 0; ··· 156 156 157 157 sa.u.cap = cap; 158 158 error = fn_for_each_confined(label, profile, 159 - profile_capable(profile, cap, audit, &sa)); 159 + profile_capable(profile, cap, opts, &sa)); 160 160 161 161 return error; 162 162 }
+1 -1
security/apparmor/include/capability.h
··· 40 40 41 41 extern struct aa_sfs_entry aa_sfs_entry_caps[]; 42 42 43 - int aa_capable(struct aa_label *label, int cap, int audit); 43 + int aa_capable(struct aa_label *label, int cap, unsigned int opts); 44 44 45 45 static inline void aa_free_cap_rules(struct aa_caps *caps) 46 46 {
+2 -1
security/apparmor/ipc.c
··· 107 107 aad(sa)->label = &tracer->label; 108 108 aad(sa)->peer = tracee; 109 109 aad(sa)->request = 0; 110 - aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); 110 + aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 111 + CAP_OPT_NONE); 111 112 112 113 return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); 113 114 }
+2 -2
security/apparmor/lsm.c
··· 172 172 } 173 173 174 174 static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, 175 - int cap, int audit) 175 + int cap, unsigned int opts) 176 176 { 177 177 struct aa_label *label; 178 178 int error = 0; 179 179 180 180 label = aa_get_newest_cred_label(cred); 181 181 if (!unconfined(label)) 182 - error = aa_capable(label, cap, audit); 182 + error = aa_capable(label, cap, opts); 183 183 aa_put_label(label); 184 184 185 185 return error;
+1 -1
security/apparmor/resource.c
··· 124 124 */ 125 125 126 126 if (label != peer && 127 - aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0) 127 + aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0) 128 128 error = fn_for_each(label, profile, 129 129 audit_resource(profile, resource, 130 130 new_rlim->rlim_max, peer,
+9 -8
security/commoncap.c
··· 68 68 * kernel's capable() and has_capability() returns 1 for this case. 69 69 */ 70 70 int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, 71 - int cap, int audit) 71 + int cap, unsigned int opts) 72 72 { 73 73 struct user_namespace *ns = targ_ns; 74 74 ··· 222 222 */ 223 223 static inline int cap_inh_is_capped(void) 224 224 { 225 - 226 225 /* they are so limited unless the current task has the CAP_SETPCAP 227 226 * capability 228 227 */ 229 228 if (cap_capable(current_cred(), current_cred()->user_ns, 230 - CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) 229 + CAP_SETPCAP, CAP_OPT_NONE) == 0) 231 230 return 0; 232 231 return 1; 233 232 } ··· 1207 1208 || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ 1208 1209 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ 1209 1210 || (cap_capable(current_cred(), 1210 - current_cred()->user_ns, CAP_SETPCAP, 1211 - SECURITY_CAP_AUDIT) != 0) /*[4]*/ 1211 + current_cred()->user_ns, 1212 + CAP_SETPCAP, 1213 + CAP_OPT_NONE) != 0) /*[4]*/ 1212 1214 /* 1213 1215 * [1] no changing of bits that are locked 1214 1216 * [2] no unlocking of locks ··· 1304 1304 { 1305 1305 int cap_sys_admin = 0; 1306 1306 1307 - if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, 1308 - SECURITY_CAP_NOAUDIT) == 0) 1307 + if (cap_capable(current_cred(), &init_user_ns, 1308 + CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0) 1309 1309 cap_sys_admin = 1; 1310 + 1310 1311 return cap_sys_admin; 1311 1312 } 1312 1313 ··· 1326 1325 1327 1326 if (addr < dac_mmap_min_addr) { 1328 1327 ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, 1329 - SECURITY_CAP_AUDIT); 1328 + CAP_OPT_NONE); 1330 1329 /* set PF_SUPERPRIV if it turns out we allow the low mmap */ 1331 1330 if (ret == 0) 1332 1331 current->flags |= PF_SUPERPRIV;
+5 -9
security/security.c
··· 689 689 effective, inheritable, permitted); 690 690 } 691 691 692 - int security_capable(const struct cred *cred, struct user_namespace *ns, 693 - int cap) 692 + int security_capable(const struct cred *cred, 693 + struct user_namespace *ns, 694 + int cap, 695 + unsigned int opts) 694 696 { 695 - return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT); 696 - } 697 - 698 - int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, 699 - int cap) 700 - { 701 - return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT); 697 + return call_int_hook(capable, 0, cred, ns, cap, opts); 702 698 } 703 699 704 700 int security_quotactl(int cmds, int type, int id, struct super_block *sb)
+9 -9
security/selinux/hooks.c
··· 1578 1578 1579 1579 /* Check whether a task is allowed to use a capability. */ 1580 1580 static int cred_has_capability(const struct cred *cred, 1581 - int cap, int audit, bool initns) 1581 + int cap, unsigned int opts, bool initns) 1582 1582 { 1583 1583 struct common_audit_data ad; 1584 1584 struct av_decision avd; ··· 1605 1605 1606 1606 rc = avc_has_perm_noaudit(&selinux_state, 1607 1607 sid, sid, sclass, av, 0, &avd); 1608 - if (audit == SECURITY_CAP_AUDIT) { 1608 + if (!(opts & CAP_OPT_NOAUDIT)) { 1609 1609 int rc2 = avc_audit(&selinux_state, 1610 1610 sid, sid, sclass, av, &avd, rc, &ad, 0); 1611 1611 if (rc2) ··· 2125 2125 */ 2126 2126 2127 2127 static int selinux_capable(const struct cred *cred, struct user_namespace *ns, 2128 - int cap, int audit) 2128 + int cap, unsigned int opts) 2129 2129 { 2130 - return cred_has_capability(cred, cap, audit, ns == &init_user_ns); 2130 + return cred_has_capability(cred, cap, opts, ns == &init_user_ns); 2131 2131 } 2132 2132 2133 2133 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) ··· 2201 2201 int rc, cap_sys_admin = 0; 2202 2202 2203 2203 rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, 2204 - SECURITY_CAP_NOAUDIT, true); 2204 + CAP_OPT_NOAUDIT, true); 2205 2205 if (rc == 0) 2206 2206 cap_sys_admin = 1; 2207 2207 ··· 2988 2988 static bool has_cap_mac_admin(bool audit) 2989 2989 { 2990 2990 const struct cred *cred = current_cred(); 2991 - int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT; 2991 + unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT; 2992 2992 2993 - if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit)) 2993 + if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts)) 2994 2994 return false; 2995 - if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true)) 2995 + if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true)) 2996 2996 return false; 2997 2997 return true; 2998 2998 } ··· 3387 3387 case KDSKBENT: 3388 3388 case KDSKBSENT: 3389 3389 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, 3390 - SECURITY_CAP_AUDIT, true); 3390 + CAP_OPT_NONE, true); 3391 3391 break; 3392 3392 3393 3393 /* default case assumes that the command will go
+1 -1
security/smack/smack_access.c
··· 640 640 struct smack_known_list_elem *sklep; 641 641 int rc; 642 642 643 - rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT); 643 + rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE); 644 644 if (rc) 645 645 return false; 646 646