diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2011-06-26 10:18:58 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-06-28 19:31:20 -0400 |
commit | eadd99cc85347b4f9eb10122ac90032eb4971b02 (patch) | |
tree | fa6075ad4917422288222ee52bfcb66b7ed30a0e /security/tomoyo/audit.c | |
parent | d5ca1725ac9ba876c2dd614bb9826d0c4e13d818 (diff) |
TOMOYO: Add auditing interface.
Add /sys/kernel/security/tomoyo/audit interface. This interface generates audit
logs in the form of domain policy so that /usr/sbin/tomoyo-auditd can reuse
audit logs for appending to /sys/kernel/security/tomoyo/domain_policy
interface.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/audit.c')
-rw-r--r-- | security/tomoyo/audit.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c new file mode 100644 index 000000000000..e882f17065f2 --- /dev/null +++ b/security/tomoyo/audit.c | |||
@@ -0,0 +1,300 @@ | |||
1 | /* | ||
2 | * security/tomoyo/audit.c | ||
3 | * | ||
4 | * Pathname restriction functions. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | ||
8 | |||
9 | #include "common.h" | ||
10 | #include <linux/slab.h> | ||
11 | |||
12 | /** | ||
13 | * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss. | ||
14 | * | ||
15 | * @time: Seconds since 1970/01/01 00:00:00. | ||
16 | * @stamp: Pointer to "struct tomoyo_time". | ||
17 | * | ||
18 | * Returns nothing. | ||
19 | * | ||
20 | * This function does not handle Y2038 problem. | ||
21 | */ | ||
22 | static void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp) | ||
23 | { | ||
24 | static const u16 tomoyo_eom[2][12] = { | ||
25 | { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | ||
26 | { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | ||
27 | }; | ||
28 | u16 y; | ||
29 | u8 m; | ||
30 | bool r; | ||
31 | stamp->sec = time % 60; | ||
32 | time /= 60; | ||
33 | stamp->min = time % 60; | ||
34 | time /= 60; | ||
35 | stamp->hour = time % 24; | ||
36 | time /= 24; | ||
37 | for (y = 1970; ; y++) { | ||
38 | const unsigned short days = (y & 3) ? 365 : 366; | ||
39 | if (time < days) | ||
40 | break; | ||
41 | time -= days; | ||
42 | } | ||
43 | r = (y & 3) == 0; | ||
44 | for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++) | ||
45 | ; | ||
46 | if (m) | ||
47 | time -= tomoyo_eom[r][m - 1]; | ||
48 | stamp->year = y; | ||
49 | stamp->month = ++m; | ||
50 | stamp->day = ++time; | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * tomoyo_print_header - Get header line of audit log. | ||
55 | * | ||
56 | * @r: Pointer to "struct tomoyo_request_info". | ||
57 | * | ||
58 | * Returns string representation. | ||
59 | * | ||
60 | * This function uses kmalloc(), so caller must kfree() if this function | ||
61 | * didn't return NULL. | ||
62 | */ | ||
63 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | ||
64 | { | ||
65 | struct tomoyo_time stamp; | ||
66 | const pid_t gpid = task_pid_nr(current); | ||
67 | static const int tomoyo_buffer_len = 4096; | ||
68 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | ||
69 | pid_t ppid; | ||
70 | if (!buffer) | ||
71 | return NULL; | ||
72 | { | ||
73 | struct timeval tv; | ||
74 | do_gettimeofday(&tv); | ||
75 | tomoyo_convert_time(tv.tv_sec, &stamp); | ||
76 | } | ||
77 | rcu_read_lock(); | ||
78 | ppid = task_tgid_vnr(current->real_parent); | ||
79 | rcu_read_unlock(); | ||
80 | snprintf(buffer, tomoyo_buffer_len - 1, | ||
81 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " | ||
82 | "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " | ||
83 | "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " | ||
84 | "fsuid=%u fsgid=%u }", | ||
85 | stamp.year, stamp.month, stamp.day, stamp.hour, | ||
86 | stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode], | ||
87 | tomoyo_yesno(r->granted), gpid, task_tgid_vnr(current), ppid, | ||
88 | current_uid(), current_gid(), current_euid(), current_egid(), | ||
89 | current_suid(), current_sgid(), current_fsuid(), | ||
90 | current_fsgid()); | ||
91 | return buffer; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * tomoyo_init_log - Allocate buffer for audit logs. | ||
96 | * | ||
97 | * @r: Pointer to "struct tomoyo_request_info". | ||
98 | * @len: Buffer size needed for @fmt and @args. | ||
99 | * @fmt: The printf()'s format string. | ||
100 | * @args: va_list structure for @fmt. | ||
101 | * | ||
102 | * Returns pointer to allocated memory. | ||
103 | * | ||
104 | * This function uses kzalloc(), so caller must kfree() if this function | ||
105 | * didn't return NULL. | ||
106 | */ | ||
107 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | ||
108 | va_list args) | ||
109 | { | ||
110 | char *buf = NULL; | ||
111 | const char *header = NULL; | ||
112 | int pos; | ||
113 | const char *domainname = tomoyo_domain()->domainname->name; | ||
114 | header = tomoyo_print_header(r); | ||
115 | if (!header) | ||
116 | return NULL; | ||
117 | /* +10 is for '\n' etc. and '\0'. */ | ||
118 | len += strlen(domainname) + strlen(header) + 10; | ||
119 | len = tomoyo_round2(len); | ||
120 | buf = kzalloc(len, GFP_NOFS); | ||
121 | if (!buf) | ||
122 | goto out; | ||
123 | len--; | ||
124 | pos = snprintf(buf, len, "%s", header); | ||
125 | pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname); | ||
126 | vsnprintf(buf + pos, len - pos, fmt, args); | ||
127 | out: | ||
128 | kfree(header); | ||
129 | return buf; | ||
130 | } | ||
131 | |||
132 | /* Wait queue for /sys/kernel/security/tomoyo/audit. */ | ||
133 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait); | ||
134 | |||
135 | /* Structure for audit log. */ | ||
136 | struct tomoyo_log { | ||
137 | struct list_head list; | ||
138 | char *log; | ||
139 | int size; | ||
140 | }; | ||
141 | |||
142 | /* The list for "struct tomoyo_log". */ | ||
143 | static LIST_HEAD(tomoyo_log); | ||
144 | |||
145 | /* Lock for "struct list_head tomoyo_log". */ | ||
146 | static DEFINE_SPINLOCK(tomoyo_log_lock); | ||
147 | |||
148 | /* Length of "stuct list_head tomoyo_log". */ | ||
149 | static unsigned int tomoyo_log_count; | ||
150 | |||
151 | /** | ||
152 | * tomoyo_get_audit - Get audit mode. | ||
153 | * | ||
154 | * @profile: Profile number. | ||
155 | * @index: Index number of functionality. | ||
156 | * @is_granted: True if granted log, false otherwise. | ||
157 | * | ||
158 | * Returns true if this request should be audited, false otherwise. | ||
159 | */ | ||
160 | static bool tomoyo_get_audit(const u8 profile, const u8 index, | ||
161 | const bool is_granted) | ||
162 | { | ||
163 | u8 mode; | ||
164 | const u8 category = TOMOYO_MAC_CATEGORY_FILE + TOMOYO_MAX_MAC_INDEX; | ||
165 | struct tomoyo_profile *p; | ||
166 | if (!tomoyo_policy_loaded) | ||
167 | return false; | ||
168 | p = tomoyo_profile(profile); | ||
169 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) | ||
170 | return false; | ||
171 | mode = p->config[index]; | ||
172 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | ||
173 | mode = p->config[category]; | ||
174 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | ||
175 | mode = p->default_config; | ||
176 | if (is_granted) | ||
177 | return mode & TOMOYO_CONFIG_WANT_GRANT_LOG; | ||
178 | return mode & TOMOYO_CONFIG_WANT_REJECT_LOG; | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * tomoyo_write_log2 - Write an audit log. | ||
183 | * | ||
184 | * @r: Pointer to "struct tomoyo_request_info". | ||
185 | * @len: Buffer size needed for @fmt and @args. | ||
186 | * @fmt: The printf()'s format string. | ||
187 | * @args: va_list structure for @fmt. | ||
188 | * | ||
189 | * Returns nothing. | ||
190 | */ | ||
191 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | ||
192 | va_list args) | ||
193 | { | ||
194 | char *buf; | ||
195 | struct tomoyo_log *entry; | ||
196 | bool quota_exceeded = false; | ||
197 | if (!tomoyo_get_audit(r->profile, r->type, r->granted)) | ||
198 | goto out; | ||
199 | buf = tomoyo_init_log(r, len, fmt, args); | ||
200 | if (!buf) | ||
201 | goto out; | ||
202 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | ||
203 | if (!entry) { | ||
204 | kfree(buf); | ||
205 | goto out; | ||
206 | } | ||
207 | entry->log = buf; | ||
208 | len = tomoyo_round2(strlen(buf) + 1); | ||
209 | /* | ||
210 | * The entry->size is used for memory quota checks. | ||
211 | * Don't go beyond strlen(entry->log). | ||
212 | */ | ||
213 | entry->size = len + tomoyo_round2(sizeof(*entry)); | ||
214 | spin_lock(&tomoyo_log_lock); | ||
215 | if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] && | ||
216 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >= | ||
217 | tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) { | ||
218 | quota_exceeded = true; | ||
219 | } else { | ||
220 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size; | ||
221 | list_add_tail(&entry->list, &tomoyo_log); | ||
222 | tomoyo_log_count++; | ||
223 | } | ||
224 | spin_unlock(&tomoyo_log_lock); | ||
225 | if (quota_exceeded) { | ||
226 | kfree(buf); | ||
227 | kfree(entry); | ||
228 | goto out; | ||
229 | } | ||
230 | wake_up(&tomoyo_log_wait); | ||
231 | out: | ||
232 | return; | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * tomoyo_write_log - Write an audit log. | ||
237 | * | ||
238 | * @r: Pointer to "struct tomoyo_request_info". | ||
239 | * @fmt: The printf()'s format string, followed by parameters. | ||
240 | * | ||
241 | * Returns nothing. | ||
242 | */ | ||
243 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
244 | { | ||
245 | va_list args; | ||
246 | int len; | ||
247 | va_start(args, fmt); | ||
248 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | ||
249 | va_end(args); | ||
250 | va_start(args, fmt); | ||
251 | tomoyo_write_log2(r, len, fmt, args); | ||
252 | va_end(args); | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * tomoyo_read_log - Read an audit log. | ||
257 | * | ||
258 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
259 | * | ||
260 | * Returns nothing. | ||
261 | */ | ||
262 | void tomoyo_read_log(struct tomoyo_io_buffer *head) | ||
263 | { | ||
264 | struct tomoyo_log *ptr = NULL; | ||
265 | if (head->r.w_pos) | ||
266 | return; | ||
267 | kfree(head->read_buf); | ||
268 | head->read_buf = NULL; | ||
269 | spin_lock(&tomoyo_log_lock); | ||
270 | if (!list_empty(&tomoyo_log)) { | ||
271 | ptr = list_entry(tomoyo_log.next, typeof(*ptr), list); | ||
272 | list_del(&ptr->list); | ||
273 | tomoyo_log_count--; | ||
274 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size; | ||
275 | } | ||
276 | spin_unlock(&tomoyo_log_lock); | ||
277 | if (ptr) { | ||
278 | head->read_buf = ptr->log; | ||
279 | head->r.w[head->r.w_pos++] = head->read_buf; | ||
280 | kfree(ptr); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * tomoyo_poll_log - Wait for an audit log. | ||
286 | * | ||
287 | * @file: Pointer to "struct file". | ||
288 | * @wait: Pointer to "poll_table". | ||
289 | * | ||
290 | * Returns POLLIN | POLLRDNORM when ready to read an audit log. | ||
291 | */ | ||
292 | int tomoyo_poll_log(struct file *file, poll_table *wait) | ||
293 | { | ||
294 | if (tomoyo_log_count) | ||
295 | return POLLIN | POLLRDNORM; | ||
296 | poll_wait(file, &tomoyo_log_wait, wait); | ||
297 | if (tomoyo_log_count) | ||
298 | return POLLIN | POLLRDNORM; | ||
299 | return 0; | ||
300 | } | ||