1*b886d83cSThomas 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> 150ed3b28aSJohn Johansen 160ed3b28aSJohn Johansen #include "include/apparmor.h" 170ed3b28aSJohn Johansen #include "include/capability.h" 18d8889d49SJohn Johansen #include "include/cred.h" 190ed3b28aSJohn Johansen #include "include/policy.h" 200ed3b28aSJohn Johansen #include "include/audit.h" 210ed3b28aSJohn Johansen 220ed3b28aSJohn Johansen /* 230ed3b28aSJohn Johansen * Table of capability names: we generate it from capabilities.h. 240ed3b28aSJohn Johansen */ 250ed3b28aSJohn Johansen #include "capability_names.h" 260ed3b28aSJohn Johansen 27c97204baSJohn Johansen struct aa_sfs_entry aa_sfs_entry_caps[] = { 28c97204baSJohn Johansen AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK), 2984f1f787SJohn Johansen { } 3084f1f787SJohn Johansen }; 3184f1f787SJohn Johansen 320ed3b28aSJohn Johansen struct audit_cache { 330ed3b28aSJohn Johansen struct aa_profile *profile; 340ed3b28aSJohn Johansen kernel_cap_t caps; 350ed3b28aSJohn Johansen }; 360ed3b28aSJohn Johansen 370ed3b28aSJohn Johansen static DEFINE_PER_CPU(struct audit_cache, audit_cache); 380ed3b28aSJohn Johansen 390ed3b28aSJohn Johansen /** 400ed3b28aSJohn Johansen * audit_cb - call back for capability components of audit struct 410ed3b28aSJohn Johansen * @ab - audit buffer (NOT NULL) 420ed3b28aSJohn Johansen * @va - audit struct to audit data from (NOT NULL) 430ed3b28aSJohn Johansen */ 440ed3b28aSJohn Johansen static void audit_cb(struct audit_buffer *ab, void *va) 450ed3b28aSJohn Johansen { 460ed3b28aSJohn Johansen struct common_audit_data *sa = va; 47c70c86c4SJohn Johansen 480ed3b28aSJohn Johansen audit_log_format(ab, " capname="); 490ed3b28aSJohn Johansen audit_log_untrustedstring(ab, capability_names[sa->u.cap]); 500ed3b28aSJohn Johansen } 510ed3b28aSJohn Johansen 520ed3b28aSJohn Johansen /** 530ed3b28aSJohn Johansen * audit_caps - audit a capability 54c70c86c4SJohn Johansen * @sa: audit data 55dd0c6e86SJohn Johansen * @profile: profile being tested for confinement (NOT NULL) 560ed3b28aSJohn Johansen * @cap: capability tested 570ed3b28aSJohn Johansen * @error: error code returned by test 580ed3b28aSJohn Johansen * 590ed3b28aSJohn Johansen * Do auditing of capability and handle, audit/complain/kill modes switching 600ed3b28aSJohn Johansen * and duplicate message elimination. 610ed3b28aSJohn Johansen * 620ed3b28aSJohn Johansen * Returns: 0 or sa->error on success, error code on failure 630ed3b28aSJohn Johansen */ 64c70c86c4SJohn Johansen static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, 65c70c86c4SJohn Johansen int cap, int error) 660ed3b28aSJohn Johansen { 670ed3b28aSJohn Johansen struct audit_cache *ent; 680ed3b28aSJohn Johansen int type = AUDIT_APPARMOR_AUTO; 69c70c86c4SJohn Johansen 70c70c86c4SJohn Johansen aad(sa)->error = error; 710ed3b28aSJohn Johansen 720ed3b28aSJohn Johansen if (likely(!error)) { 730ed3b28aSJohn Johansen /* test if auditing is being forced */ 740ed3b28aSJohn Johansen if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && 750ed3b28aSJohn Johansen !cap_raised(profile->caps.audit, cap))) 760ed3b28aSJohn Johansen return 0; 770ed3b28aSJohn Johansen type = AUDIT_APPARMOR_AUDIT; 780ed3b28aSJohn Johansen } else if (KILL_MODE(profile) || 790ed3b28aSJohn Johansen cap_raised(profile->caps.kill, cap)) { 800ed3b28aSJohn Johansen type = AUDIT_APPARMOR_KILL; 810ed3b28aSJohn Johansen } else if (cap_raised(profile->caps.quiet, cap) && 820ed3b28aSJohn Johansen AUDIT_MODE(profile) != AUDIT_NOQUIET && 830ed3b28aSJohn Johansen AUDIT_MODE(profile) != AUDIT_ALL) { 840ed3b28aSJohn Johansen /* quiet auditing */ 850ed3b28aSJohn Johansen return error; 860ed3b28aSJohn Johansen } 870ed3b28aSJohn Johansen 880ed3b28aSJohn Johansen /* Do simple duplicate message elimination */ 890ed3b28aSJohn Johansen ent = &get_cpu_var(audit_cache); 900ed3b28aSJohn Johansen if (profile == ent->profile && cap_raised(ent->caps, cap)) { 910ed3b28aSJohn Johansen put_cpu_var(audit_cache); 920ed3b28aSJohn Johansen if (COMPLAIN_MODE(profile)) 930ed3b28aSJohn Johansen return complain_error(error); 940ed3b28aSJohn Johansen return error; 950ed3b28aSJohn Johansen } else { 960ed3b28aSJohn Johansen aa_put_profile(ent->profile); 970ed3b28aSJohn Johansen ent->profile = aa_get_profile(profile); 980ed3b28aSJohn Johansen cap_raise(ent->caps, cap); 990ed3b28aSJohn Johansen } 1000ed3b28aSJohn Johansen put_cpu_var(audit_cache); 1010ed3b28aSJohn Johansen 102c70c86c4SJohn Johansen return aa_audit(type, profile, sa, audit_cb); 1030ed3b28aSJohn Johansen } 1040ed3b28aSJohn Johansen 1050ed3b28aSJohn Johansen /** 1060ed3b28aSJohn Johansen * profile_capable - test if profile allows use of capability @cap 1070ed3b28aSJohn Johansen * @profile: profile being enforced (NOT NULL, NOT unconfined) 1080ed3b28aSJohn Johansen * @cap: capability to test if allowed 109c1a85a00SMicah Morton * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 110c70c86c4SJohn Johansen * @sa: audit data (MAY BE NULL indicating no auditing) 1110ed3b28aSJohn Johansen * 1120ed3b28aSJohn Johansen * Returns: 0 if allowed else -EPERM 1130ed3b28aSJohn Johansen */ 114c1a85a00SMicah Morton static int profile_capable(struct aa_profile *profile, int cap, 115c1a85a00SMicah Morton unsigned int opts, struct common_audit_data *sa) 1160ed3b28aSJohn Johansen { 117c70c86c4SJohn Johansen int error; 118c70c86c4SJohn Johansen 119c70c86c4SJohn Johansen if (cap_raised(profile->caps.allow, cap) && 120c70c86c4SJohn Johansen !cap_raised(profile->caps.denied, cap)) 121c70c86c4SJohn Johansen error = 0; 122c70c86c4SJohn Johansen else 123c70c86c4SJohn Johansen error = -EPERM; 124c70c86c4SJohn Johansen 125c1a85a00SMicah Morton if (opts & CAP_OPT_NOAUDIT) { 126c70c86c4SJohn Johansen if (!COMPLAIN_MODE(profile)) 127c70c86c4SJohn Johansen return error; 128c70c86c4SJohn Johansen /* audit the cap request in complain mode but note that it 129c70c86c4SJohn Johansen * should be optional. 130c70c86c4SJohn Johansen */ 131c70c86c4SJohn Johansen aad(sa)->info = "optional: no audit"; 132c70c86c4SJohn Johansen } 133c70c86c4SJohn Johansen 134c70c86c4SJohn Johansen return audit_caps(sa, profile, cap, error); 1350ed3b28aSJohn Johansen } 1360ed3b28aSJohn Johansen 1370ed3b28aSJohn Johansen /** 1380ed3b28aSJohn Johansen * aa_capable - test permission to use capability 139c70c86c4SJohn Johansen * @label: label being tested for capability (NOT NULL) 1400ed3b28aSJohn Johansen * @cap: capability to be tested 141c1a85a00SMicah Morton * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 1420ed3b28aSJohn Johansen * 1430ed3b28aSJohn Johansen * Look up capability in profile capability set. 1440ed3b28aSJohn Johansen * 1450ed3b28aSJohn Johansen * Returns: 0 on success, or else an error code. 1460ed3b28aSJohn Johansen */ 147c1a85a00SMicah Morton int aa_capable(struct aa_label *label, int cap, unsigned int opts) 1480ed3b28aSJohn Johansen { 149c70c86c4SJohn Johansen struct aa_profile *profile; 150c70c86c4SJohn Johansen int error = 0; 151c70c86c4SJohn Johansen DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); 1520ed3b28aSJohn Johansen 153c70c86c4SJohn Johansen sa.u.cap = cap; 154c70c86c4SJohn Johansen error = fn_for_each_confined(label, profile, 155c1a85a00SMicah Morton profile_capable(profile, cap, opts, &sa)); 156c70c86c4SJohn Johansen 1570ed3b28aSJohn Johansen return error; 1580ed3b28aSJohn Johansen } 159