xref: /linux-6.15/security/apparmor/capability.c (revision 0ed3b28a)
1*0ed3b28aSJohn Johansen /*
2*0ed3b28aSJohn Johansen  * AppArmor security module
3*0ed3b28aSJohn Johansen  *
4*0ed3b28aSJohn Johansen  * This file contains AppArmor capability mediation functions
5*0ed3b28aSJohn Johansen  *
6*0ed3b28aSJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
7*0ed3b28aSJohn Johansen  * Copyright 2009-2010 Canonical Ltd.
8*0ed3b28aSJohn Johansen  *
9*0ed3b28aSJohn Johansen  * This program is free software; you can redistribute it and/or
10*0ed3b28aSJohn Johansen  * modify it under the terms of the GNU General Public License as
11*0ed3b28aSJohn Johansen  * published by the Free Software Foundation, version 2 of the
12*0ed3b28aSJohn Johansen  * License.
13*0ed3b28aSJohn Johansen  */
14*0ed3b28aSJohn Johansen 
15*0ed3b28aSJohn Johansen #include <linux/capability.h>
16*0ed3b28aSJohn Johansen #include <linux/errno.h>
17*0ed3b28aSJohn Johansen #include <linux/gfp.h>
18*0ed3b28aSJohn Johansen 
19*0ed3b28aSJohn Johansen #include "include/apparmor.h"
20*0ed3b28aSJohn Johansen #include "include/capability.h"
21*0ed3b28aSJohn Johansen #include "include/context.h"
22*0ed3b28aSJohn Johansen #include "include/policy.h"
23*0ed3b28aSJohn Johansen #include "include/audit.h"
24*0ed3b28aSJohn Johansen 
25*0ed3b28aSJohn Johansen /*
26*0ed3b28aSJohn Johansen  * Table of capability names: we generate it from capabilities.h.
27*0ed3b28aSJohn Johansen  */
28*0ed3b28aSJohn Johansen #include "capability_names.h"
29*0ed3b28aSJohn Johansen 
30*0ed3b28aSJohn Johansen struct audit_cache {
31*0ed3b28aSJohn Johansen 	struct aa_profile *profile;
32*0ed3b28aSJohn Johansen 	kernel_cap_t caps;
33*0ed3b28aSJohn Johansen };
34*0ed3b28aSJohn Johansen 
35*0ed3b28aSJohn Johansen static DEFINE_PER_CPU(struct audit_cache, audit_cache);
36*0ed3b28aSJohn Johansen 
37*0ed3b28aSJohn Johansen /**
38*0ed3b28aSJohn Johansen  * audit_cb - call back for capability components of audit struct
39*0ed3b28aSJohn Johansen  * @ab - audit buffer   (NOT NULL)
40*0ed3b28aSJohn Johansen  * @va - audit struct to audit data from  (NOT NULL)
41*0ed3b28aSJohn Johansen  */
42*0ed3b28aSJohn Johansen static void audit_cb(struct audit_buffer *ab, void *va)
43*0ed3b28aSJohn Johansen {
44*0ed3b28aSJohn Johansen 	struct common_audit_data *sa = va;
45*0ed3b28aSJohn Johansen 	audit_log_format(ab, " capname=");
46*0ed3b28aSJohn Johansen 	audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
47*0ed3b28aSJohn Johansen }
48*0ed3b28aSJohn Johansen 
49*0ed3b28aSJohn Johansen /**
50*0ed3b28aSJohn Johansen  * audit_caps - audit a capability
51*0ed3b28aSJohn Johansen  * @profile: profile confining task (NOT NULL)
52*0ed3b28aSJohn Johansen  * @task: task capability test was performed against (NOT NULL)
53*0ed3b28aSJohn Johansen  * @cap: capability tested
54*0ed3b28aSJohn Johansen  * @error: error code returned by test
55*0ed3b28aSJohn Johansen  *
56*0ed3b28aSJohn Johansen  * Do auditing of capability and handle, audit/complain/kill modes switching
57*0ed3b28aSJohn Johansen  * and duplicate message elimination.
58*0ed3b28aSJohn Johansen  *
59*0ed3b28aSJohn Johansen  * Returns: 0 or sa->error on success,  error code on failure
60*0ed3b28aSJohn Johansen  */
61*0ed3b28aSJohn Johansen static int audit_caps(struct aa_profile *profile, struct task_struct *task,
62*0ed3b28aSJohn Johansen 		      int cap, int error)
63*0ed3b28aSJohn Johansen {
64*0ed3b28aSJohn Johansen 	struct audit_cache *ent;
65*0ed3b28aSJohn Johansen 	int type = AUDIT_APPARMOR_AUTO;
66*0ed3b28aSJohn Johansen 	struct common_audit_data sa;
67*0ed3b28aSJohn Johansen 	COMMON_AUDIT_DATA_INIT(&sa, CAP);
68*0ed3b28aSJohn Johansen 	sa.tsk = task;
69*0ed3b28aSJohn Johansen 	sa.u.cap = cap;
70*0ed3b28aSJohn Johansen 	sa.aad.op = OP_CAPABLE;
71*0ed3b28aSJohn Johansen 	sa.aad.error = error;
72*0ed3b28aSJohn Johansen 
73*0ed3b28aSJohn Johansen 	if (likely(!error)) {
74*0ed3b28aSJohn Johansen 		/* test if auditing is being forced */
75*0ed3b28aSJohn Johansen 		if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
76*0ed3b28aSJohn Johansen 			   !cap_raised(profile->caps.audit, cap)))
77*0ed3b28aSJohn Johansen 			return 0;
78*0ed3b28aSJohn Johansen 		type = AUDIT_APPARMOR_AUDIT;
79*0ed3b28aSJohn Johansen 	} else if (KILL_MODE(profile) ||
80*0ed3b28aSJohn Johansen 		   cap_raised(profile->caps.kill, cap)) {
81*0ed3b28aSJohn Johansen 		type = AUDIT_APPARMOR_KILL;
82*0ed3b28aSJohn Johansen 	} else if (cap_raised(profile->caps.quiet, cap) &&
83*0ed3b28aSJohn Johansen 		   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
84*0ed3b28aSJohn Johansen 		   AUDIT_MODE(profile) != AUDIT_ALL) {
85*0ed3b28aSJohn Johansen 		/* quiet auditing */
86*0ed3b28aSJohn Johansen 		return error;
87*0ed3b28aSJohn Johansen 	}
88*0ed3b28aSJohn Johansen 
89*0ed3b28aSJohn Johansen 	/* Do simple duplicate message elimination */
90*0ed3b28aSJohn Johansen 	ent = &get_cpu_var(audit_cache);
91*0ed3b28aSJohn Johansen 	if (profile == ent->profile && cap_raised(ent->caps, cap)) {
92*0ed3b28aSJohn Johansen 		put_cpu_var(audit_cache);
93*0ed3b28aSJohn Johansen 		if (COMPLAIN_MODE(profile))
94*0ed3b28aSJohn Johansen 			return complain_error(error);
95*0ed3b28aSJohn Johansen 		return error;
96*0ed3b28aSJohn Johansen 	} else {
97*0ed3b28aSJohn Johansen 		aa_put_profile(ent->profile);
98*0ed3b28aSJohn Johansen 		ent->profile = aa_get_profile(profile);
99*0ed3b28aSJohn Johansen 		cap_raise(ent->caps, cap);
100*0ed3b28aSJohn Johansen 	}
101*0ed3b28aSJohn Johansen 	put_cpu_var(audit_cache);
102*0ed3b28aSJohn Johansen 
103*0ed3b28aSJohn Johansen 	return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
104*0ed3b28aSJohn Johansen }
105*0ed3b28aSJohn Johansen 
106*0ed3b28aSJohn Johansen /**
107*0ed3b28aSJohn Johansen  * profile_capable - test if profile allows use of capability @cap
108*0ed3b28aSJohn Johansen  * @profile: profile being enforced    (NOT NULL, NOT unconfined)
109*0ed3b28aSJohn Johansen  * @cap: capability to test if allowed
110*0ed3b28aSJohn Johansen  *
111*0ed3b28aSJohn Johansen  * Returns: 0 if allowed else -EPERM
112*0ed3b28aSJohn Johansen  */
113*0ed3b28aSJohn Johansen static int profile_capable(struct aa_profile *profile, int cap)
114*0ed3b28aSJohn Johansen {
115*0ed3b28aSJohn Johansen 	return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
116*0ed3b28aSJohn Johansen }
117*0ed3b28aSJohn Johansen 
118*0ed3b28aSJohn Johansen /**
119*0ed3b28aSJohn Johansen  * aa_capable - test permission to use capability
120*0ed3b28aSJohn Johansen  * @task: task doing capability test against (NOT NULL)
121*0ed3b28aSJohn Johansen  * @profile: profile confining @task (NOT NULL)
122*0ed3b28aSJohn Johansen  * @cap: capability to be tested
123*0ed3b28aSJohn Johansen  * @audit: whether an audit record should be generated
124*0ed3b28aSJohn Johansen  *
125*0ed3b28aSJohn Johansen  * Look up capability in profile capability set.
126*0ed3b28aSJohn Johansen  *
127*0ed3b28aSJohn Johansen  * Returns: 0 on success, or else an error code.
128*0ed3b28aSJohn Johansen  */
129*0ed3b28aSJohn Johansen int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
130*0ed3b28aSJohn Johansen 	       int audit)
131*0ed3b28aSJohn Johansen {
132*0ed3b28aSJohn Johansen 	int error = profile_capable(profile, cap);
133*0ed3b28aSJohn Johansen 
134*0ed3b28aSJohn Johansen 	if (!audit) {
135*0ed3b28aSJohn Johansen 		if (COMPLAIN_MODE(profile))
136*0ed3b28aSJohn Johansen 			return complain_error(error);
137*0ed3b28aSJohn Johansen 		return error;
138*0ed3b28aSJohn Johansen 	}
139*0ed3b28aSJohn Johansen 
140*0ed3b28aSJohn Johansen 	return audit_caps(profile, task, cap, error);
141*0ed3b28aSJohn Johansen }
142