aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2008-11-11 05:48:18 -0500
committerJames Morris <jmorris@namei.org>2008-11-11 05:48:18 -0500
commit3fc689e96c0c90b6fede5946d6c31075e9464f69 (patch)
tree5e59b6c607eb595ababa74bad18787cfa49b16e9
parent851f7ff56d9c21272f289dd85fb3f1b6cf7a6e10 (diff)
Any time fcaps or a setuid app under SECURE_NOROOT is used to result in a
non-zero pE we will crate a new audit record which contains the entire set of known information about the executable in question, fP, fI, fE, fversion and includes the process's pE, pI, pP. Before and after the bprm capability are applied. This record type will only be emitted from execve syscalls. an example of making ping use fcaps instead of setuid: setcap "cat_net_raw+pe" /bin/ping type=SYSCALL msg=audit(1225742021.015:236): arch=c000003e syscall=59 success=yes exit=0 a0=1457f30 a1=14606b0 a2=1463940 a3=321b770a70 items=2 ppid=2929 pid=2963 auid=0 uid=500 gid=500 euid=500 suid=500 fsuid=500 egid=500 sgid=500 fsgid=500 tty=pts0 ses=3 comm="ping" exe="/bin/ping" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) type=UNKNOWN[1321] msg=audit(1225742021.015:236): fver=2 fp=0000000000002000 fi=0000000000000000 fe=1 old_pp=0000000000000000 old_pi=0000000000000000 old_pe=0000000000000000 new_pp=0000000000002000 new_pi=0000000000000000 new_pe=0000000000002000 type=EXECVE msg=audit(1225742021.015:236): argc=2 a0="ping" a1="127.0.0.1" type=CWD msg=audit(1225742021.015:236): cwd="/home/test" type=PATH msg=audit(1225742021.015:236): item=0 name="/bin/ping" inode=49256 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ping_exec_t:s0 cap_fp=0000000000002000 cap_fe=1 cap_fver=2 type=PATH msg=audit(1225742021.015:236): item=1 name=(null) inode=507915 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0 Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--include/linux/audit.h26
-rw-r--r--kernel/auditsc.c68
-rw-r--r--security/commoncap.c23
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
452extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout); 453extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
453extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification); 454extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
454extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); 455extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
456extern void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE);
455 457
456static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) 458static 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 */
523static 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
504extern int audit_n_rules; 529extern int audit_n_rules;
505extern int audit_signals; 530extern 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
199struct 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
199struct audit_tree_refs { 207struct 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 */
2539void __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
377void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) 378void 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}