18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor capability mediation functions 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 88c2ecf20Sopenharmony_ci * Copyright 2009-2010 Canonical Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/capability.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/gfp.h> 148c2ecf20Sopenharmony_ci#include <linux/security.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "include/apparmor.h" 178c2ecf20Sopenharmony_ci#include "include/capability.h" 188c2ecf20Sopenharmony_ci#include "include/cred.h" 198c2ecf20Sopenharmony_ci#include "include/policy.h" 208c2ecf20Sopenharmony_ci#include "include/audit.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Table of capability names: we generate it from capabilities.h. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci#include "capability_names.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct aa_sfs_entry aa_sfs_entry_caps[] = { 288c2ecf20Sopenharmony_ci AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK), 298c2ecf20Sopenharmony_ci { } 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct audit_cache { 338c2ecf20Sopenharmony_ci struct aa_profile *profile; 348c2ecf20Sopenharmony_ci kernel_cap_t caps; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct audit_cache, audit_cache); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * audit_cb - call back for capability components of audit struct 418c2ecf20Sopenharmony_ci * @ab - audit buffer (NOT NULL) 428c2ecf20Sopenharmony_ci * @va - audit struct to audit data from (NOT NULL) 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cistatic void audit_cb(struct audit_buffer *ab, void *va) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct common_audit_data *sa = va; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci audit_log_format(ab, " capname="); 498c2ecf20Sopenharmony_ci audit_log_untrustedstring(ab, capability_names[sa->u.cap]); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * audit_caps - audit a capability 548c2ecf20Sopenharmony_ci * @sa: audit data 558c2ecf20Sopenharmony_ci * @profile: profile being tested for confinement (NOT NULL) 568c2ecf20Sopenharmony_ci * @cap: capability tested 578c2ecf20Sopenharmony_ci * @error: error code returned by test 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Do auditing of capability and handle, audit/complain/kill modes switching 608c2ecf20Sopenharmony_ci * and duplicate message elimination. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Returns: 0 or sa->error on success, error code on failure 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, 658c2ecf20Sopenharmony_ci int cap, int error) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct audit_cache *ent; 688c2ecf20Sopenharmony_ci int type = AUDIT_APPARMOR_AUTO; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci aad(sa)->error = error; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (likely(!error)) { 738c2ecf20Sopenharmony_ci /* test if auditing is being forced */ 748c2ecf20Sopenharmony_ci if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && 758c2ecf20Sopenharmony_ci !cap_raised(profile->caps.audit, cap))) 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci type = AUDIT_APPARMOR_AUDIT; 788c2ecf20Sopenharmony_ci } else if (KILL_MODE(profile) || 798c2ecf20Sopenharmony_ci cap_raised(profile->caps.kill, cap)) { 808c2ecf20Sopenharmony_ci type = AUDIT_APPARMOR_KILL; 818c2ecf20Sopenharmony_ci } else if (cap_raised(profile->caps.quiet, cap) && 828c2ecf20Sopenharmony_ci AUDIT_MODE(profile) != AUDIT_NOQUIET && 838c2ecf20Sopenharmony_ci AUDIT_MODE(profile) != AUDIT_ALL) { 848c2ecf20Sopenharmony_ci /* quiet auditing */ 858c2ecf20Sopenharmony_ci return error; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Do simple duplicate message elimination */ 898c2ecf20Sopenharmony_ci ent = &get_cpu_var(audit_cache); 908c2ecf20Sopenharmony_ci if (profile == ent->profile && cap_raised(ent->caps, cap)) { 918c2ecf20Sopenharmony_ci put_cpu_var(audit_cache); 928c2ecf20Sopenharmony_ci if (COMPLAIN_MODE(profile)) 938c2ecf20Sopenharmony_ci return complain_error(error); 948c2ecf20Sopenharmony_ci return error; 958c2ecf20Sopenharmony_ci } else { 968c2ecf20Sopenharmony_ci aa_put_profile(ent->profile); 978c2ecf20Sopenharmony_ci ent->profile = aa_get_profile(profile); 988c2ecf20Sopenharmony_ci cap_raise(ent->caps, cap); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci put_cpu_var(audit_cache); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return aa_audit(type, profile, sa, audit_cb); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/** 1068c2ecf20Sopenharmony_ci * profile_capable - test if profile allows use of capability @cap 1078c2ecf20Sopenharmony_ci * @profile: profile being enforced (NOT NULL, NOT unconfined) 1088c2ecf20Sopenharmony_ci * @cap: capability to test if allowed 1098c2ecf20Sopenharmony_ci * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 1108c2ecf20Sopenharmony_ci * @sa: audit data (MAY BE NULL indicating no auditing) 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Returns: 0 if allowed else -EPERM 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic int profile_capable(struct aa_profile *profile, int cap, 1158c2ecf20Sopenharmony_ci unsigned int opts, struct common_audit_data *sa) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci int error; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (cap_raised(profile->caps.allow, cap) && 1208c2ecf20Sopenharmony_ci !cap_raised(profile->caps.denied, cap)) 1218c2ecf20Sopenharmony_ci error = 0; 1228c2ecf20Sopenharmony_ci else 1238c2ecf20Sopenharmony_ci error = -EPERM; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (opts & CAP_OPT_NOAUDIT) { 1268c2ecf20Sopenharmony_ci if (!COMPLAIN_MODE(profile)) 1278c2ecf20Sopenharmony_ci return error; 1288c2ecf20Sopenharmony_ci /* audit the cap request in complain mode but note that it 1298c2ecf20Sopenharmony_ci * should be optional. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci aad(sa)->info = "optional: no audit"; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return audit_caps(sa, profile, cap, error); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/** 1388c2ecf20Sopenharmony_ci * aa_capable - test permission to use capability 1398c2ecf20Sopenharmony_ci * @label: label being tested for capability (NOT NULL) 1408c2ecf20Sopenharmony_ci * @cap: capability to be tested 1418c2ecf20Sopenharmony_ci * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * Look up capability in profile capability set. 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Returns: 0 on success, or else an error code. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ciint aa_capable(struct aa_label *label, int cap, unsigned int opts) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct aa_profile *profile; 1508c2ecf20Sopenharmony_ci int error = 0; 1518c2ecf20Sopenharmony_ci DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci sa.u.cap = cap; 1548c2ecf20Sopenharmony_ci error = fn_for_each_confined(label, profile, 1558c2ecf20Sopenharmony_ci profile_capable(profile, cap, opts, &sa)); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return error; 1588c2ecf20Sopenharmony_ci} 159