Audit: save audit_backlog_limit audit messages in case auditd comes back
Eric Paris
maintainerPATCH 1/1 Audit: save audit_backlog_limit audit messages in case auditd comes back
This patch causes the kernel audit subsystem to store up to audit_backlog_limit messages for use by auditd if it ever appears sometime in the future in userspace. This is useful to collect audit messages during bootup and even when auditd is stopped. This is NOT a reliable mechanism, it does not ever call audit_panic, nor should it. The messages are still sent to printk/syslog as usual and if too many messages appear they will be silently discarded.
If auditd never starts the kernel will hold by default up to 64 messages in memory forever.
---
[root@dhcp231-146 ~]# echo > /var/log/audit/audit.log [root@dhcp231-146 ~]# service auditd stop
Stopping auditd: [ OK ]
[root@dhcp231-146 ~]# load_policy [root@dhcp231-146 ~]# cat /var/log/audit/audit.log
type=DAEMON_END msg=audit(1206653123.111:2388): auditd normal halt, sending auid=0 pid=6006 subj=unconfined_u:system_r:initrc_t:s0 res=success [root@dhcp231-146 ~]# service auditd start
Starting auditd: [ OK ]
[root@dhcp231-146 ~]# cat /var/log/audit/audit.log
type=DAEMON_END msg=audit(1206653123.111:2388): auditd normal halt, sending auid=0 pid=6006 subj=unconfined_u:system_r:initrc_t:s0 res=success
type=DAEMON_START msg=audit(1206653139.737:8211): auditd start, ver=1.6.9 format=raw kernel=2.6.25-rc7 auid=0 pid=6031 res=success
type=CONFIG_CHANGE msg=audit(1206653123.154:26): audit_pid=0 old=1789 by auid=4294967295 subj=system_u:system_r:auditd_t:s0 res=1
type=MAC_POLICY_LOAD msg=audit(1206653127.614:27): policy loaded auid=0 ses=2
type=SYSCALL msg=audit(1206653127.614:27): arch=c000003e syscall=1 success=yes exit=3758310 a0=4 a1=7f25dd44d000 a2=3958e6 a3=7fffeae26ee0 items=0 ppid=5418 pid=6019 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="load_policy" exe="/usr/sbin/load_policy" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) type=USER_AVC msg=audit(1206653130.800:28): user pid=1803 uid=81 auid=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: received policyload notice (seqno=2) : exe="?" (sauid=81, hostname=?, addr=?, terminal=?)'
type=CONFIG_CHANGE msg=audit(1206653139.738:29): audit_pid=6031 old=0 by auid=0 subj=unconfined_u:system_r:auditd_t:s0 res=1
type=CONFIG_CHANGE msg=audit(1206653139.839:30): audit_enabled=1 old=1 by auid=0 subj=unconfined_u:system_r:auditd_t:s0 res=1
type=CONFIG_CHANGE msg=audit(1206653139.939:31): audit_backlog_limit=8192 old=8192 by auid=0 subj=unconfined_u:system_r:auditctl_t:s0 res=1
type=CONFIG_CHANGE msg=audit(1206653139.940:32): audit_failure=1 old=1 by auid=0 subj=unconfined_u:system_r:auditctl_t:s0 res=1
kernel/audit.c | 89 ++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 68 insertions(+), 21 deletions(-)
kernel/audit.c +68 -21
@@ -127,6 +127,8 @@ static int audit_freelist_count;static LIST_HEAD (audit_freelist);static struct sk_buff_head audit_skb_queue; +/* queue of skbs to send to auditd when/if it comes back */ +static struct sk_buff_head audit_skb_hold_queue;static struct task_struct *kauditd_task;static DECLARE_WAIT_QUEUE_HEAD (kauditd_wait);static DECLARE_WAIT_QUEUE_HEAD (audit_backlog_wait);
@@ -344,30 +346,70 @@ static int audit_set_failure(int state, uid_t loginuid, u32 sid) loginuid, sid); } +/* +* Queue skbs to be sent to auditd when/if it comes back. These skbs should +* already have been sent via prink/syslog and so if these messages are dropped +* it is not a huge concern. This is just nice to get audit messages during +* boot before auditd is running or messages generated while auditd is stopped +*/ +static void audit_hold_skb (struct sk_buff *skb) +{ +if (skb_queue_len (&audit_skb_hold_queue) < audit_backlog_limit) +skb_queue_tail (&audit_skb_hold_queue, skb); +else +kfree_skb (skb); +} + +static void kauditd_send_skb (struct sk_buff *skb) +{ +int err; +/* take a reference in case we can't send it and we want to hold it */ +skb_get (skb); + err =netlink_unicast (audit_sock, skb, audit_nlk_pid,0 ); +if (err <0 ) { +BUG_ON (err != -ECONNREFUSED );/* Shoudn't happen */ +printk (KERN_ERR "audit: *NO* daemon at audit_pid=%d\n" , audit_pid); +audit_log_lost ("auditd dissapeared\n" ); + audit_pid =0 ; +/* we might get lucky and get this in the next auditd */ +audit_hold_skb (skb); + }else +/* drop the extra reference if sent ok */ +kfree_skb (skb); +} +static int kauditd_thread (void *dummy) {struct sk_buff *skb;set_freezable ();while (!kthread_should_stop ()) { +/* +* if auditd just started drain the queue of messages already +* sent to syslog/printk. +*/ +if (audit_pid) { + skb =skb_dequeue (&audit_skb_hold_queue); +if (unlikely (skb)) { +while (skb && audit_pid) { +kauditd_send_skb (skb); + skb =skb_dequeue (&audit_skb_hold_queue); + } + } + } + skb =skb_dequeue (&audit_skb_queue);wake_up (&audit_backlog_wait);if (skb) { -if (audit_pid) { -int err =netlink_unicast (audit_sock, skb, audit_nlk_pid,0 ); -if (err <0 ) { -BUG_ON (err != -ECONNREFUSED );/* Shoudn't happen */ -printk (KERN_ERR "audit: *NO* daemon at audit_pid=%d\n" , audit_pid); -audit_log_lost ("auditd dissapeared\n" ); - audit_pid =0 ; - } - }else { +if (audit_pid) +kauditd_send_skb (skb); +else {if (printk_ratelimit ()) -printk (KERN_NOTICE "%s\n" , skb->data + -NLMSG_SPACE (0 )); +printk (KERN_NOTICE "%s\n" , skb->data +NLMSG_SPACE (0 ));else audit_log_lost ("printk limit exceeded\n" ); -kfree_skb (skb); + +audit_hold_skb (skb); } }else {DECLARE_WAITQUEUE (wait, current);
@@ -877,6 +919,7 @@ static int __init audit_init(void) audit_sock->sk_sndtimeo =MAX_SCHEDULE_TIMEOUT ;skb_queue_head_init (&audit_skb_queue); +skb_queue_head_init (&audit_skb_hold_queue); audit_initialized =1 ; audit_enabled = audit_default; audit_ever_enabled |= !!audit_default;
@@ -1359,19 +1402,23 @@ void audit_log_end(struct audit_buffer *ab)audit_log_lost ("rate limit exceeded" ); }else {struct nlmsghdr *nlh =nlmsg_hdr (ab->skb); + nlh->nlmsg_len = ab->skb->len -NLMSG_SPACE (0 ); +if (audit_pid) { - nlh->nlmsg_len = ab->skb->len -NLMSG_SPACE (0 );skb_queue_tail (&audit_skb_queue, ab->skb); - ab->skb =NULL ;wake_up_interruptible (&kauditd_wait); - }else if (nlh->nlmsg_type !=AUDIT_EOE ) { -if (printk_ratelimit ()) { -printk (KERN_NOTICE "type=%d %s\n" , - nlh->nlmsg_type, - ab->skb->data +NLMSG_SPACE (0 )); - }else -audit_log_lost ("printk limit exceeded\n" ); + }else { +if (nlh->nlmsg_type !=AUDIT_EOE ) { +if (printk_ratelimit ()) { +printk (KERN_NOTICE "type=%d %s\n" , + nlh->nlmsg_type, + ab->skb->data +NLMSG_SPACE (0 )); + }else +audit_log_lost ("printk limit exceeded\n" ); + } +audit_hold_skb (ab->skb); } + ab->skb =NULL ; }audit_buffer_free (ab); }
Quoted 3 lines · On Thursday 27 March 2008 17:37:44 Eric Paris wrote:
This is useful to collect audit messages during bootup and even when auditd is stopped. This is NOT a reliable mechanism, it does not ever call
audit_panic, nor should it.
Thanks Eric for working on this. We've needed this for quite a while so that we can see some of the avcs that happen during boot.
Quoted 2 lines
If auditd never starts the kernel will hold by default up to 64 messages in memory forever.
I have an idea. Maybe this behavior could be enabled if audit=1 is passed as a boot parameter. In this way, you would know that the user intended for the audit daemon to start at some point. You could then call audit panic or whatever else is normal. If no audit=1 is passed, you could just do the printk like usual and not waste memory. Would this be helpful?
Thanks,
-Steve
Eric Paris
maintainerQuoted 9 lines · Steve Grubb
Quoted 3 lines · On Thursday 27 March 2008 17:37:44 Eric Paris wrote:
This is useful to collect audit messages during bootup and even when auditd is stopped. This is NOT a reliable mechanism, it does not ever call
audit_panic, nor should it.Thanks Eric for working on this. We've needed this for quite a while so that we can see some of the avcs that happen during boot.
Quoted 8 lines
Quoted 2 lines
If auditd never starts the kernel will hold by default up to 64 messages in memory forever.
I have an idea. Maybe this behavior could be enabled if audit=1 is passed as a boot parameter. In this way, you would know that the user intended for the audit daemon to start at some point. You could then call audit panic or whatever else is normal. If no audit=1 is passed, you could just do the printk like usual and not waste memory. Would this be helpful?
I could probably do that. I also could conditionalize it on auditd ever having run. I can't imagine it is normal for auditd to be running and then stopped forever....
Anyone else see value in that situation? Only do it on boot if audit=1 is passed? Does anyone actually use that command line option?
-Eric
Quoted 17 lines · Eric Paris
Quoted 8 lines · Steve Grubb
Quoted 3 lines · On Thursday 27 March 2008 17:37:44 Eric Paris wrote:
This is useful to collect audit messages during bootup and even when auditd is stopped. This is NOT a reliable mechanism, it does not ever call
audit_panic, nor should it.Thanks Eric for working on this. We've needed this for quite a while so that we can see some of the avcs that happen during boot.
Quoted 7 lines
Quoted 2 lines
If auditd never starts the kernel will hold by default up to 64 messages in memory forever.
I have an idea. Maybe this behavior could be enabled if audit=1 is passed as a boot parameter. In this way, you would know that the user intended for the audit daemon to start at some point. You could then call audit panic or whatever else is normal. If no audit=1 is passed, you could just do the printk like usual and not waste memory. Would this be helpful?
Quoted 6 lines
I could probably do that. I also could conditionalize it on auditd ever having run. I can't imagine it is normal for auditd to be running and then stopped forever....
Anyone else see value in that situation? Only do it on boot if audit=1 is passed?
I think doing it on boot if audit=1 is passed is a good idea. I'm not sure I see the value of doing something when auditd was running but was stopped. I think when auditd is stopped, we shouldn't guess why or for how long it will be stopped.
-- ljk
Quoted 8 lines
Does anyone actually use that command line option?
-Eric
--
Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit
Quoted 11 lines · On Thursday 27 March 2008 20:52:03 Eric Paris wrote:
Quoted 9 lines · Steve Grubb
Quoted 2 lines · On Thursday 27 March 2008 17:37:44 Eric Paris wrote:
If auditd never starts the kernel will hold by default up to 64 messages in memory forever.
I have an idea. Maybe this behavior could be enabled if audit=1 is passed as a boot parameter. In this way, you would know that the user intended for the audit daemon to start at some point. You could then call audit panic or whatever else is normal. If no audit=1 is passed, you could just do the printk like usual and not waste memory. Would this be helpful?
Quoted 3 lines
I could probably do that. I also could conditionalize it on auditd ever having run. I can't imagine it is normal for auditd to be running and then stopped forever....
Could be, but if auditd stops, we normally send things go to syslog.
Quoted 2 lines
Anyone else see value in that situation? Only do it on boot if audit=1 is passed? Does anyone actually use that command line option?
Yes, anyone that is serious about audit *has* to use that boot option. That is the one thing that differentiates a casual user from a serious user of audit. The serious user would always be expecting auditd to start at some point.
-Steve
Quoted 19 lines · Eric Paris
Quoted 9 lines · Steve Grubb
Quoted 3 lines · On Thursday 27 March 2008 17:37:44 Eric Paris wrote:
This is useful to collect audit messages during bootup and even when auditd is stopped. This is NOT a reliable mechanism, it does not ever call
audit_panic, nor should it.Thanks Eric for working on this. We've needed this for quite a while so that we can see some of the avcs that happen during boot.
Quoted 8 lines
Quoted 2 lines
If auditd never starts the kernel will hold by default up to 64 messages in memory forever.
I have an idea. Maybe this behavior could be enabled if audit=1 is passed as a boot parameter. In this way, you would know that the user intended for the audit daemon to start at some point. You could then call audit panic or whatever else is normal. If no audit=1 is passed, you could just do the printk like usual and not waste memory. Would this be helpful?
Quoted 3 lines
I could probably do that. I also could conditionalize it on auditd ever having run. I can't imagine it is normal for auditd to be running and then stopped forever....
Unless it is an IDS-like event. Or a sysadmin makes a mistake.
Quoted 3 lines
Anyone else see value in that situation? Only do it on boot if audit=1 is passed? Does anyone actually use that command line option?
I will start using it. Audit collected as early in the boot sequence as possible is better.
Quoted 7 lines
-Eric
--
Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit
Signature · 2 lines
LC (Lenny) Bruzenak [email protected]