Commit 67012e8209df95a8290d135753ff5145431a666e
Committed by
James Morris
1 parent
cdff264264
Exists in
master
and in
4 other branches
AppArmor: basic auditing infrastructure.
Update lsm_audit for AppArmor specific data, and add the core routines for AppArmor uses for auditing. Signed-off-by: John Johansen <john.johansen@canonical.com> Signed-off-by: James Morris <jmorris@namei.org>
Showing 3 changed files with 365 additions and 0 deletions Side-by-side Diff
include/linux/lsm_audit.h
... | ... | @@ -99,6 +99,33 @@ |
99 | 99 | int result; |
100 | 100 | } selinux_audit_data; |
101 | 101 | #endif |
102 | +#ifdef CONFIG_SECURITY_APPARMOR | |
103 | + struct { | |
104 | + int error; | |
105 | + int op; | |
106 | + int type; | |
107 | + void *profile; | |
108 | + const char *name; | |
109 | + const char *info; | |
110 | + union { | |
111 | + void *target; | |
112 | + struct { | |
113 | + long pos; | |
114 | + void *target; | |
115 | + } iface; | |
116 | + struct { | |
117 | + int rlim; | |
118 | + unsigned long max; | |
119 | + } rlim; | |
120 | + struct { | |
121 | + const char *target; | |
122 | + u32 request; | |
123 | + u32 denied; | |
124 | + uid_t ouid; | |
125 | + } fs; | |
126 | + }; | |
127 | + } apparmor_audit_data; | |
128 | +#endif | |
102 | 129 | }; |
103 | 130 | /* these callback will be implemented by a specific LSM */ |
104 | 131 | void (*lsm_pre_audit)(struct audit_buffer *, void *); |
security/apparmor/audit.c
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 | + | |
22 | +const char *op_table[] = { | |
23 | + "null", | |
24 | + | |
25 | + "sysctl", | |
26 | + "capable", | |
27 | + | |
28 | + "unlink", | |
29 | + "mkdir", | |
30 | + "rmdir", | |
31 | + "mknod", | |
32 | + "truncate", | |
33 | + "link", | |
34 | + "symlink", | |
35 | + "rename_src", | |
36 | + "rename_dest", | |
37 | + "chmod", | |
38 | + "chown", | |
39 | + "getattr", | |
40 | + "open", | |
41 | + | |
42 | + "file_perm", | |
43 | + "file_lock", | |
44 | + "file_mmap", | |
45 | + "file_mprotect", | |
46 | + | |
47 | + "create", | |
48 | + "post_create", | |
49 | + "bind", | |
50 | + "connect", | |
51 | + "listen", | |
52 | + "accept", | |
53 | + "sendmsg", | |
54 | + "recvmsg", | |
55 | + "getsockname", | |
56 | + "getpeername", | |
57 | + "getsockopt", | |
58 | + "setsockopt", | |
59 | + "socket_shutdown", | |
60 | + | |
61 | + "ptrace", | |
62 | + | |
63 | + "exec", | |
64 | + "change_hat", | |
65 | + "change_profile", | |
66 | + "change_onexec", | |
67 | + | |
68 | + "setprocattr", | |
69 | + "setrlimit", | |
70 | + | |
71 | + "profile_replace", | |
72 | + "profile_load", | |
73 | + "profile_remove" | |
74 | +}; | |
75 | + | |
76 | +const char *audit_mode_names[] = { | |
77 | + "normal", | |
78 | + "quiet_denied", | |
79 | + "quiet", | |
80 | + "noquiet", | |
81 | + "all" | |
82 | +}; | |
83 | + | |
84 | +static char *aa_audit_type[] = { | |
85 | + "AUDIT", | |
86 | + "ALLOWED", | |
87 | + "DENIED", | |
88 | + "HINT", | |
89 | + "STATUS", | |
90 | + "ERROR", | |
91 | + "KILLED" | |
92 | +}; | |
93 | + | |
94 | +/* | |
95 | + * Currently AppArmor auditing is fed straight into the audit framework. | |
96 | + * | |
97 | + * TODO: | |
98 | + * netlink interface for complain mode | |
99 | + * user auditing, - send user auditing to netlink interface | |
100 | + * system control of whether user audit messages go to system log | |
101 | + */ | |
102 | + | |
103 | +/** | |
104 | + * audit_base - core AppArmor function. | |
105 | + * @ab: audit buffer to fill (NOT NULL) | |
106 | + * @ca: audit structure containing data to audit (NOT NULL) | |
107 | + * | |
108 | + * Record common AppArmor audit data from @sa | |
109 | + */ | |
110 | +static void audit_pre(struct audit_buffer *ab, void *ca) | |
111 | +{ | |
112 | + struct common_audit_data *sa = ca; | |
113 | + struct task_struct *tsk = sa->tsk ? sa->tsk : current; | |
114 | + | |
115 | + if (aa_g_audit_header) { | |
116 | + audit_log_format(ab, "apparmor="); | |
117 | + audit_log_string(ab, aa_audit_type[sa->aad.type]); | |
118 | + } | |
119 | + | |
120 | + if (sa->aad.op) { | |
121 | + audit_log_format(ab, " operation="); | |
122 | + audit_log_string(ab, op_table[sa->aad.op]); | |
123 | + } | |
124 | + | |
125 | + if (sa->aad.info) { | |
126 | + audit_log_format(ab, " info="); | |
127 | + audit_log_string(ab, sa->aad.info); | |
128 | + if (sa->aad.error) | |
129 | + audit_log_format(ab, " error=%d", sa->aad.error); | |
130 | + } | |
131 | + | |
132 | + if (sa->aad.profile) { | |
133 | + struct aa_profile *profile = sa->aad.profile; | |
134 | + pid_t pid; | |
135 | + rcu_read_lock(); | |
136 | + pid = tsk->real_parent->pid; | |
137 | + rcu_read_unlock(); | |
138 | + audit_log_format(ab, " parent=%d", pid); | |
139 | + if (profile->ns != root_ns) { | |
140 | + audit_log_format(ab, " namespace="); | |
141 | + audit_log_untrustedstring(ab, profile->ns->base.hname); | |
142 | + } | |
143 | + audit_log_format(ab, " profile="); | |
144 | + audit_log_untrustedstring(ab, profile->base.hname); | |
145 | + } | |
146 | + | |
147 | + if (sa->aad.name) { | |
148 | + audit_log_format(ab, " name="); | |
149 | + audit_log_untrustedstring(ab, sa->aad.name); | |
150 | + } | |
151 | +} | |
152 | + | |
153 | +/** | |
154 | + * aa_audit_msg - Log a message to the audit subsystem | |
155 | + * @sa: audit event structure (NOT NULL) | |
156 | + * @cb: optional callback fn for type specific fields (MAYBE NULL) | |
157 | + */ | |
158 | +void aa_audit_msg(int type, struct common_audit_data *sa, | |
159 | + void (*cb) (struct audit_buffer *, void *)) | |
160 | +{ | |
161 | + sa->aad.type = type; | |
162 | + sa->lsm_pre_audit = audit_pre; | |
163 | + sa->lsm_post_audit = cb; | |
164 | + common_lsm_audit(sa); | |
165 | +} | |
166 | + | |
167 | +/** | |
168 | + * aa_audit - Log a profile based audit event to the audit subsystem | |
169 | + * @type: audit type for the message | |
170 | + * @profile: profile to check against (NOT NULL) | |
171 | + * @gfp: allocation flags to use | |
172 | + * @sa: audit event (NOT NULL) | |
173 | + * @cb: optional callback fn for type specific fields (MAYBE NULL) | |
174 | + * | |
175 | + * Handle default message switching based off of audit mode flags | |
176 | + * | |
177 | + * Returns: error on failure | |
178 | + */ | |
179 | +int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, | |
180 | + struct common_audit_data *sa, | |
181 | + void (*cb) (struct audit_buffer *, void *)) | |
182 | +{ | |
183 | + BUG_ON(!profile); | |
184 | + | |
185 | + if (type == AUDIT_APPARMOR_AUTO) { | |
186 | + if (likely(!sa->aad.error)) { | |
187 | + if (AUDIT_MODE(profile) != AUDIT_ALL) | |
188 | + return 0; | |
189 | + type = AUDIT_APPARMOR_AUDIT; | |
190 | + } else if (COMPLAIN_MODE(profile)) | |
191 | + type = AUDIT_APPARMOR_ALLOWED; | |
192 | + else | |
193 | + type = AUDIT_APPARMOR_DENIED; | |
194 | + } | |
195 | + if (AUDIT_MODE(profile) == AUDIT_QUIET || | |
196 | + (type == AUDIT_APPARMOR_DENIED && | |
197 | + AUDIT_MODE(profile) == AUDIT_QUIET)) | |
198 | + return sa->aad.error; | |
199 | + | |
200 | + if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) | |
201 | + type = AUDIT_APPARMOR_KILL; | |
202 | + | |
203 | + if (!unconfined(profile)) | |
204 | + sa->aad.profile = profile; | |
205 | + | |
206 | + aa_audit_msg(type, sa, cb); | |
207 | + | |
208 | + if (sa->aad.type == AUDIT_APPARMOR_KILL) | |
209 | + (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current); | |
210 | + | |
211 | + if (sa->aad.type == AUDIT_APPARMOR_ALLOWED) | |
212 | + return complain_error(sa->aad.error); | |
213 | + | |
214 | + return sa->aad.error; | |
215 | +} |
security/apparmor/include/audit.h
1 | +/* | |
2 | + * AppArmor security module | |
3 | + * | |
4 | + * This file contains AppArmor auditing function definitions. | |
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 | +#ifndef __AA_AUDIT_H | |
16 | +#define __AA_AUDIT_H | |
17 | + | |
18 | +#include <linux/audit.h> | |
19 | +#include <linux/fs.h> | |
20 | +#include <linux/lsm_audit.h> | |
21 | +#include <linux/sched.h> | |
22 | +#include <linux/slab.h> | |
23 | + | |
24 | +#include "file.h" | |
25 | + | |
26 | +struct aa_profile; | |
27 | + | |
28 | +extern const char *audit_mode_names[]; | |
29 | +#define AUDIT_MAX_INDEX 5 | |
30 | + | |
31 | +#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */ | |
32 | + | |
33 | +enum audit_mode { | |
34 | + AUDIT_NORMAL, /* follow normal auditing of accesses */ | |
35 | + AUDIT_QUIET_DENIED, /* quiet all denied access messages */ | |
36 | + AUDIT_QUIET, /* quiet all messages */ | |
37 | + AUDIT_NOQUIET, /* do not quiet audit messages */ | |
38 | + AUDIT_ALL /* audit all accesses */ | |
39 | +}; | |
40 | + | |
41 | +enum audit_type { | |
42 | + AUDIT_APPARMOR_AUDIT, | |
43 | + AUDIT_APPARMOR_ALLOWED, | |
44 | + AUDIT_APPARMOR_DENIED, | |
45 | + AUDIT_APPARMOR_HINT, | |
46 | + AUDIT_APPARMOR_STATUS, | |
47 | + AUDIT_APPARMOR_ERROR, | |
48 | + AUDIT_APPARMOR_KILL | |
49 | +}; | |
50 | + | |
51 | +extern const char *op_table[]; | |
52 | +enum aa_ops { | |
53 | + OP_NULL, | |
54 | + | |
55 | + OP_SYSCTL, | |
56 | + OP_CAPABLE, | |
57 | + | |
58 | + OP_UNLINK, | |
59 | + OP_MKDIR, | |
60 | + OP_RMDIR, | |
61 | + OP_MKNOD, | |
62 | + OP_TRUNC, | |
63 | + OP_LINK, | |
64 | + OP_SYMLINK, | |
65 | + OP_RENAME_SRC, | |
66 | + OP_RENAME_DEST, | |
67 | + OP_CHMOD, | |
68 | + OP_CHOWN, | |
69 | + OP_GETATTR, | |
70 | + OP_OPEN, | |
71 | + | |
72 | + OP_FPERM, | |
73 | + OP_FLOCK, | |
74 | + OP_FMMAP, | |
75 | + OP_FMPROT, | |
76 | + | |
77 | + OP_CREATE, | |
78 | + OP_POST_CREATE, | |
79 | + OP_BIND, | |
80 | + OP_CONNECT, | |
81 | + OP_LISTEN, | |
82 | + OP_ACCEPT, | |
83 | + OP_SENDMSG, | |
84 | + OP_RECVMSG, | |
85 | + OP_GETSOCKNAME, | |
86 | + OP_GETPEERNAME, | |
87 | + OP_GETSOCKOPT, | |
88 | + OP_SETSOCKOPT, | |
89 | + OP_SOCK_SHUTDOWN, | |
90 | + | |
91 | + OP_PTRACE, | |
92 | + | |
93 | + OP_EXEC, | |
94 | + OP_CHANGE_HAT, | |
95 | + OP_CHANGE_PROFILE, | |
96 | + OP_CHANGE_ONEXEC, | |
97 | + | |
98 | + OP_SETPROCATTR, | |
99 | + OP_SETRLIMIT, | |
100 | + | |
101 | + OP_PROF_REPL, | |
102 | + OP_PROF_LOAD, | |
103 | + OP_PROF_RM, | |
104 | +}; | |
105 | + | |
106 | + | |
107 | +/* define a short hand for apparmor_audit_data portion of common_audit_data */ | |
108 | +#define aad apparmor_audit_data | |
109 | + | |
110 | +void aa_audit_msg(int type, struct common_audit_data *sa, | |
111 | + void (*cb) (struct audit_buffer *, void *)); | |
112 | +int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, | |
113 | + struct common_audit_data *sa, | |
114 | + void (*cb) (struct audit_buffer *, void *)); | |
115 | + | |
116 | +static inline int complain_error(int error) | |
117 | +{ | |
118 | + if (error == -EPERM || error == -EACCES) | |
119 | + return 0; | |
120 | + return error; | |
121 | +} | |
122 | + | |
123 | +#endif /* __AA_AUDIT_H */ |