diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-19 16:29:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-19 16:29:54 -0500 |
commit | cb4aaf46c0283dd79ab2e8b8b165c0bf13ab6194 (patch) | |
tree | 2e01de06d4740300cfcfbb9e9f9fd3b7078dd3ce /kernel | |
parent | 874ff01bd9183ad16495acfd54e93a619d12b8b5 (diff) | |
parent | db3495099d3d52854b13874905af6e40a91f4721 (diff) |
Merge branch 'audit.b37' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current
* 'audit.b37' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current:
[PATCH] AUDIT_FD_PAIR
[PATCH] audit config lockdown
[PATCH] minor update to rule add/delete messages (ver 2)
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.c | 216 | ||||
-rw-r--r-- | kernel/auditfilter.c | 9 | ||||
-rw-r--r-- | kernel/auditsc.c | 40 |
3 files changed, 202 insertions, 63 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index d9b690ac684b..76c9a11b72d6 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Gateway between the kernel (e.g., selinux) and the user-space audit daemon. | 2 | * Gateway between the kernel (e.g., selinux) and the user-space audit daemon. |
3 | * System-call specific features have moved to auditsc.c | 3 | * System-call specific features have moved to auditsc.c |
4 | * | 4 | * |
5 | * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. | 5 | * Copyright 2003-2007 Red Hat Inc., Durham, North Carolina. |
6 | * All Rights Reserved. | 6 | * All Rights Reserved. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -65,7 +65,9 @@ | |||
65 | * (Initialization happens after skb_init is called.) */ | 65 | * (Initialization happens after skb_init is called.) */ |
66 | static int audit_initialized; | 66 | static int audit_initialized; |
67 | 67 | ||
68 | /* No syscall auditing will take place unless audit_enabled != 0. */ | 68 | /* 0 - no auditing |
69 | * 1 - auditing enabled | ||
70 | * 2 - auditing enabled and configuration is locked/unchangeable. */ | ||
69 | int audit_enabled; | 71 | int audit_enabled; |
70 | 72 | ||
71 | /* Default state when kernel boots without any parameters. */ | 73 | /* Default state when kernel boots without any parameters. */ |
@@ -239,102 +241,150 @@ void audit_log_lost(const char *message) | |||
239 | 241 | ||
240 | static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid) | 242 | static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid) |
241 | { | 243 | { |
242 | int old = audit_rate_limit; | 244 | int res, rc = 0, old = audit_rate_limit; |
245 | |||
246 | /* check if we are locked */ | ||
247 | if (audit_enabled == 2) | ||
248 | res = 0; | ||
249 | else | ||
250 | res = 1; | ||
243 | 251 | ||
244 | if (sid) { | 252 | if (sid) { |
245 | char *ctx = NULL; | 253 | char *ctx = NULL; |
246 | u32 len; | 254 | u32 len; |
247 | int rc; | 255 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
248 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
249 | return rc; | ||
250 | else | ||
251 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 256 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
252 | "audit_rate_limit=%d old=%d by auid=%u subj=%s", | 257 | "audit_rate_limit=%d old=%d by auid=%u" |
253 | limit, old, loginuid, ctx); | 258 | " subj=%s res=%d", |
254 | kfree(ctx); | 259 | limit, old, loginuid, ctx, res); |
255 | } else | 260 | kfree(ctx); |
256 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 261 | } else |
257 | "audit_rate_limit=%d old=%d by auid=%u", | 262 | res = 0; /* Something weird, deny request */ |
258 | limit, old, loginuid); | 263 | } |
259 | audit_rate_limit = limit; | 264 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
260 | return 0; | 265 | "audit_rate_limit=%d old=%d by auid=%u res=%d", |
266 | limit, old, loginuid, res); | ||
267 | |||
268 | /* If we are allowed, make the change */ | ||
269 | if (res == 1) | ||
270 | audit_rate_limit = limit; | ||
271 | /* Not allowed, update reason */ | ||
272 | else if (rc == 0) | ||
273 | rc = -EPERM; | ||
274 | return rc; | ||
261 | } | 275 | } |
262 | 276 | ||
263 | static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) | 277 | static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid) |
264 | { | 278 | { |
265 | int old = audit_backlog_limit; | 279 | int res, rc = 0, old = audit_backlog_limit; |
280 | |||
281 | /* check if we are locked */ | ||
282 | if (audit_enabled == 2) | ||
283 | res = 0; | ||
284 | else | ||
285 | res = 1; | ||
266 | 286 | ||
267 | if (sid) { | 287 | if (sid) { |
268 | char *ctx = NULL; | 288 | char *ctx = NULL; |
269 | u32 len; | 289 | u32 len; |
270 | int rc; | 290 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
271 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
272 | return rc; | ||
273 | else | ||
274 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 291 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
275 | "audit_backlog_limit=%d old=%d by auid=%u subj=%s", | 292 | "audit_backlog_limit=%d old=%d by auid=%u" |
276 | limit, old, loginuid, ctx); | 293 | " subj=%s res=%d", |
277 | kfree(ctx); | 294 | limit, old, loginuid, ctx, res); |
278 | } else | 295 | kfree(ctx); |
279 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 296 | } else |
280 | "audit_backlog_limit=%d old=%d by auid=%u", | 297 | res = 0; /* Something weird, deny request */ |
281 | limit, old, loginuid); | 298 | } |
282 | audit_backlog_limit = limit; | 299 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
283 | return 0; | 300 | "audit_backlog_limit=%d old=%d by auid=%u res=%d", |
301 | limit, old, loginuid, res); | ||
302 | |||
303 | /* If we are allowed, make the change */ | ||
304 | if (res == 1) | ||
305 | audit_backlog_limit = limit; | ||
306 | /* Not allowed, update reason */ | ||
307 | else if (rc == 0) | ||
308 | rc = -EPERM; | ||
309 | return rc; | ||
284 | } | 310 | } |
285 | 311 | ||
286 | static int audit_set_enabled(int state, uid_t loginuid, u32 sid) | 312 | static int audit_set_enabled(int state, uid_t loginuid, u32 sid) |
287 | { | 313 | { |
288 | int old = audit_enabled; | 314 | int res, rc = 0, old = audit_enabled; |
289 | 315 | ||
290 | if (state != 0 && state != 1) | 316 | if (state < 0 || state > 2) |
291 | return -EINVAL; | 317 | return -EINVAL; |
292 | 318 | ||
319 | /* check if we are locked */ | ||
320 | if (audit_enabled == 2) | ||
321 | res = 0; | ||
322 | else | ||
323 | res = 1; | ||
324 | |||
293 | if (sid) { | 325 | if (sid) { |
294 | char *ctx = NULL; | 326 | char *ctx = NULL; |
295 | u32 len; | 327 | u32 len; |
296 | int rc; | 328 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
297 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
298 | return rc; | ||
299 | else | ||
300 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 329 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
301 | "audit_enabled=%d old=%d by auid=%u subj=%s", | 330 | "audit_enabled=%d old=%d by auid=%u" |
302 | state, old, loginuid, ctx); | 331 | " subj=%s res=%d", |
303 | kfree(ctx); | 332 | state, old, loginuid, ctx, res); |
304 | } else | 333 | kfree(ctx); |
305 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 334 | } else |
306 | "audit_enabled=%d old=%d by auid=%u", | 335 | res = 0; /* Something weird, deny request */ |
307 | state, old, loginuid); | 336 | } |
308 | audit_enabled = state; | 337 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
309 | return 0; | 338 | "audit_enabled=%d old=%d by auid=%u res=%d", |
339 | state, old, loginuid, res); | ||
340 | |||
341 | /* If we are allowed, make the change */ | ||
342 | if (res == 1) | ||
343 | audit_enabled = state; | ||
344 | /* Not allowed, update reason */ | ||
345 | else if (rc == 0) | ||
346 | rc = -EPERM; | ||
347 | return rc; | ||
310 | } | 348 | } |
311 | 349 | ||
312 | static int audit_set_failure(int state, uid_t loginuid, u32 sid) | 350 | static int audit_set_failure(int state, uid_t loginuid, u32 sid) |
313 | { | 351 | { |
314 | int old = audit_failure; | 352 | int res, rc = 0, old = audit_failure; |
315 | 353 | ||
316 | if (state != AUDIT_FAIL_SILENT | 354 | if (state != AUDIT_FAIL_SILENT |
317 | && state != AUDIT_FAIL_PRINTK | 355 | && state != AUDIT_FAIL_PRINTK |
318 | && state != AUDIT_FAIL_PANIC) | 356 | && state != AUDIT_FAIL_PANIC) |
319 | return -EINVAL; | 357 | return -EINVAL; |
320 | 358 | ||
359 | /* check if we are locked */ | ||
360 | if (audit_enabled == 2) | ||
361 | res = 0; | ||
362 | else | ||
363 | res = 1; | ||
364 | |||
321 | if (sid) { | 365 | if (sid) { |
322 | char *ctx = NULL; | 366 | char *ctx = NULL; |
323 | u32 len; | 367 | u32 len; |
324 | int rc; | 368 | if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) { |
325 | if ((rc = selinux_sid_to_string(sid, &ctx, &len))) | ||
326 | return rc; | ||
327 | else | ||
328 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 369 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
329 | "audit_failure=%d old=%d by auid=%u subj=%s", | 370 | "audit_failure=%d old=%d by auid=%u" |
330 | state, old, loginuid, ctx); | 371 | " subj=%s res=%d", |
331 | kfree(ctx); | 372 | state, old, loginuid, ctx, res); |
332 | } else | 373 | kfree(ctx); |
333 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 374 | } else |
334 | "audit_failure=%d old=%d by auid=%u", | 375 | res = 0; /* Something weird, deny request */ |
335 | state, old, loginuid); | 376 | } |
336 | audit_failure = state; | 377 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
337 | return 0; | 378 | "audit_failure=%d old=%d by auid=%u res=%d", |
379 | state, old, loginuid, res); | ||
380 | |||
381 | /* If we are allowed, make the change */ | ||
382 | if (res == 1) | ||
383 | audit_failure = state; | ||
384 | /* Not allowed, update reason */ | ||
385 | else if (rc == 0) | ||
386 | rc = -EPERM; | ||
387 | return rc; | ||
338 | } | 388 | } |
339 | 389 | ||
340 | static int kauditd_thread(void *dummy) | 390 | static int kauditd_thread(void *dummy) |
@@ -599,6 +649,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
599 | case AUDIT_DEL: | 649 | case AUDIT_DEL: |
600 | if (nlmsg_len(nlh) < sizeof(struct audit_rule)) | 650 | if (nlmsg_len(nlh) < sizeof(struct audit_rule)) |
601 | return -EINVAL; | 651 | return -EINVAL; |
652 | if (audit_enabled == 2) { | ||
653 | ab = audit_log_start(NULL, GFP_KERNEL, | ||
654 | AUDIT_CONFIG_CHANGE); | ||
655 | if (ab) { | ||
656 | audit_log_format(ab, | ||
657 | "pid=%d uid=%u auid=%u", | ||
658 | pid, uid, loginuid); | ||
659 | if (sid) { | ||
660 | if (selinux_sid_to_string( | ||
661 | sid, &ctx, &len)) { | ||
662 | audit_log_format(ab, | ||
663 | " ssid=%u", sid); | ||
664 | /* Maybe call audit_panic? */ | ||
665 | } else | ||
666 | audit_log_format(ab, | ||
667 | " subj=%s", ctx); | ||
668 | kfree(ctx); | ||
669 | } | ||
670 | audit_log_format(ab, " audit_enabled=%d res=0", | ||
671 | audit_enabled); | ||
672 | audit_log_end(ab); | ||
673 | } | ||
674 | return -EPERM; | ||
675 | } | ||
602 | /* fallthrough */ | 676 | /* fallthrough */ |
603 | case AUDIT_LIST: | 677 | case AUDIT_LIST: |
604 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, | 678 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, |
@@ -609,6 +683,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
609 | case AUDIT_DEL_RULE: | 683 | case AUDIT_DEL_RULE: |
610 | if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) | 684 | if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) |
611 | return -EINVAL; | 685 | return -EINVAL; |
686 | if (audit_enabled == 2) { | ||
687 | ab = audit_log_start(NULL, GFP_KERNEL, | ||
688 | AUDIT_CONFIG_CHANGE); | ||
689 | if (ab) { | ||
690 | audit_log_format(ab, | ||
691 | "pid=%d uid=%u auid=%u", | ||
692 | pid, uid, loginuid); | ||
693 | if (sid) { | ||
694 | if (selinux_sid_to_string( | ||
695 | sid, &ctx, &len)) { | ||
696 | audit_log_format(ab, | ||
697 | " ssid=%u", sid); | ||
698 | /* Maybe call audit_panic? */ | ||
699 | } else | ||
700 | audit_log_format(ab, | ||
701 | " subj=%s", ctx); | ||
702 | kfree(ctx); | ||
703 | } | ||
704 | audit_log_format(ab, " audit_enabled=%d res=0", | ||
705 | audit_enabled); | ||
706 | audit_log_end(ab); | ||
707 | } | ||
708 | return -EPERM; | ||
709 | } | ||
612 | /* fallthrough */ | 710 | /* fallthrough */ |
613 | case AUDIT_LIST_RULES: | 711 | case AUDIT_LIST_RULES: |
614 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, | 712 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 87865f8b4ce3..3749193aed8c 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -937,9 +937,10 @@ static void audit_update_watch(struct audit_parent *parent, | |||
937 | } | 937 | } |
938 | 938 | ||
939 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 939 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
940 | audit_log_format(ab, "audit updated rules specifying path="); | 940 | audit_log_format(ab, "op=updated rules specifying path="); |
941 | audit_log_untrustedstring(ab, owatch->path); | 941 | audit_log_untrustedstring(ab, owatch->path); |
942 | audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino); | 942 | audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino); |
943 | audit_log_format(ab, " list=%d res=1", r->listnr); | ||
943 | audit_log_end(ab); | 944 | audit_log_end(ab); |
944 | 945 | ||
945 | audit_remove_watch(owatch); | 946 | audit_remove_watch(owatch); |
@@ -969,14 +970,14 @@ static void audit_remove_parent_watches(struct audit_parent *parent) | |||
969 | e = container_of(r, struct audit_entry, rule); | 970 | e = container_of(r, struct audit_entry, rule); |
970 | 971 | ||
971 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 972 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
972 | audit_log_format(ab, "audit implicitly removed rule path="); | 973 | audit_log_format(ab, "op=remove rule path="); |
973 | audit_log_untrustedstring(ab, w->path); | 974 | audit_log_untrustedstring(ab, w->path); |
974 | if (r->filterkey) { | 975 | if (r->filterkey) { |
975 | audit_log_format(ab, " key="); | 976 | audit_log_format(ab, " key="); |
976 | audit_log_untrustedstring(ab, r->filterkey); | 977 | audit_log_untrustedstring(ab, r->filterkey); |
977 | } else | 978 | } else |
978 | audit_log_format(ab, " key=(null)"); | 979 | audit_log_format(ab, " key=(null)"); |
979 | audit_log_format(ab, " list=%d", r->listnr); | 980 | audit_log_format(ab, " list=%d res=1", r->listnr); |
980 | audit_log_end(ab); | 981 | audit_log_end(ab); |
981 | 982 | ||
982 | list_del(&r->rlist); | 983 | list_del(&r->rlist); |
@@ -1410,7 +1411,7 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action, | |||
1410 | audit_log_format(ab, " subj=%s", ctx); | 1411 | audit_log_format(ab, " subj=%s", ctx); |
1411 | kfree(ctx); | 1412 | kfree(ctx); |
1412 | } | 1413 | } |
1413 | audit_log_format(ab, " %s rule key=", action); | 1414 | audit_log_format(ab, " op=%s rule key=", action); |
1414 | if (rule->filterkey) | 1415 | if (rule->filterkey) |
1415 | audit_log_untrustedstring(ab, rule->filterkey); | 1416 | audit_log_untrustedstring(ab, rule->filterkey); |
1416 | else | 1417 | else |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 298897559ca4..359955800dd2 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -170,6 +170,11 @@ struct audit_aux_data_sockaddr { | |||
170 | char a[0]; | 170 | char a[0]; |
171 | }; | 171 | }; |
172 | 172 | ||
173 | struct audit_aux_data_fd_pair { | ||
174 | struct audit_aux_data d; | ||
175 | int fd[2]; | ||
176 | }; | ||
177 | |||
173 | struct audit_aux_data_path { | 178 | struct audit_aux_data_path { |
174 | struct audit_aux_data d; | 179 | struct audit_aux_data d; |
175 | struct dentry *dentry; | 180 | struct dentry *dentry; |
@@ -961,6 +966,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
961 | audit_log_d_path(ab, "path=", axi->dentry, axi->mnt); | 966 | audit_log_d_path(ab, "path=", axi->dentry, axi->mnt); |
962 | break; } | 967 | break; } |
963 | 968 | ||
969 | case AUDIT_FD_PAIR: { | ||
970 | struct audit_aux_data_fd_pair *axs = (void *)aux; | ||
971 | audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); | ||
972 | break; } | ||
973 | |||
964 | } | 974 | } |
965 | audit_log_end(ab); | 975 | audit_log_end(ab); |
966 | } | 976 | } |
@@ -1815,6 +1825,36 @@ int audit_socketcall(int nargs, unsigned long *args) | |||
1815 | } | 1825 | } |
1816 | 1826 | ||
1817 | /** | 1827 | /** |
1828 | * __audit_fd_pair - record audit data for pipe and socketpair | ||
1829 | * @fd1: the first file descriptor | ||
1830 | * @fd2: the second file descriptor | ||
1831 | * | ||
1832 | * Returns 0 for success or NULL context or < 0 on error. | ||
1833 | */ | ||
1834 | int __audit_fd_pair(int fd1, int fd2) | ||
1835 | { | ||
1836 | struct audit_context *context = current->audit_context; | ||
1837 | struct audit_aux_data_fd_pair *ax; | ||
1838 | |||
1839 | if (likely(!context)) { | ||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | ||
1844 | if (!ax) { | ||
1845 | return -ENOMEM; | ||
1846 | } | ||
1847 | |||
1848 | ax->fd[0] = fd1; | ||
1849 | ax->fd[1] = fd2; | ||
1850 | |||
1851 | ax->d.type = AUDIT_FD_PAIR; | ||
1852 | ax->d.next = context->aux; | ||
1853 | context->aux = (void *)ax; | ||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1857 | /** | ||
1818 | * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto | 1858 | * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto |
1819 | * @len: data length in user space | 1859 | * @len: data length in user space |
1820 | * @a: data address in kernel space | 1860 | * @a: data address in kernel space |