Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
67012e82 JJ |
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. | |
67012e82 JJ |
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" | |
cff281f6 | 17 | #include "include/policy_ns.h" |
e79c26d0 | 18 | #include "include/secid.h" |
67012e82 | 19 | |
2d4cee7e | 20 | const char *const audit_mode_names[] = { |
67012e82 JJ |
21 | "normal", |
22 | "quiet_denied", | |
23 | "quiet", | |
24 | "noquiet", | |
25 | "all" | |
26 | }; | |
27 | ||
2d4cee7e | 28 | static const char *const aa_audit_type[] = { |
67012e82 JJ |
29 | "AUDIT", |
30 | "ALLOWED", | |
31 | "DENIED", | |
32 | "HINT", | |
33 | "STATUS", | |
34 | "ERROR", | |
b492d50b | 35 | "KILLED", |
ade3ddc0 | 36 | "AUTO" |
67012e82 JJ |
37 | }; |
38 | ||
39 | /* | |
40 | * Currently AppArmor auditing is fed straight into the audit framework. | |
41 | * | |
42 | * TODO: | |
43 | * netlink interface for complain mode | |
44 | * user auditing, - send user auditing to netlink interface | |
45 | * system control of whether user audit messages go to system log | |
46 | */ | |
47 | ||
48 | /** | |
49 | * audit_base - core AppArmor function. | |
50 | * @ab: audit buffer to fill (NOT NULL) | |
51 | * @ca: audit structure containing data to audit (NOT NULL) | |
52 | * | |
53 | * Record common AppArmor audit data from @sa | |
54 | */ | |
55 | static void audit_pre(struct audit_buffer *ab, void *ca) | |
56 | { | |
57 | struct common_audit_data *sa = ca; | |
67012e82 JJ |
58 | |
59 | if (aa_g_audit_header) { | |
f1d9b23c RGB |
60 | audit_log_format(ab, "apparmor=\"%s\"", |
61 | aa_audit_type[aad(sa)->type]); | |
67012e82 JJ |
62 | } |
63 | ||
ef88a7ac | 64 | if (aad(sa)->op) { |
f1d9b23c | 65 | audit_log_format(ab, " operation=\"%s\"", aad(sa)->op); |
67012e82 JJ |
66 | } |
67 | ||
ef88a7ac | 68 | if (aad(sa)->info) { |
f1d9b23c | 69 | audit_log_format(ab, " info=\"%s\"", aad(sa)->info); |
ef88a7ac JJ |
70 | if (aad(sa)->error) |
71 | audit_log_format(ab, " error=%d", aad(sa)->error); | |
67012e82 JJ |
72 | } |
73 | ||
637f688d JJ |
74 | if (aad(sa)->label) { |
75 | struct aa_label *label = aad(sa)->label; | |
76 | ||
77 | if (label_isprofile(label)) { | |
78 | struct aa_profile *profile = labels_profile(label); | |
79 | ||
80 | if (profile->ns != root_ns) { | |
81 | audit_log_format(ab, " namespace="); | |
82 | audit_log_untrustedstring(ab, | |
83 | profile->ns->base.hname); | |
84 | } | |
85 | audit_log_format(ab, " profile="); | |
86 | audit_log_untrustedstring(ab, profile->base.hname); | |
87 | } else { | |
88 | audit_log_format(ab, " label="); | |
89 | aa_label_xaudit(ab, root_ns, label, FLAG_VIEW_SUBNS, | |
90 | GFP_ATOMIC); | |
67012e82 | 91 | } |
67012e82 JJ |
92 | } |
93 | ||
ef88a7ac | 94 | if (aad(sa)->name) { |
67012e82 | 95 | audit_log_format(ab, " name="); |
ef88a7ac | 96 | audit_log_untrustedstring(ab, aad(sa)->name); |
67012e82 JJ |
97 | } |
98 | } | |
99 | ||
100 | /** | |
101 | * aa_audit_msg - Log a message to the audit subsystem | |
102 | * @sa: audit event structure (NOT NULL) | |
103 | * @cb: optional callback fn for type specific fields (MAYBE NULL) | |
104 | */ | |
105 | void aa_audit_msg(int type, struct common_audit_data *sa, | |
106 | void (*cb) (struct audit_buffer *, void *)) | |
107 | { | |
ef88a7ac | 108 | aad(sa)->type = type; |
b61c37f5 | 109 | common_lsm_audit(sa, audit_pre, cb); |
67012e82 JJ |
110 | } |
111 | ||
112 | /** | |
113 | * aa_audit - Log a profile based audit event to the audit subsystem | |
114 | * @type: audit type for the message | |
115 | * @profile: profile to check against (NOT NULL) | |
67012e82 JJ |
116 | * @sa: audit event (NOT NULL) |
117 | * @cb: optional callback fn for type specific fields (MAYBE NULL) | |
118 | * | |
119 | * Handle default message switching based off of audit mode flags | |
120 | * | |
121 | * Returns: error on failure | |
122 | */ | |
ef88a7ac | 123 | int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, |
67012e82 JJ |
124 | void (*cb) (struct audit_buffer *, void *)) |
125 | { | |
e6bfa25d | 126 | AA_BUG(!profile); |
67012e82 JJ |
127 | |
128 | if (type == AUDIT_APPARMOR_AUTO) { | |
ef88a7ac | 129 | if (likely(!aad(sa)->error)) { |
67012e82 JJ |
130 | if (AUDIT_MODE(profile) != AUDIT_ALL) |
131 | return 0; | |
132 | type = AUDIT_APPARMOR_AUDIT; | |
133 | } else if (COMPLAIN_MODE(profile)) | |
134 | type = AUDIT_APPARMOR_ALLOWED; | |
135 | else | |
136 | type = AUDIT_APPARMOR_DENIED; | |
137 | } | |
138 | if (AUDIT_MODE(profile) == AUDIT_QUIET || | |
139 | (type == AUDIT_APPARMOR_DENIED && | |
140 | AUDIT_MODE(profile) == AUDIT_QUIET)) | |
ef88a7ac | 141 | return aad(sa)->error; |
67012e82 JJ |
142 | |
143 | if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) | |
144 | type = AUDIT_APPARMOR_KILL; | |
145 | ||
637f688d | 146 | aad(sa)->label = &profile->label; |
67012e82 JJ |
147 | |
148 | aa_audit_msg(type, sa, cb); | |
149 | ||
ef88a7ac | 150 | if (aad(sa)->type == AUDIT_APPARMOR_KILL) |
0972c74e | 151 | (void)send_sig_info(SIGKILL, NULL, |
b6b1b81b JJ |
152 | sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ? |
153 | sa->u.tsk : current); | |
67012e82 | 154 | |
ef88a7ac JJ |
155 | if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED) |
156 | return complain_error(aad(sa)->error); | |
67012e82 | 157 | |
ef88a7ac | 158 | return aad(sa)->error; |
67012e82 | 159 | } |
e79c26d0 MG |
160 | |
161 | struct aa_audit_rule { | |
2ab47dae | 162 | struct aa_label *label; |
e79c26d0 MG |
163 | }; |
164 | ||
165 | void aa_audit_rule_free(void *vrule) | |
166 | { | |
167 | struct aa_audit_rule *rule = vrule; | |
168 | ||
169 | if (rule) { | |
2ab47dae JJ |
170 | if (!IS_ERR(rule->label)) |
171 | aa_put_label(rule->label); | |
e79c26d0 MG |
172 | kfree(rule); |
173 | } | |
174 | } | |
175 | ||
176 | int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | |
177 | { | |
178 | struct aa_audit_rule *rule; | |
179 | ||
180 | switch (field) { | |
181 | case AUDIT_SUBJ_ROLE: | |
182 | if (op != Audit_equal && op != Audit_not_equal) | |
183 | return -EINVAL; | |
184 | break; | |
185 | default: | |
186 | return -EINVAL; | |
187 | } | |
188 | ||
189 | rule = kzalloc(sizeof(struct aa_audit_rule), GFP_KERNEL); | |
190 | ||
191 | if (!rule) | |
192 | return -ENOMEM; | |
193 | ||
2ab47dae JJ |
194 | /* Currently rules are treated as coming from the root ns */ |
195 | rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr, | |
196 | GFP_KERNEL, true, false); | |
52e8c380 | 197 | if (IS_ERR(rule->label)) { |
c54d481d | 198 | int err = PTR_ERR(rule->label); |
52e8c380 | 199 | aa_audit_rule_free(rule); |
c54d481d | 200 | return err; |
52e8c380 | 201 | } |
e79c26d0 | 202 | |
52e8c380 | 203 | *vrule = rule; |
e79c26d0 MG |
204 | return 0; |
205 | } | |
206 | ||
207 | int aa_audit_rule_known(struct audit_krule *rule) | |
208 | { | |
209 | int i; | |
210 | ||
211 | for (i = 0; i < rule->field_count; i++) { | |
212 | struct audit_field *f = &rule->fields[i]; | |
213 | ||
214 | switch (f->type) { | |
215 | case AUDIT_SUBJ_ROLE: | |
216 | return 1; | |
217 | } | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
90462a5b | 223 | int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) |
e79c26d0 MG |
224 | { |
225 | struct aa_audit_rule *rule = vrule; | |
226 | struct aa_label *label; | |
e79c26d0 MG |
227 | int found = 0; |
228 | ||
229 | label = aa_secid_to_label(sid); | |
230 | ||
231 | if (!label) | |
232 | return -ENOENT; | |
233 | ||
2ab47dae JJ |
234 | if (aa_label_is_subset(label, rule->label)) |
235 | found = 1; | |
e79c26d0 MG |
236 | |
237 | switch (field) { | |
238 | case AUDIT_SUBJ_ROLE: | |
239 | switch (op) { | |
240 | case Audit_equal: | |
241 | return found; | |
242 | case Audit_not_equal: | |
243 | return !found; | |
244 | } | |
245 | } | |
246 | return 0; | |
247 | } |