diff options
-rw-r--r-- | kernel/audit.c | 216 |
1 files changed, 157 insertions, 59 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, |