xref: /openbmc/linux/security/apparmor/audit.c (revision ee1cd5048959de496cd005c50b137212a5b62062)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
267012e82SJohn Johansen /*
367012e82SJohn Johansen  * AppArmor security module
467012e82SJohn Johansen  *
567012e82SJohn Johansen  * This file contains AppArmor auditing functions
667012e82SJohn Johansen  *
767012e82SJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
867012e82SJohn Johansen  * Copyright 2009-2010 Canonical Ltd.
967012e82SJohn Johansen  */
1067012e82SJohn Johansen 
1167012e82SJohn Johansen #include <linux/audit.h>
1267012e82SJohn Johansen #include <linux/socket.h>
1367012e82SJohn Johansen 
1467012e82SJohn Johansen #include "include/apparmor.h"
1567012e82SJohn Johansen #include "include/audit.h"
1667012e82SJohn Johansen #include "include/policy.h"
17cff281f6SJohn Johansen #include "include/policy_ns.h"
18e79c26d0SMatthew Garrett #include "include/secid.h"
1967012e82SJohn Johansen 
202d4cee7eSJan Engelhardt const char *const audit_mode_names[] = {
2167012e82SJohn Johansen 	"normal",
2267012e82SJohn Johansen 	"quiet_denied",
2367012e82SJohn Johansen 	"quiet",
2467012e82SJohn Johansen 	"noquiet",
2567012e82SJohn Johansen 	"all"
2667012e82SJohn Johansen };
2767012e82SJohn Johansen 
282d4cee7eSJan Engelhardt static const char *const aa_audit_type[] = {
2967012e82SJohn Johansen 	"AUDIT",
3067012e82SJohn Johansen 	"ALLOWED",
3167012e82SJohn Johansen 	"DENIED",
3267012e82SJohn Johansen 	"HINT",
3367012e82SJohn Johansen 	"STATUS",
3467012e82SJohn Johansen 	"ERROR",
35b492d50bSJohn Johansen 	"KILLED",
36ade3ddc0SJohn Johansen 	"AUTO"
3767012e82SJohn Johansen };
3867012e82SJohn Johansen 
398c4b785aSJohn Johansen static const char *const aa_class_names[] = {
408c4b785aSJohn Johansen 	"none",
418c4b785aSJohn Johansen 	"unknown",
428c4b785aSJohn Johansen 	"file",
438c4b785aSJohn Johansen 	"cap",
448c4b785aSJohn Johansen 	"net",
458c4b785aSJohn Johansen 	"rlimits",
468c4b785aSJohn Johansen 	"domain",
478c4b785aSJohn Johansen 	"mount",
488c4b785aSJohn Johansen 	"unknown",
498c4b785aSJohn Johansen 	"ptrace",
508c4b785aSJohn Johansen 	"signal",
51961f3e3dSJohn Johansen 	"xmatch",
528c4b785aSJohn Johansen 	"unknown",
538c4b785aSJohn Johansen 	"unknown",
548c4b785aSJohn Johansen 	"net",
558c4b785aSJohn Johansen 	"unknown",
568c4b785aSJohn Johansen 	"label",
57961f3e3dSJohn Johansen 	"posix_mqueue",
58961f3e3dSJohn Johansen 	"io_uring",
59961f3e3dSJohn Johansen 	"module",
608c4b785aSJohn Johansen 	"lsm",
61961f3e3dSJohn Johansen 	"unknown",
62961f3e3dSJohn Johansen 	"unknown",
63961f3e3dSJohn Johansen 	"unknown",
64961f3e3dSJohn Johansen 	"unknown",
65961f3e3dSJohn Johansen 	"unknown",
66961f3e3dSJohn Johansen 	"unknown",
67961f3e3dSJohn Johansen 	"unknown",
68961f3e3dSJohn Johansen 	"unknown",
69961f3e3dSJohn Johansen 	"unknown",
70961f3e3dSJohn Johansen 	"unknown",
71961f3e3dSJohn Johansen 	"X",
72961f3e3dSJohn Johansen 	"dbus",
738c4b785aSJohn Johansen };
748c4b785aSJohn Johansen 
758c4b785aSJohn Johansen 
7667012e82SJohn Johansen /*
7767012e82SJohn Johansen  * Currently AppArmor auditing is fed straight into the audit framework.
7867012e82SJohn Johansen  *
7967012e82SJohn Johansen  * TODO:
8067012e82SJohn Johansen  * netlink interface for complain mode
8167012e82SJohn Johansen  * user auditing, - send user auditing to netlink interface
8267012e82SJohn Johansen  * system control of whether user audit messages go to system log
8367012e82SJohn Johansen  */
8467012e82SJohn Johansen 
8567012e82SJohn Johansen /**
8664a27ba9SJiapeng Chong  * audit_pre() - core AppArmor function.
8767012e82SJohn Johansen  * @ab: audit buffer to fill (NOT NULL)
88c57bc80fSJohn Johansen  * @va: audit structure containing data to audit (NOT NULL)
8967012e82SJohn Johansen  *
90c57bc80fSJohn Johansen  * Record common AppArmor audit data from @va
9167012e82SJohn Johansen  */
audit_pre(struct audit_buffer * ab,void * va)92c57bc80fSJohn Johansen static void audit_pre(struct audit_buffer *ab, void *va)
9367012e82SJohn Johansen {
94c57bc80fSJohn Johansen 	struct apparmor_audit_data *ad = aad_of_va(va);
9567012e82SJohn Johansen 
9667012e82SJohn Johansen 	if (aa_g_audit_header) {
97f1d9b23cSRichard Guy Briggs 		audit_log_format(ab, "apparmor=\"%s\"",
98c57bc80fSJohn Johansen 				 aa_audit_type[ad->type]);
9967012e82SJohn Johansen 	}
10067012e82SJohn Johansen 
101c57bc80fSJohn Johansen 	if (ad->op)
102c57bc80fSJohn Johansen 		audit_log_format(ab, " operation=\"%s\"", ad->op);
10367012e82SJohn Johansen 
104c57bc80fSJohn Johansen 	if (ad->class)
1058c4b785aSJohn Johansen 		audit_log_format(ab, " class=\"%s\"",
106c57bc80fSJohn Johansen 				 ad->class <= AA_CLASS_LAST ?
107c57bc80fSJohn Johansen 				 aa_class_names[ad->class] :
1088c4b785aSJohn Johansen 				 "unknown");
1098c4b785aSJohn Johansen 
110c57bc80fSJohn Johansen 	if (ad->info) {
111c57bc80fSJohn Johansen 		audit_log_format(ab, " info=\"%s\"", ad->info);
112c57bc80fSJohn Johansen 		if (ad->error)
113c57bc80fSJohn Johansen 			audit_log_format(ab, " error=%d", ad->error);
11467012e82SJohn Johansen 	}
11567012e82SJohn Johansen 
11630b3669dSJohn Johansen 	if (ad->subj_label) {
11730b3669dSJohn Johansen 		struct aa_label *label = ad->subj_label;
118637f688dSJohn Johansen 
119637f688dSJohn Johansen 		if (label_isprofile(label)) {
120637f688dSJohn Johansen 			struct aa_profile *profile = labels_profile(label);
121637f688dSJohn Johansen 
12267012e82SJohn Johansen 			if (profile->ns != root_ns) {
12367012e82SJohn Johansen 				audit_log_format(ab, " namespace=");
124637f688dSJohn Johansen 				audit_log_untrustedstring(ab,
125637f688dSJohn Johansen 						       profile->ns->base.hname);
12667012e82SJohn Johansen 			}
12767012e82SJohn Johansen 			audit_log_format(ab, " profile=");
12867012e82SJohn Johansen 			audit_log_untrustedstring(ab, profile->base.hname);
129637f688dSJohn Johansen 		} else {
130637f688dSJohn Johansen 			audit_log_format(ab, " label=");
131637f688dSJohn Johansen 			aa_label_xaudit(ab, root_ns, label, FLAG_VIEW_SUBNS,
132637f688dSJohn Johansen 					GFP_ATOMIC);
133637f688dSJohn Johansen 		}
13467012e82SJohn Johansen 	}
13567012e82SJohn Johansen 
136c57bc80fSJohn Johansen 	if (ad->name) {
13767012e82SJohn Johansen 		audit_log_format(ab, " name=");
138c57bc80fSJohn Johansen 		audit_log_untrustedstring(ab, ad->name);
13967012e82SJohn Johansen 	}
14067012e82SJohn Johansen }
14167012e82SJohn Johansen 
14267012e82SJohn Johansen /**
14367012e82SJohn Johansen  * aa_audit_msg - Log a message to the audit subsystem
14463c7297cSGaosheng Cui  * @type: audit type for the message
145c57bc80fSJohn Johansen  * @ad: audit event structure (NOT NULL)
14667012e82SJohn Johansen  * @cb: optional callback fn for type specific fields (MAYBE NULL)
14767012e82SJohn Johansen  */
aa_audit_msg(int type,struct apparmor_audit_data * ad,void (* cb)(struct audit_buffer *,void *))148c57bc80fSJohn Johansen void aa_audit_msg(int type, struct apparmor_audit_data *ad,
14967012e82SJohn Johansen 		  void (*cb) (struct audit_buffer *, void *))
15067012e82SJohn Johansen {
151c57bc80fSJohn Johansen 	ad->type = type;
152c57bc80fSJohn Johansen 	common_lsm_audit(&ad->common, audit_pre, cb);
15367012e82SJohn Johansen }
15467012e82SJohn Johansen 
15567012e82SJohn Johansen /**
15667012e82SJohn Johansen  * aa_audit - Log a profile based audit event to the audit subsystem
15767012e82SJohn Johansen  * @type: audit type for the message
15867012e82SJohn Johansen  * @profile: profile to check against (NOT NULL)
159c57bc80fSJohn Johansen  * @ad: audit event (NOT NULL)
16067012e82SJohn Johansen  * @cb: optional callback fn for type specific fields (MAYBE NULL)
16167012e82SJohn Johansen  *
16267012e82SJohn Johansen  * Handle default message switching based off of audit mode flags
16367012e82SJohn Johansen  *
16467012e82SJohn Johansen  * Returns: error on failure
16567012e82SJohn Johansen  */
aa_audit(int type,struct aa_profile * profile,struct apparmor_audit_data * ad,void (* cb)(struct audit_buffer *,void *))166c57bc80fSJohn Johansen int aa_audit(int type, struct aa_profile *profile,
167c57bc80fSJohn Johansen 	     struct apparmor_audit_data *ad,
16867012e82SJohn Johansen 	     void (*cb) (struct audit_buffer *, void *))
16967012e82SJohn Johansen {
170e6bfa25dSJohn Johansen 	AA_BUG(!profile);
17167012e82SJohn Johansen 
17267012e82SJohn Johansen 	if (type == AUDIT_APPARMOR_AUTO) {
173c57bc80fSJohn Johansen 		if (likely(!ad->error)) {
17467012e82SJohn Johansen 			if (AUDIT_MODE(profile) != AUDIT_ALL)
17567012e82SJohn Johansen 				return 0;
17667012e82SJohn Johansen 			type = AUDIT_APPARMOR_AUDIT;
17767012e82SJohn Johansen 		} else if (COMPLAIN_MODE(profile))
17867012e82SJohn Johansen 			type = AUDIT_APPARMOR_ALLOWED;
17967012e82SJohn Johansen 		else
18067012e82SJohn Johansen 			type = AUDIT_APPARMOR_DENIED;
18167012e82SJohn Johansen 	}
18267012e82SJohn Johansen 	if (AUDIT_MODE(profile) == AUDIT_QUIET ||
18367012e82SJohn Johansen 	    (type == AUDIT_APPARMOR_DENIED &&
18468ff8540SJohn Johansen 	     AUDIT_MODE(profile) == AUDIT_QUIET_DENIED))
185c57bc80fSJohn Johansen 		return ad->error;
18667012e82SJohn Johansen 
18767012e82SJohn Johansen 	if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
18867012e82SJohn Johansen 		type = AUDIT_APPARMOR_KILL;
18967012e82SJohn Johansen 
19030b3669dSJohn Johansen 	ad->subj_label = &profile->label;
19167012e82SJohn Johansen 
192c57bc80fSJohn Johansen 	aa_audit_msg(type, ad, cb);
19367012e82SJohn Johansen 
194c57bc80fSJohn Johansen 	if (ad->type == AUDIT_APPARMOR_KILL)
1950972c74eSEric Paris 		(void)send_sig_info(SIGKILL, NULL,
196c57bc80fSJohn Johansen 			ad->common.type == LSM_AUDIT_DATA_TASK &&
197c57bc80fSJohn Johansen 			ad->common.u.tsk ? ad->common.u.tsk : current);
19867012e82SJohn Johansen 
199c57bc80fSJohn Johansen 	if (ad->type == AUDIT_APPARMOR_ALLOWED)
200c57bc80fSJohn Johansen 		return complain_error(ad->error);
20167012e82SJohn Johansen 
202c57bc80fSJohn Johansen 	return ad->error;
20367012e82SJohn Johansen }
204e79c26d0SMatthew Garrett 
205e79c26d0SMatthew Garrett struct aa_audit_rule {
2062ab47daeSJohn Johansen 	struct aa_label *label;
207e79c26d0SMatthew Garrett };
208e79c26d0SMatthew Garrett 
aa_audit_rule_free(void * vrule)209e79c26d0SMatthew Garrett void aa_audit_rule_free(void *vrule)
210e79c26d0SMatthew Garrett {
211e79c26d0SMatthew Garrett 	struct aa_audit_rule *rule = vrule;
212e79c26d0SMatthew Garrett 
213e79c26d0SMatthew Garrett 	if (rule) {
2142ab47daeSJohn Johansen 		if (!IS_ERR(rule->label))
2152ab47daeSJohn Johansen 			aa_put_label(rule->label);
216e79c26d0SMatthew Garrett 		kfree(rule);
217e79c26d0SMatthew Garrett 	}
218e79c26d0SMatthew Garrett }
219e79c26d0SMatthew Garrett 
aa_audit_rule_init(u32 field,u32 op,char * rulestr,void ** vrule,gfp_t gfp)220*28d0ecc5SGUO Zihua int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp)
221e79c26d0SMatthew Garrett {
222e79c26d0SMatthew Garrett 	struct aa_audit_rule *rule;
223e79c26d0SMatthew Garrett 
224e79c26d0SMatthew Garrett 	switch (field) {
225e79c26d0SMatthew Garrett 	case AUDIT_SUBJ_ROLE:
226e79c26d0SMatthew Garrett 		if (op != Audit_equal && op != Audit_not_equal)
227e79c26d0SMatthew Garrett 			return -EINVAL;
228e79c26d0SMatthew Garrett 		break;
229e79c26d0SMatthew Garrett 	default:
230e79c26d0SMatthew Garrett 		return -EINVAL;
231e79c26d0SMatthew Garrett 	}
232e79c26d0SMatthew Garrett 
233*28d0ecc5SGUO Zihua 	rule = kzalloc(sizeof(struct aa_audit_rule), gfp);
234e79c26d0SMatthew Garrett 
235e79c26d0SMatthew Garrett 	if (!rule)
236e79c26d0SMatthew Garrett 		return -ENOMEM;
237e79c26d0SMatthew Garrett 
2382ab47daeSJohn Johansen 	/* Currently rules are treated as coming from the root ns */
2392ab47daeSJohn Johansen 	rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr,
240*28d0ecc5SGUO Zihua 				     gfp, true, false);
24152e8c380STyler Hicks 	if (IS_ERR(rule->label)) {
242c54d481dSNavid Emamdoost 		int err = PTR_ERR(rule->label);
24352e8c380STyler Hicks 		aa_audit_rule_free(rule);
244c54d481dSNavid Emamdoost 		return err;
24552e8c380STyler Hicks 	}
246e79c26d0SMatthew Garrett 
24752e8c380STyler Hicks 	*vrule = rule;
248e79c26d0SMatthew Garrett 	return 0;
249e79c26d0SMatthew Garrett }
250e79c26d0SMatthew Garrett 
aa_audit_rule_known(struct audit_krule * rule)251e79c26d0SMatthew Garrett int aa_audit_rule_known(struct audit_krule *rule)
252e79c26d0SMatthew Garrett {
253e79c26d0SMatthew Garrett 	int i;
254e79c26d0SMatthew Garrett 
255e79c26d0SMatthew Garrett 	for (i = 0; i < rule->field_count; i++) {
256e79c26d0SMatthew Garrett 		struct audit_field *f = &rule->fields[i];
257e79c26d0SMatthew Garrett 
258e79c26d0SMatthew Garrett 		switch (f->type) {
259e79c26d0SMatthew Garrett 		case AUDIT_SUBJ_ROLE:
260e79c26d0SMatthew Garrett 			return 1;
261e79c26d0SMatthew Garrett 		}
262e79c26d0SMatthew Garrett 	}
263e79c26d0SMatthew Garrett 
264e79c26d0SMatthew Garrett 	return 0;
265e79c26d0SMatthew Garrett }
266e79c26d0SMatthew Garrett 
aa_audit_rule_match(u32 sid,u32 field,u32 op,void * vrule)26790462a5bSRichard Guy Briggs int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
268e79c26d0SMatthew Garrett {
269e79c26d0SMatthew Garrett 	struct aa_audit_rule *rule = vrule;
270e79c26d0SMatthew Garrett 	struct aa_label *label;
271e79c26d0SMatthew Garrett 	int found = 0;
272e79c26d0SMatthew Garrett 
273e79c26d0SMatthew Garrett 	label = aa_secid_to_label(sid);
274e79c26d0SMatthew Garrett 
275e79c26d0SMatthew Garrett 	if (!label)
276e79c26d0SMatthew Garrett 		return -ENOENT;
277e79c26d0SMatthew Garrett 
2782ab47daeSJohn Johansen 	if (aa_label_is_subset(label, rule->label))
279e79c26d0SMatthew Garrett 		found = 1;
280e79c26d0SMatthew Garrett 
281e79c26d0SMatthew Garrett 	switch (field) {
282e79c26d0SMatthew Garrett 	case AUDIT_SUBJ_ROLE:
283e79c26d0SMatthew Garrett 		switch (op) {
284e79c26d0SMatthew Garrett 		case Audit_equal:
285e79c26d0SMatthew Garrett 			return found;
286e79c26d0SMatthew Garrett 		case Audit_not_equal:
287e79c26d0SMatthew Garrett 			return !found;
288e79c26d0SMatthew Garrett 		}
289e79c26d0SMatthew Garrett 	}
290e79c26d0SMatthew Garrett 	return 0;
291e79c26d0SMatthew Garrett }
292