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