diff options
-rw-r--r-- | include/linux/audit.h | 26 | ||||
-rw-r--r-- | kernel/auditsc.c | 68 | ||||
-rw-r--r-- | security/commoncap.c | 23 |
3 files changed, 116 insertions, 1 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 6272a395d43c..8cfb9feb2a05 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -99,6 +99,7 @@ | |||
99 | #define AUDIT_OBJ_PID 1318 /* ptrace target */ | 99 | #define AUDIT_OBJ_PID 1318 /* ptrace target */ |
100 | #define AUDIT_TTY 1319 /* Input on an administrative TTY */ | 100 | #define AUDIT_TTY 1319 /* Input on an administrative TTY */ |
101 | #define AUDIT_EOE 1320 /* End of multi-record event */ | 101 | #define AUDIT_EOE 1320 /* End of multi-record event */ |
102 | #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ | ||
102 | 103 | ||
103 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 104 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
104 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 105 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
@@ -452,6 +453,7 @@ extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_pr | |||
452 | extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout); | 453 | extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout); |
453 | extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification); | 454 | extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification); |
454 | extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); | 455 | extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); |
456 | extern void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE); | ||
455 | 457 | ||
456 | static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) | 458 | static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) |
457 | { | 459 | { |
@@ -501,6 +503,29 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) | |||
501 | return __audit_mq_getsetattr(mqdes, mqstat); | 503 | return __audit_mq_getsetattr(mqdes, mqstat); |
502 | return 0; | 504 | return 0; |
503 | } | 505 | } |
506 | |||
507 | /* | ||
508 | * ieieeeeee, an audit function without a return code! | ||
509 | * | ||
510 | * This function might fail! I decided that it didn't matter. We are too late | ||
511 | * to fail the syscall and the information isn't REQUIRED for any purpose. It's | ||
512 | * just nice to have. We should be able to look at past audit logs to figure | ||
513 | * out this process's current cap set along with the fcaps from the PATH record | ||
514 | * and use that to come up with the final set. Yeah, its ugly, but all the info | ||
515 | * is still in the audit log. So I'm not going to bother mentioning we failed | ||
516 | * if we couldn't allocate memory. | ||
517 | * | ||
518 | * If someone changes their mind they could create the aux record earlier and | ||
519 | * then search here and use that earlier allocation. But I don't wanna. | ||
520 | * | ||
521 | * -Eric | ||
522 | */ | ||
523 | static inline void audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE) | ||
524 | { | ||
525 | if (unlikely(!audit_dummy_context())) | ||
526 | __audit_log_bprm_fcaps(bprm, pP, pE); | ||
527 | } | ||
528 | |||
504 | extern int audit_n_rules; | 529 | extern int audit_n_rules; |
505 | extern int audit_signals; | 530 | extern int audit_signals; |
506 | #else | 531 | #else |
@@ -532,6 +557,7 @@ extern int audit_signals; | |||
532 | #define audit_mq_timedreceive(d,l,p,t) ({ 0; }) | 557 | #define audit_mq_timedreceive(d,l,p,t) ({ 0; }) |
533 | #define audit_mq_notify(d,n) ({ 0; }) | 558 | #define audit_mq_notify(d,n) ({ 0; }) |
534 | #define audit_mq_getsetattr(d,s) ({ 0; }) | 559 | #define audit_mq_getsetattr(d,s) ({ 0; }) |
560 | #define audit_log_bprm_fcaps(b, p, e) do { ; } while (0) | ||
535 | #define audit_ptrace(t) ((void)0) | 561 | #define audit_ptrace(t) ((void)0) |
536 | #define audit_n_rules 0 | 562 | #define audit_n_rules 0 |
537 | #define audit_signals 0 | 563 | #define audit_signals 0 |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index de7e9bcba9ae..3229cd4206f5 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -196,6 +196,14 @@ struct audit_aux_data_pids { | |||
196 | int pid_count; | 196 | int pid_count; |
197 | }; | 197 | }; |
198 | 198 | ||
199 | struct audit_aux_data_bprm_fcaps { | ||
200 | struct audit_aux_data d; | ||
201 | struct audit_cap_data fcap; | ||
202 | unsigned int fcap_ver; | ||
203 | struct audit_cap_data old_pcap; | ||
204 | struct audit_cap_data new_pcap; | ||
205 | }; | ||
206 | |||
199 | struct audit_tree_refs { | 207 | struct audit_tree_refs { |
200 | struct audit_tree_refs *next; | 208 | struct audit_tree_refs *next; |
201 | struct audit_chunk *c[31]; | 209 | struct audit_chunk *c[31]; |
@@ -1375,6 +1383,20 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1375 | audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); | 1383 | audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); |
1376 | break; } | 1384 | break; } |
1377 | 1385 | ||
1386 | case AUDIT_BPRM_FCAPS: { | ||
1387 | struct audit_aux_data_bprm_fcaps *axs = (void *)aux; | ||
1388 | audit_log_format(ab, "fver=%x", axs->fcap_ver); | ||
1389 | audit_log_cap(ab, "fp", &axs->fcap.permitted); | ||
1390 | audit_log_cap(ab, "fi", &axs->fcap.inheritable); | ||
1391 | audit_log_format(ab, " fe=%d", axs->fcap.fE); | ||
1392 | audit_log_cap(ab, "old_pp", &axs->old_pcap.permitted); | ||
1393 | audit_log_cap(ab, "old_pi", &axs->old_pcap.inheritable); | ||
1394 | audit_log_cap(ab, "old_pe", &axs->old_pcap.effective); | ||
1395 | audit_log_cap(ab, "new_pp", &axs->new_pcap.permitted); | ||
1396 | audit_log_cap(ab, "new_pi", &axs->new_pcap.inheritable); | ||
1397 | audit_log_cap(ab, "new_pe", &axs->new_pcap.effective); | ||
1398 | break; } | ||
1399 | |||
1378 | } | 1400 | } |
1379 | audit_log_end(ab); | 1401 | audit_log_end(ab); |
1380 | } | 1402 | } |
@@ -2502,6 +2524,52 @@ int __audit_signal_info(int sig, struct task_struct *t) | |||
2502 | } | 2524 | } |
2503 | 2525 | ||
2504 | /** | 2526 | /** |
2527 | * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps | ||
2528 | * @bprm pointer to the bprm being processed | ||
2529 | * @caps the caps read from the disk | ||
2530 | * | ||
2531 | * Simply check if the proc already has the caps given by the file and if not | ||
2532 | * store the priv escalation info for later auditing at the end of the syscall | ||
2533 | * | ||
2534 | * this can fail and we don't care. See the note in audit.h for | ||
2535 | * audit_log_bprm_fcaps() for my explaination.... | ||
2536 | * | ||
2537 | * -Eric | ||
2538 | */ | ||
2539 | void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE) | ||
2540 | { | ||
2541 | struct audit_aux_data_bprm_fcaps *ax; | ||
2542 | struct audit_context *context = current->audit_context; | ||
2543 | struct cpu_vfs_cap_data vcaps; | ||
2544 | struct dentry *dentry; | ||
2545 | |||
2546 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | ||
2547 | if (!ax) | ||
2548 | return; | ||
2549 | |||
2550 | ax->d.type = AUDIT_BPRM_FCAPS; | ||
2551 | ax->d.next = context->aux; | ||
2552 | context->aux = (void *)ax; | ||
2553 | |||
2554 | dentry = dget(bprm->file->f_dentry); | ||
2555 | get_vfs_caps_from_disk(dentry, &vcaps); | ||
2556 | dput(dentry); | ||
2557 | |||
2558 | ax->fcap.permitted = vcaps.permitted; | ||
2559 | ax->fcap.inheritable = vcaps.inheritable; | ||
2560 | ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); | ||
2561 | ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; | ||
2562 | |||
2563 | ax->old_pcap.permitted = *pP; | ||
2564 | ax->old_pcap.inheritable = current->cap_inheritable; | ||
2565 | ax->old_pcap.effective = *pE; | ||
2566 | |||
2567 | ax->new_pcap.permitted = current->cap_permitted; | ||
2568 | ax->new_pcap.inheritable = current->cap_inheritable; | ||
2569 | ax->new_pcap.effective = current->cap_effective; | ||
2570 | } | ||
2571 | |||
2572 | /** | ||
2505 | * audit_core_dumps - record information about processes that end abnormally | 2573 | * audit_core_dumps - record information about processes that end abnormally |
2506 | * @signr: signal value | 2574 | * @signr: signal value |
2507 | * | 2575 | * |
diff --git a/security/commoncap.c b/security/commoncap.c index d7eff5797b91..d45393380997 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/capability.h> | 10 | #include <linux/capability.h> |
11 | #include <linux/audit.h> | ||
11 | #include <linux/module.h> | 12 | #include <linux/module.h> |
12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
@@ -376,6 +377,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm) | |||
376 | 377 | ||
377 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | 378 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) |
378 | { | 379 | { |
380 | kernel_cap_t pP = current->cap_permitted; | ||
381 | kernel_cap_t pE = current->cap_effective; | ||
382 | |||
379 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || | 383 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || |
380 | !cap_issubset(bprm->cap_post_exec_permitted, | 384 | !cap_issubset(bprm->cap_post_exec_permitted, |
381 | current->cap_permitted)) { | 385 | current->cap_permitted)) { |
@@ -409,7 +413,24 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
409 | cap_clear(current->cap_effective); | 413 | cap_clear(current->cap_effective); |
410 | } | 414 | } |
411 | 415 | ||
412 | /* AUD: Audit candidate if current->cap_effective is set */ | 416 | /* |
417 | * Audit candidate if current->cap_effective is set | ||
418 | * | ||
419 | * We do not bother to audit if 3 things are true: | ||
420 | * 1) cap_effective has all caps | ||
421 | * 2) we are root | ||
422 | * 3) root is supposed to have all caps (SECURE_NOROOT) | ||
423 | * Since this is just a normal root execing a process. | ||
424 | * | ||
425 | * Number 1 above might fail if you don't have a full bset, but I think | ||
426 | * that is interesting information to audit. | ||
427 | */ | ||
428 | if (!cap_isclear(current->cap_effective)) { | ||
429 | if (!cap_issubset(CAP_FULL_SET, current->cap_effective) || | ||
430 | (bprm->e_uid != 0) || (current->uid != 0) || | ||
431 | issecure(SECURE_NOROOT)) | ||
432 | audit_log_bprm_fcaps(bprm, &pP, &pE); | ||
433 | } | ||
413 | 434 | ||
414 | current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); | 435 | current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
415 | } | 436 | } |