1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20ed3b28aSJohn Johansen /* 30ed3b28aSJohn Johansen * AppArmor security module 40ed3b28aSJohn Johansen * 50ed3b28aSJohn Johansen * This file contains AppArmor capability mediation functions 60ed3b28aSJohn Johansen * 70ed3b28aSJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 80ed3b28aSJohn Johansen * Copyright 2009-2010 Canonical Ltd. 90ed3b28aSJohn Johansen */ 100ed3b28aSJohn Johansen 110ed3b28aSJohn Johansen #include <linux/capability.h> 120ed3b28aSJohn Johansen #include <linux/errno.h> 130ed3b28aSJohn Johansen #include <linux/gfp.h> 1412eb87d5SJohn Johansen #include <linux/security.h> 15*fee7a234SRyan Lee #include <linux/timekeeping.h> 160ed3b28aSJohn Johansen 170ed3b28aSJohn Johansen #include "include/apparmor.h" 180ed3b28aSJohn Johansen #include "include/capability.h" 19d8889d49SJohn Johansen #include "include/cred.h" 200ed3b28aSJohn Johansen #include "include/policy.h" 210ed3b28aSJohn Johansen #include "include/audit.h" 220ed3b28aSJohn Johansen 230ed3b28aSJohn Johansen /* 240ed3b28aSJohn Johansen * Table of capability names: we generate it from capabilities.h. 250ed3b28aSJohn Johansen */ 260ed3b28aSJohn Johansen #include "capability_names.h" 270ed3b28aSJohn Johansen 28c97204baSJohn Johansen struct aa_sfs_entry aa_sfs_entry_caps[] = { 29c97204baSJohn Johansen AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK), 3084f1f787SJohn Johansen { } 3184f1f787SJohn Johansen }; 3284f1f787SJohn Johansen 330ed3b28aSJohn Johansen struct audit_cache { 340ed3b28aSJohn Johansen struct aa_profile *profile; 35*fee7a234SRyan Lee /* Capabilities go from 0 to CAP_LAST_CAP */ 36*fee7a234SRyan Lee u64 ktime_ns_expiration[CAP_LAST_CAP+1]; 370ed3b28aSJohn Johansen }; 380ed3b28aSJohn Johansen 390ed3b28aSJohn Johansen static DEFINE_PER_CPU(struct audit_cache, audit_cache); 400ed3b28aSJohn Johansen 410ed3b28aSJohn Johansen /** 420ed3b28aSJohn Johansen * audit_cb - call back for capability components of audit struct 43c98c8972SGaosheng Cui * @ab: audit buffer (NOT NULL) 44c98c8972SGaosheng Cui * @va: audit struct to audit data from (NOT NULL) 450ed3b28aSJohn Johansen */ 460ed3b28aSJohn Johansen static void audit_cb(struct audit_buffer *ab, void *va) 470ed3b28aSJohn Johansen { 480ed3b28aSJohn Johansen struct common_audit_data *sa = va; 49c70c86c4SJohn Johansen 500ed3b28aSJohn Johansen audit_log_format(ab, " capname="); 510ed3b28aSJohn Johansen audit_log_untrustedstring(ab, capability_names[sa->u.cap]); 520ed3b28aSJohn Johansen } 530ed3b28aSJohn Johansen 540ed3b28aSJohn Johansen /** 550ed3b28aSJohn Johansen * audit_caps - audit a capability 566a810513SYang Li * @ad: audit data 57dd0c6e86SJohn Johansen * @profile: profile being tested for confinement (NOT NULL) 580ed3b28aSJohn Johansen * @cap: capability tested 590ed3b28aSJohn Johansen * @error: error code returned by test 600ed3b28aSJohn Johansen * 610ed3b28aSJohn Johansen * Do auditing of capability and handle, audit/complain/kill modes switching 620ed3b28aSJohn Johansen * and duplicate message elimination. 630ed3b28aSJohn Johansen * 64bd7bd201SJohn Johansen * Returns: 0 or ad->error on success, error code on failure 650ed3b28aSJohn Johansen */ 66bd7bd201SJohn Johansen static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile, 67c70c86c4SJohn Johansen int cap, int error) 680ed3b28aSJohn Johansen { 69*fee7a234SRyan Lee const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */ 70*fee7a234SRyan Lee 711ad22fccSJohn Johansen struct aa_ruleset *rules = list_first_entry(&profile->rules, 721ad22fccSJohn Johansen typeof(*rules), list); 730ed3b28aSJohn Johansen struct audit_cache *ent; 740ed3b28aSJohn Johansen int type = AUDIT_APPARMOR_AUTO; 75c70c86c4SJohn Johansen 76bd7bd201SJohn Johansen ad->error = error; 770ed3b28aSJohn Johansen 780ed3b28aSJohn Johansen if (likely(!error)) { 790ed3b28aSJohn Johansen /* test if auditing is being forced */ 800ed3b28aSJohn Johansen if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && 81217af7e2SJohn Johansen !cap_raised(rules->caps.audit, cap))) 820ed3b28aSJohn Johansen return 0; 830ed3b28aSJohn Johansen type = AUDIT_APPARMOR_AUDIT; 840ed3b28aSJohn Johansen } else if (KILL_MODE(profile) || 85217af7e2SJohn Johansen cap_raised(rules->caps.kill, cap)) { 860ed3b28aSJohn Johansen type = AUDIT_APPARMOR_KILL; 87217af7e2SJohn Johansen } else if (cap_raised(rules->caps.quiet, cap) && 880ed3b28aSJohn Johansen AUDIT_MODE(profile) != AUDIT_NOQUIET && 890ed3b28aSJohn Johansen AUDIT_MODE(profile) != AUDIT_ALL) { 900ed3b28aSJohn Johansen /* quiet auditing */ 910ed3b28aSJohn Johansen return error; 920ed3b28aSJohn Johansen } 930ed3b28aSJohn Johansen 940ed3b28aSJohn Johansen /* Do simple duplicate message elimination */ 950ed3b28aSJohn Johansen ent = &get_cpu_var(audit_cache); 96*fee7a234SRyan Lee /* If the capability was never raised the timestamp check would also catch that */ 97*fee7a234SRyan Lee if (profile == ent->profile && ktime_get_ns() <= ent->ktime_ns_expiration[cap]) { 980ed3b28aSJohn Johansen put_cpu_var(audit_cache); 990ed3b28aSJohn Johansen if (COMPLAIN_MODE(profile)) 1000ed3b28aSJohn Johansen return complain_error(error); 1010ed3b28aSJohn Johansen return error; 1020ed3b28aSJohn Johansen } else { 1030ed3b28aSJohn Johansen aa_put_profile(ent->profile); 1049b897132Schao liu if (profile != ent->profile) 1059b897132Schao liu cap_clear(ent->caps); 1060ed3b28aSJohn Johansen ent->profile = aa_get_profile(profile); 107*fee7a234SRyan Lee ent->ktime_ns_expiration[cap] = ktime_get_ns() + AUDIT_CACHE_TIMEOUT_NS; 1080ed3b28aSJohn Johansen } 1090ed3b28aSJohn Johansen put_cpu_var(audit_cache); 1100ed3b28aSJohn Johansen 111bd7bd201SJohn Johansen return aa_audit(type, profile, ad, audit_cb); 1120ed3b28aSJohn Johansen } 1130ed3b28aSJohn Johansen 1140ed3b28aSJohn Johansen /** 1150ed3b28aSJohn Johansen * profile_capable - test if profile allows use of capability @cap 1160ed3b28aSJohn Johansen * @profile: profile being enforced (NOT NULL, NOT unconfined) 1170ed3b28aSJohn Johansen * @cap: capability to test if allowed 118c1a85a00SMicah Morton * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 1198532503eSRyan Lee * @ad: audit data (NOT NULL) 1200ed3b28aSJohn Johansen * 1210ed3b28aSJohn Johansen * Returns: 0 if allowed else -EPERM 1220ed3b28aSJohn Johansen */ 123c1a85a00SMicah Morton static int profile_capable(struct aa_profile *profile, int cap, 124bd7bd201SJohn Johansen unsigned int opts, struct apparmor_audit_data *ad) 1250ed3b28aSJohn Johansen { 1261ad22fccSJohn Johansen struct aa_ruleset *rules = list_first_entry(&profile->rules, 1271ad22fccSJohn Johansen typeof(*rules), list); 128c70c86c4SJohn Johansen int error; 129c70c86c4SJohn Johansen 130217af7e2SJohn Johansen if (cap_raised(rules->caps.allow, cap) && 131217af7e2SJohn Johansen !cap_raised(rules->caps.denied, cap)) 132c70c86c4SJohn Johansen error = 0; 133c70c86c4SJohn Johansen else 134c70c86c4SJohn Johansen error = -EPERM; 135c70c86c4SJohn Johansen 136c1a85a00SMicah Morton if (opts & CAP_OPT_NOAUDIT) { 137c70c86c4SJohn Johansen if (!COMPLAIN_MODE(profile)) 138c70c86c4SJohn Johansen return error; 139c70c86c4SJohn Johansen /* audit the cap request in complain mode but note that it 140c70c86c4SJohn Johansen * should be optional. 141c70c86c4SJohn Johansen */ 142bd7bd201SJohn Johansen ad->info = "optional: no audit"; 143c70c86c4SJohn Johansen } 144c70c86c4SJohn Johansen 145bd7bd201SJohn Johansen return audit_caps(ad, profile, cap, error); 1460ed3b28aSJohn Johansen } 1470ed3b28aSJohn Johansen 1480ed3b28aSJohn Johansen /** 1490ed3b28aSJohn Johansen * aa_capable - test permission to use capability 1506a810513SYang Li * @subj_cred: cred we are testing capability against 151c70c86c4SJohn Johansen * @label: label being tested for capability (NOT NULL) 1520ed3b28aSJohn Johansen * @cap: capability to be tested 153c1a85a00SMicah Morton * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 1540ed3b28aSJohn Johansen * 1550ed3b28aSJohn Johansen * Look up capability in profile capability set. 1560ed3b28aSJohn Johansen * 1570ed3b28aSJohn Johansen * Returns: 0 on success, or else an error code. 1580ed3b28aSJohn Johansen */ 15990c436a6SJohn Johansen int aa_capable(const struct cred *subj_cred, struct aa_label *label, 16090c436a6SJohn Johansen int cap, unsigned int opts) 1610ed3b28aSJohn Johansen { 162c70c86c4SJohn Johansen struct aa_profile *profile; 163c70c86c4SJohn Johansen int error = 0; 164bd7bd201SJohn Johansen DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_CAP, AA_CLASS_CAP, OP_CAPABLE); 1650ed3b28aSJohn Johansen 16690c436a6SJohn Johansen ad.subj_cred = subj_cred; 167bd7bd201SJohn Johansen ad.common.u.cap = cap; 168c70c86c4SJohn Johansen error = fn_for_each_confined(label, profile, 169bd7bd201SJohn Johansen profile_capable(profile, cap, opts, &ad)); 170c70c86c4SJohn Johansen 1710ed3b28aSJohn Johansen return error; 1720ed3b28aSJohn Johansen } 173