1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AppArmor security module |
4 | * |
5 | * This file contains AppArmor auditing functions |
6 | * |
7 | * Copyright (C) 1998-2008 Novell/SUSE |
8 | * Copyright 2009-2010 Canonical Ltd. |
9 | */ |
10 | |
11 | #include <linux/audit.h> |
12 | #include <linux/socket.h> |
13 | |
14 | #include "include/apparmor.h" |
15 | #include "include/audit.h" |
16 | #include "include/policy.h" |
17 | #include "include/policy_ns.h" |
18 | #include "include/secid.h" |
19 | |
20 | const char *const audit_mode_names[] = { |
21 | "normal" , |
22 | "quiet_denied" , |
23 | "quiet" , |
24 | "noquiet" , |
25 | "all" |
26 | }; |
27 | |
28 | static const char *const aa_audit_type[] = { |
29 | "AUDIT" , |
30 | "ALLOWED" , |
31 | "DENIED" , |
32 | "HINT" , |
33 | "STATUS" , |
34 | "ERROR" , |
35 | "KILLED" , |
36 | "AUTO" |
37 | }; |
38 | |
39 | static const char *const aa_class_names[] = { |
40 | "none" , |
41 | "unknown" , |
42 | "file" , |
43 | "cap" , |
44 | "net" , |
45 | "rlimits" , |
46 | "domain" , |
47 | "mount" , |
48 | "unknown" , |
49 | "ptrace" , |
50 | "signal" , |
51 | "xmatch" , |
52 | "unknown" , |
53 | "unknown" , |
54 | "net" , |
55 | "unknown" , |
56 | "label" , |
57 | "posix_mqueue" , |
58 | "io_uring" , |
59 | "module" , |
60 | "lsm" , |
61 | "namespace" , |
62 | "io_uring" , |
63 | "unknown" , |
64 | "unknown" , |
65 | "unknown" , |
66 | "unknown" , |
67 | "unknown" , |
68 | "unknown" , |
69 | "unknown" , |
70 | "unknown" , |
71 | "X" , |
72 | "dbus" , |
73 | }; |
74 | |
75 | |
76 | /* |
77 | * Currently AppArmor auditing is fed straight into the audit framework. |
78 | * |
79 | * TODO: |
80 | * netlink interface for complain mode |
81 | * user auditing, - send user auditing to netlink interface |
82 | * system control of whether user audit messages go to system log |
83 | */ |
84 | |
85 | /** |
86 | * audit_pre() - core AppArmor function. |
87 | * @ab: audit buffer to fill (NOT NULL) |
88 | * @va: audit structure containing data to audit (NOT NULL) |
89 | * |
90 | * Record common AppArmor audit data from @va |
91 | */ |
92 | static void audit_pre(struct audit_buffer *ab, void *va) |
93 | { |
94 | struct apparmor_audit_data *ad = aad_of_va(va); |
95 | |
96 | if (aa_g_audit_header) { |
97 | audit_log_format(ab, fmt: "apparmor=\"%s\"" , |
98 | aa_audit_type[ad->type]); |
99 | } |
100 | |
101 | if (ad->op) |
102 | audit_log_format(ab, fmt: " operation=\"%s\"" , ad->op); |
103 | |
104 | if (ad->class) |
105 | audit_log_format(ab, fmt: " class=\"%s\"" , |
106 | ad->class <= AA_CLASS_LAST ? |
107 | aa_class_names[ad->class] : |
108 | "unknown" ); |
109 | |
110 | if (ad->info) { |
111 | audit_log_format(ab, fmt: " info=\"%s\"" , ad->info); |
112 | if (ad->error) |
113 | audit_log_format(ab, fmt: " error=%d" , ad->error); |
114 | } |
115 | |
116 | if (ad->subj_label) { |
117 | struct aa_label *label = ad->subj_label; |
118 | |
119 | if (label_isprofile(label)) { |
120 | struct aa_profile *profile = labels_profile(label); |
121 | |
122 | if (profile->ns != root_ns) { |
123 | audit_log_format(ab, fmt: " namespace=" ); |
124 | audit_log_untrustedstring(ab, |
125 | string: profile->ns->base.hname); |
126 | } |
127 | audit_log_format(ab, fmt: " profile=" ); |
128 | audit_log_untrustedstring(ab, string: profile->base.hname); |
129 | } else { |
130 | audit_log_format(ab, fmt: " label=" ); |
131 | aa_label_xaudit(ab, ns: root_ns, label, FLAG_VIEW_SUBNS, |
132 | GFP_ATOMIC); |
133 | } |
134 | } |
135 | |
136 | if (ad->name) { |
137 | audit_log_format(ab, fmt: " name=" ); |
138 | audit_log_untrustedstring(ab, string: ad->name); |
139 | } |
140 | } |
141 | |
142 | /** |
143 | * aa_audit_msg - Log a message to the audit subsystem |
144 | * @type: audit type for the message |
145 | * @ad: audit event structure (NOT NULL) |
146 | * @cb: optional callback fn for type specific fields (MAYBE NULL) |
147 | */ |
148 | void aa_audit_msg(int type, struct apparmor_audit_data *ad, |
149 | void (*cb) (struct audit_buffer *, void *)) |
150 | { |
151 | ad->type = type; |
152 | common_lsm_audit(a: &ad->common, pre_audit: audit_pre, post_audit: cb); |
153 | } |
154 | |
155 | /** |
156 | * aa_audit - Log a profile based audit event to the audit subsystem |
157 | * @type: audit type for the message |
158 | * @profile: profile to check against (NOT NULL) |
159 | * @ad: audit event (NOT NULL) |
160 | * @cb: optional callback fn for type specific fields (MAYBE NULL) |
161 | * |
162 | * Handle default message switching based off of audit mode flags |
163 | * |
164 | * Returns: error on failure |
165 | */ |
166 | int aa_audit(int type, struct aa_profile *profile, |
167 | struct apparmor_audit_data *ad, |
168 | void (*cb) (struct audit_buffer *, void *)) |
169 | { |
170 | AA_BUG(!profile); |
171 | |
172 | if (type == AUDIT_APPARMOR_AUTO) { |
173 | if (likely(!ad->error)) { |
174 | if (AUDIT_MODE(profile) != AUDIT_ALL) |
175 | return 0; |
176 | type = AUDIT_APPARMOR_AUDIT; |
177 | } else if (COMPLAIN_MODE(profile)) |
178 | type = AUDIT_APPARMOR_ALLOWED; |
179 | else |
180 | type = AUDIT_APPARMOR_DENIED; |
181 | } |
182 | if (AUDIT_MODE(profile) == AUDIT_QUIET || |
183 | (type == AUDIT_APPARMOR_DENIED && |
184 | AUDIT_MODE(profile) == AUDIT_QUIET_DENIED)) |
185 | return ad->error; |
186 | |
187 | if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) |
188 | type = AUDIT_APPARMOR_KILL; |
189 | |
190 | ad->subj_label = &profile->label; |
191 | |
192 | aa_audit_msg(type, ad, cb); |
193 | |
194 | if (ad->type == AUDIT_APPARMOR_KILL) |
195 | (void)send_sig_info(SIGKILL, NULL, |
196 | ad->common.type == LSM_AUDIT_DATA_TASK && |
197 | ad->common.u.tsk ? ad->common.u.tsk : current); |
198 | |
199 | if (ad->type == AUDIT_APPARMOR_ALLOWED) |
200 | return complain_error(error: ad->error); |
201 | |
202 | return ad->error; |
203 | } |
204 | |
205 | struct aa_audit_rule { |
206 | struct aa_label *label; |
207 | }; |
208 | |
209 | void aa_audit_rule_free(void *vrule) |
210 | { |
211 | struct aa_audit_rule *rule = vrule; |
212 | |
213 | if (rule) { |
214 | if (!IS_ERR(ptr: rule->label)) |
215 | aa_put_label(l: rule->label); |
216 | kfree(objp: rule); |
217 | } |
218 | } |
219 | |
220 | int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) |
221 | { |
222 | struct aa_audit_rule *rule; |
223 | |
224 | switch (field) { |
225 | case AUDIT_SUBJ_ROLE: |
226 | if (op != Audit_equal && op != Audit_not_equal) |
227 | return -EINVAL; |
228 | break; |
229 | default: |
230 | return -EINVAL; |
231 | } |
232 | |
233 | rule = kzalloc(size: sizeof(struct aa_audit_rule), GFP_KERNEL); |
234 | |
235 | if (!rule) |
236 | return -ENOMEM; |
237 | |
238 | /* Currently rules are treated as coming from the root ns */ |
239 | rule->label = aa_label_parse(base: &root_ns->unconfined->label, str: rulestr, |
240 | GFP_KERNEL, create: true, force_stack: false); |
241 | if (IS_ERR(ptr: rule->label)) { |
242 | int err = PTR_ERR(ptr: rule->label); |
243 | aa_audit_rule_free(vrule: rule); |
244 | return err; |
245 | } |
246 | |
247 | *vrule = rule; |
248 | return 0; |
249 | } |
250 | |
251 | int aa_audit_rule_known(struct audit_krule *rule) |
252 | { |
253 | int i; |
254 | |
255 | for (i = 0; i < rule->field_count; i++) { |
256 | struct audit_field *f = &rule->fields[i]; |
257 | |
258 | switch (f->type) { |
259 | case AUDIT_SUBJ_ROLE: |
260 | return 1; |
261 | } |
262 | } |
263 | |
264 | return 0; |
265 | } |
266 | |
267 | int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) |
268 | { |
269 | struct aa_audit_rule *rule = vrule; |
270 | struct aa_label *label; |
271 | int found = 0; |
272 | |
273 | label = aa_secid_to_label(secid: sid); |
274 | |
275 | if (!label) |
276 | return -ENOENT; |
277 | |
278 | if (aa_label_is_subset(set: label, sub: rule->label)) |
279 | found = 1; |
280 | |
281 | switch (field) { |
282 | case AUDIT_SUBJ_ROLE: |
283 | switch (op) { |
284 | case Audit_equal: |
285 | return found; |
286 | case Audit_not_equal: |
287 | return !found; |
288 | } |
289 | } |
290 | return 0; |
291 | } |
292 | |