forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
5.3 KiB
247 lines
5.3 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* AppArmor security module |
|
* |
|
* This file contains AppArmor auditing functions |
|
* |
|
* Copyright (C) 1998-2008 Novell/SUSE |
|
* Copyright 2009-2010 Canonical Ltd. |
|
*/ |
|
|
|
#include <linux/audit.h> |
|
#include <linux/socket.h> |
|
|
|
#include "include/apparmor.h" |
|
#include "include/audit.h" |
|
#include "include/policy.h" |
|
#include "include/policy_ns.h" |
|
#include "include/secid.h" |
|
|
|
const char *const audit_mode_names[] = { |
|
"normal", |
|
"quiet_denied", |
|
"quiet", |
|
"noquiet", |
|
"all" |
|
}; |
|
|
|
static const char *const aa_audit_type[] = { |
|
"AUDIT", |
|
"ALLOWED", |
|
"DENIED", |
|
"HINT", |
|
"STATUS", |
|
"ERROR", |
|
"KILLED", |
|
"AUTO" |
|
}; |
|
|
|
/* |
|
* Currently AppArmor auditing is fed straight into the audit framework. |
|
* |
|
* TODO: |
|
* netlink interface for complain mode |
|
* user auditing, - send user auditing to netlink interface |
|
* system control of whether user audit messages go to system log |
|
*/ |
|
|
|
/** |
|
* audit_base - core AppArmor function. |
|
* @ab: audit buffer to fill (NOT NULL) |
|
* @ca: audit structure containing data to audit (NOT NULL) |
|
* |
|
* Record common AppArmor audit data from @sa |
|
*/ |
|
static void audit_pre(struct audit_buffer *ab, void *ca) |
|
{ |
|
struct common_audit_data *sa = ca; |
|
|
|
if (aa_g_audit_header) { |
|
audit_log_format(ab, "apparmor=\"%s\"", |
|
aa_audit_type[aad(sa)->type]); |
|
} |
|
|
|
if (aad(sa)->op) { |
|
audit_log_format(ab, " operation=\"%s\"", aad(sa)->op); |
|
} |
|
|
|
if (aad(sa)->info) { |
|
audit_log_format(ab, " info=\"%s\"", aad(sa)->info); |
|
if (aad(sa)->error) |
|
audit_log_format(ab, " error=%d", aad(sa)->error); |
|
} |
|
|
|
if (aad(sa)->label) { |
|
struct aa_label *label = aad(sa)->label; |
|
|
|
if (label_isprofile(label)) { |
|
struct aa_profile *profile = labels_profile(label); |
|
|
|
if (profile->ns != root_ns) { |
|
audit_log_format(ab, " namespace="); |
|
audit_log_untrustedstring(ab, |
|
profile->ns->base.hname); |
|
} |
|
audit_log_format(ab, " profile="); |
|
audit_log_untrustedstring(ab, profile->base.hname); |
|
} else { |
|
audit_log_format(ab, " label="); |
|
aa_label_xaudit(ab, root_ns, label, FLAG_VIEW_SUBNS, |
|
GFP_ATOMIC); |
|
} |
|
} |
|
|
|
if (aad(sa)->name) { |
|
audit_log_format(ab, " name="); |
|
audit_log_untrustedstring(ab, aad(sa)->name); |
|
} |
|
} |
|
|
|
/** |
|
* aa_audit_msg - Log a message to the audit subsystem |
|
* @sa: audit event structure (NOT NULL) |
|
* @cb: optional callback fn for type specific fields (MAYBE NULL) |
|
*/ |
|
void aa_audit_msg(int type, struct common_audit_data *sa, |
|
void (*cb) (struct audit_buffer *, void *)) |
|
{ |
|
aad(sa)->type = type; |
|
common_lsm_audit(sa, audit_pre, cb); |
|
} |
|
|
|
/** |
|
* aa_audit - Log a profile based audit event to the audit subsystem |
|
* @type: audit type for the message |
|
* @profile: profile to check against (NOT NULL) |
|
* @sa: audit event (NOT NULL) |
|
* @cb: optional callback fn for type specific fields (MAYBE NULL) |
|
* |
|
* Handle default message switching based off of audit mode flags |
|
* |
|
* Returns: error on failure |
|
*/ |
|
int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, |
|
void (*cb) (struct audit_buffer *, void *)) |
|
{ |
|
AA_BUG(!profile); |
|
|
|
if (type == AUDIT_APPARMOR_AUTO) { |
|
if (likely(!aad(sa)->error)) { |
|
if (AUDIT_MODE(profile) != AUDIT_ALL) |
|
return 0; |
|
type = AUDIT_APPARMOR_AUDIT; |
|
} else if (COMPLAIN_MODE(profile)) |
|
type = AUDIT_APPARMOR_ALLOWED; |
|
else |
|
type = AUDIT_APPARMOR_DENIED; |
|
} |
|
if (AUDIT_MODE(profile) == AUDIT_QUIET || |
|
(type == AUDIT_APPARMOR_DENIED && |
|
AUDIT_MODE(profile) == AUDIT_QUIET)) |
|
return aad(sa)->error; |
|
|
|
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) |
|
type = AUDIT_APPARMOR_KILL; |
|
|
|
aad(sa)->label = &profile->label; |
|
|
|
aa_audit_msg(type, sa, cb); |
|
|
|
if (aad(sa)->type == AUDIT_APPARMOR_KILL) |
|
(void)send_sig_info(SIGKILL, NULL, |
|
sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ? |
|
sa->u.tsk : current); |
|
|
|
if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED) |
|
return complain_error(aad(sa)->error); |
|
|
|
return aad(sa)->error; |
|
} |
|
|
|
struct aa_audit_rule { |
|
struct aa_label *label; |
|
}; |
|
|
|
void aa_audit_rule_free(void *vrule) |
|
{ |
|
struct aa_audit_rule *rule = vrule; |
|
|
|
if (rule) { |
|
if (!IS_ERR(rule->label)) |
|
aa_put_label(rule->label); |
|
kfree(rule); |
|
} |
|
} |
|
|
|
int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) |
|
{ |
|
struct aa_audit_rule *rule; |
|
|
|
switch (field) { |
|
case AUDIT_SUBJ_ROLE: |
|
if (op != Audit_equal && op != Audit_not_equal) |
|
return -EINVAL; |
|
break; |
|
default: |
|
return -EINVAL; |
|
} |
|
|
|
rule = kzalloc(sizeof(struct aa_audit_rule), GFP_KERNEL); |
|
|
|
if (!rule) |
|
return -ENOMEM; |
|
|
|
/* Currently rules are treated as coming from the root ns */ |
|
rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr, |
|
GFP_KERNEL, true, false); |
|
if (IS_ERR(rule->label)) { |
|
int err = PTR_ERR(rule->label); |
|
aa_audit_rule_free(rule); |
|
return err; |
|
} |
|
|
|
*vrule = rule; |
|
return 0; |
|
} |
|
|
|
int aa_audit_rule_known(struct audit_krule *rule) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < rule->field_count; i++) { |
|
struct audit_field *f = &rule->fields[i]; |
|
|
|
switch (f->type) { |
|
case AUDIT_SUBJ_ROLE: |
|
return 1; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) |
|
{ |
|
struct aa_audit_rule *rule = vrule; |
|
struct aa_label *label; |
|
int found = 0; |
|
|
|
label = aa_secid_to_label(sid); |
|
|
|
if (!label) |
|
return -ENOENT; |
|
|
|
if (aa_label_is_subset(label, rule->label)) |
|
found = 1; |
|
|
|
switch (field) { |
|
case AUDIT_SUBJ_ROLE: |
|
switch (op) { |
|
case Audit_equal: |
|
return found; |
|
case Audit_not_equal: |
|
return !found; |
|
} |
|
} |
|
return 0; |
|
}
|
|
|