10ed3b28aSJohn Johansen /* 20ed3b28aSJohn Johansen * AppArmor security module 30ed3b28aSJohn Johansen * 40ed3b28aSJohn Johansen * This file contains AppArmor capability mediation functions 50ed3b28aSJohn Johansen * 60ed3b28aSJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 70ed3b28aSJohn Johansen * Copyright 2009-2010 Canonical Ltd. 80ed3b28aSJohn Johansen * 90ed3b28aSJohn Johansen * This program is free software; you can redistribute it and/or 100ed3b28aSJohn Johansen * modify it under the terms of the GNU General Public License as 110ed3b28aSJohn Johansen * published by the Free Software Foundation, version 2 of the 120ed3b28aSJohn Johansen * License. 130ed3b28aSJohn Johansen */ 140ed3b28aSJohn Johansen 150ed3b28aSJohn Johansen #include <linux/capability.h> 160ed3b28aSJohn Johansen #include <linux/errno.h> 170ed3b28aSJohn Johansen #include <linux/gfp.h> 180ed3b28aSJohn Johansen 190ed3b28aSJohn Johansen #include "include/apparmor.h" 200ed3b28aSJohn Johansen #include "include/capability.h" 210ed3b28aSJohn Johansen #include "include/context.h" 220ed3b28aSJohn Johansen #include "include/policy.h" 230ed3b28aSJohn Johansen #include "include/audit.h" 240ed3b28aSJohn Johansen 250ed3b28aSJohn Johansen /* 260ed3b28aSJohn Johansen * Table of capability names: we generate it from capabilities.h. 270ed3b28aSJohn Johansen */ 280ed3b28aSJohn Johansen #include "capability_names.h" 290ed3b28aSJohn Johansen 30*84f1f787SJohn Johansen struct aa_fs_entry aa_fs_entry_caps[] = { 31*84f1f787SJohn Johansen AA_FS_FILE_STRING("mask", AA_FS_CAPS_MASK), 32*84f1f787SJohn Johansen { } 33*84f1f787SJohn Johansen }; 34*84f1f787SJohn Johansen 350ed3b28aSJohn Johansen struct audit_cache { 360ed3b28aSJohn Johansen struct aa_profile *profile; 370ed3b28aSJohn Johansen kernel_cap_t caps; 380ed3b28aSJohn Johansen }; 390ed3b28aSJohn Johansen 400ed3b28aSJohn Johansen static DEFINE_PER_CPU(struct audit_cache, audit_cache); 410ed3b28aSJohn Johansen 420ed3b28aSJohn Johansen /** 430ed3b28aSJohn Johansen * audit_cb - call back for capability components of audit struct 440ed3b28aSJohn Johansen * @ab - audit buffer (NOT NULL) 450ed3b28aSJohn Johansen * @va - audit struct to audit data from (NOT NULL) 460ed3b28aSJohn Johansen */ 470ed3b28aSJohn Johansen static void audit_cb(struct audit_buffer *ab, void *va) 480ed3b28aSJohn Johansen { 490ed3b28aSJohn Johansen struct common_audit_data *sa = va; 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 560ed3b28aSJohn Johansen * @profile: profile confining task (NOT NULL) 570ed3b28aSJohn Johansen * @task: task capability test was performed against (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 * 640ed3b28aSJohn Johansen * Returns: 0 or sa->error on success, error code on failure 650ed3b28aSJohn Johansen */ 660ed3b28aSJohn Johansen static int audit_caps(struct aa_profile *profile, struct task_struct *task, 670ed3b28aSJohn Johansen int cap, int error) 680ed3b28aSJohn Johansen { 690ed3b28aSJohn Johansen struct audit_cache *ent; 700ed3b28aSJohn Johansen int type = AUDIT_APPARMOR_AUTO; 710ed3b28aSJohn Johansen struct common_audit_data sa; 723b3b0e4fSEric Paris struct apparmor_audit_data aad = {0,}; 7350c205f5SEric Paris sa.type = LSM_AUDIT_DATA_CAP; 743b3b0e4fSEric Paris sa.aad = &aad; 750ed3b28aSJohn Johansen sa.u.cap = cap; 760972c74eSEric Paris sa.aad->tsk = task; 773b3b0e4fSEric Paris sa.aad->op = OP_CAPABLE; 783b3b0e4fSEric Paris sa.aad->error = error; 790ed3b28aSJohn Johansen 800ed3b28aSJohn Johansen if (likely(!error)) { 810ed3b28aSJohn Johansen /* test if auditing is being forced */ 820ed3b28aSJohn Johansen if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && 830ed3b28aSJohn Johansen !cap_raised(profile->caps.audit, cap))) 840ed3b28aSJohn Johansen return 0; 850ed3b28aSJohn Johansen type = AUDIT_APPARMOR_AUDIT; 860ed3b28aSJohn Johansen } else if (KILL_MODE(profile) || 870ed3b28aSJohn Johansen cap_raised(profile->caps.kill, cap)) { 880ed3b28aSJohn Johansen type = AUDIT_APPARMOR_KILL; 890ed3b28aSJohn Johansen } else if (cap_raised(profile->caps.quiet, cap) && 900ed3b28aSJohn Johansen AUDIT_MODE(profile) != AUDIT_NOQUIET && 910ed3b28aSJohn Johansen AUDIT_MODE(profile) != AUDIT_ALL) { 920ed3b28aSJohn Johansen /* quiet auditing */ 930ed3b28aSJohn Johansen return error; 940ed3b28aSJohn Johansen } 950ed3b28aSJohn Johansen 960ed3b28aSJohn Johansen /* Do simple duplicate message elimination */ 970ed3b28aSJohn Johansen ent = &get_cpu_var(audit_cache); 980ed3b28aSJohn Johansen if (profile == ent->profile && cap_raised(ent->caps, cap)) { 990ed3b28aSJohn Johansen put_cpu_var(audit_cache); 1000ed3b28aSJohn Johansen if (COMPLAIN_MODE(profile)) 1010ed3b28aSJohn Johansen return complain_error(error); 1020ed3b28aSJohn Johansen return error; 1030ed3b28aSJohn Johansen } else { 1040ed3b28aSJohn Johansen aa_put_profile(ent->profile); 1050ed3b28aSJohn Johansen ent->profile = aa_get_profile(profile); 1060ed3b28aSJohn Johansen cap_raise(ent->caps, cap); 1070ed3b28aSJohn Johansen } 1080ed3b28aSJohn Johansen put_cpu_var(audit_cache); 1090ed3b28aSJohn Johansen 1100ed3b28aSJohn Johansen return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb); 1110ed3b28aSJohn Johansen } 1120ed3b28aSJohn Johansen 1130ed3b28aSJohn Johansen /** 1140ed3b28aSJohn Johansen * profile_capable - test if profile allows use of capability @cap 1150ed3b28aSJohn Johansen * @profile: profile being enforced (NOT NULL, NOT unconfined) 1160ed3b28aSJohn Johansen * @cap: capability to test if allowed 1170ed3b28aSJohn Johansen * 1180ed3b28aSJohn Johansen * Returns: 0 if allowed else -EPERM 1190ed3b28aSJohn Johansen */ 1200ed3b28aSJohn Johansen static int profile_capable(struct aa_profile *profile, int cap) 1210ed3b28aSJohn Johansen { 1220ed3b28aSJohn Johansen return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM; 1230ed3b28aSJohn Johansen } 1240ed3b28aSJohn Johansen 1250ed3b28aSJohn Johansen /** 1260ed3b28aSJohn Johansen * aa_capable - test permission to use capability 1270ed3b28aSJohn Johansen * @task: task doing capability test against (NOT NULL) 1280ed3b28aSJohn Johansen * @profile: profile confining @task (NOT NULL) 1290ed3b28aSJohn Johansen * @cap: capability to be tested 1300ed3b28aSJohn Johansen * @audit: whether an audit record should be generated 1310ed3b28aSJohn Johansen * 1320ed3b28aSJohn Johansen * Look up capability in profile capability set. 1330ed3b28aSJohn Johansen * 1340ed3b28aSJohn Johansen * Returns: 0 on success, or else an error code. 1350ed3b28aSJohn Johansen */ 1360ed3b28aSJohn Johansen int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap, 1370ed3b28aSJohn Johansen int audit) 1380ed3b28aSJohn Johansen { 1390ed3b28aSJohn Johansen int error = profile_capable(profile, cap); 1400ed3b28aSJohn Johansen 1410ed3b28aSJohn Johansen if (!audit) { 1420ed3b28aSJohn Johansen if (COMPLAIN_MODE(profile)) 1430ed3b28aSJohn Johansen return complain_error(error); 1440ed3b28aSJohn Johansen return error; 1450ed3b28aSJohn Johansen } 1460ed3b28aSJohn Johansen 1470ed3b28aSJohn Johansen return audit_caps(profile, task, cap, error); 1480ed3b28aSJohn Johansen } 149