From 0f45aa18e65cf3d768082d7d86054a0d2a20bb18 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 19 Jun 2005 19:35:50 +0100 Subject: AUDIT: Allow filtering of user messages Turn the field from a bitmask to an enumeration and add a list to allow filtering of messages generated by userspace. We also define a list for file system watches in anticipation of that feature. Signed-off-by: David Woodhouse --- kernel/audit.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index ef35166fdc2..f0bbfe07313 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -107,13 +107,6 @@ static struct sk_buff_head audit_skb_queue; static struct task_struct *kauditd_task; static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); -/* There are three lists of rules -- one to search at task creation - * time, one to search at syscall entry time, and another to search at - * syscall exit time. */ -static LIST_HEAD(audit_tsklist); -static LIST_HEAD(audit_entlist); -static LIST_HEAD(audit_extlist); - /* The netlink socket is only to be read by 1 CPU, which lets us assume * that list additions and deletions never happen simultaneously in * auditsc.c */ @@ -376,6 +369,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) u16 msg_type = nlh->nlmsg_type; uid_t loginuid; /* loginuid of sender */ struct audit_sig_info sig_data; + struct task_struct *tsk; err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); if (err) @@ -435,15 +429,25 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: - ab = audit_log_start(NULL, msg_type); - if (!ab) - break; /* audit_panic has been called */ - audit_log_format(ab, - "user pid=%d uid=%u auid=%u" - " msg='%.1024s'", - pid, uid, loginuid, (char *)data); - audit_set_pid(ab, pid); - audit_log_end(ab); + read_lock(&tasklist_lock); + tsk = find_task_by_pid(pid); + if (tsk) + get_task_struct(tsk); + read_unlock(&tasklist_lock); + if (!tsk) + return -ESRCH; + + if (audit_filter_user(tsk, msg_type)) { + ab = audit_log_start(NULL, msg_type); + if (ab) { + audit_log_format(ab, + "user pid=%d uid=%u auid=%u msg='%.1024s'", + pid, uid, loginuid, (char *)data); + audit_set_pid(ab, pid); + audit_log_end(ab); + } + } + put_task_struct(tsk); break; case AUDIT_ADD: case AUDIT_DEL: -- cgit v1.2.3 From d6e0e1585a1a9a15e48ec47206a809828afe4450 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 20 Jun 2005 16:02:09 +0100 Subject: AUDIT: Drop user-generated messages immediately while auditing disabled. Signed-off-by: David Woodhouse --- kernel/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index f0bbfe07313..ab6ac560cfe 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -437,7 +437,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (!tsk) return -ESRCH; - if (audit_filter_user(tsk, msg_type)) { + if (audit_enabled && audit_filter_user(tsk, msg_type)) { ab = audit_log_start(NULL, msg_type); if (ab) { audit_log_format(ab, -- cgit v1.2.3 From f6a789d19858a951e7ff9e297a44b377c21b6c33 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 21 Jun 2005 16:22:01 +0100 Subject: AUDIT: Spawn kernel thread to list filter rules. If we have enough rules to fill the netlink buffer space, it'll deadlock because auditctl isn't ever actually going to read from the socket until we return, and we aren't going to return until it reads... so we spawn a kernel thread to spew out the list and then exit. Signed-off-by: David Woodhouse --- kernel/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index ab6ac560cfe..c1ab8dbbb67 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -110,7 +110,7 @@ static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); /* The netlink socket is only to be read by 1 CPU, which lets us assume * that list additions and deletions never happen simultaneously in * auditsc.c */ -static DECLARE_MUTEX(audit_netlink_sem); +DECLARE_MUTEX(audit_netlink_sem); /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting * audit records. Since printk uses a 1024 byte buffer, this buffer -- cgit v1.2.3 From 4a4cd633b575609b741a1de7837223a2d9e1c34c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 22 Jun 2005 14:56:47 +0100 Subject: AUDIT: Optimise the audit-disabled case for discarding user messages Also exempt USER_AVC message from being discarded to preserve existing behaviour for SE Linux. Signed-off-by: David Woodhouse --- kernel/audit.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index c1ab8dbbb67..09a37581213 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -429,25 +429,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: - read_lock(&tasklist_lock); - tsk = find_task_by_pid(pid); - if (tsk) - get_task_struct(tsk); - read_unlock(&tasklist_lock); - if (!tsk) - return -ESRCH; - - if (audit_enabled && audit_filter_user(tsk, msg_type)) { - ab = audit_log_start(NULL, msg_type); - if (ab) { - audit_log_format(ab, - "user pid=%d uid=%u auid=%u msg='%.1024s'", - pid, uid, loginuid, (char *)data); - audit_set_pid(ab, pid); - audit_log_end(ab); - } + if (!audit_enabled && msg_type != AUDIT_USER_AVC) + return 0; + + err = audit_filter_user(pid, msg_type); + if (err == 1) { + err = 0; + ab = audit_log_start(NULL, msg_type); + if (ab) { + audit_log_format(ab, + "user pid=%d uid=%u auid=%u msg='%.1024s'", + pid, uid, loginuid, (char *)data); + audit_set_pid(ab, pid); + audit_log_end(ab); + } } - put_task_struct(tsk); break; case AUDIT_ADD: case AUDIT_DEL: -- cgit v1.2.3 From 9ad9ad385be27fcc7c16d290d972c6173e780a61 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 22 Jun 2005 15:04:33 +0100 Subject: AUDIT: Wait for backlog to clear when generating messages. Add a gfp_mask to audit_log_start() and audit_log(), to reduce the amount of GFP_ATOMIC allocation -- most of it doesn't need to be GFP_ATOMIC. Also if the mask includes __GFP_WAIT, then wait up to 60 seconds for the auditd backlog to clear instead of immediately abandoning the message. The timeout should probably be made configurable, but for now it'll suffice that it only happens if auditd is actually running. Signed-off-by: David Woodhouse --- kernel/audit.c | 60 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 15 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 09a37581213..644ab825118 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -106,6 +106,7 @@ static LIST_HEAD(audit_freelist); static struct sk_buff_head audit_skb_queue; static struct task_struct *kauditd_task; static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); +static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); /* The netlink socket is only to be read by 1 CPU, which lets us assume * that list additions and deletions never happen simultaneously in @@ -130,6 +131,7 @@ struct audit_buffer { struct list_head list; struct sk_buff *skb; /* formatted skb ready to send */ struct audit_context *ctx; /* NULL or associated context */ + int gfp_mask; }; static void audit_set_pid(struct audit_buffer *ab, pid_t pid) @@ -226,7 +228,7 @@ static int audit_set_rate_limit(int limit, uid_t loginuid) { int old = audit_rate_limit; audit_rate_limit = limit; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_rate_limit=%d old=%d by auid=%u", audit_rate_limit, old, loginuid); return old; @@ -236,7 +238,7 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid) { int old = audit_backlog_limit; audit_backlog_limit = limit; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_backlog_limit=%d old=%d by auid=%u", audit_backlog_limit, old, loginuid); return old; @@ -248,7 +250,7 @@ static int audit_set_enabled(int state, uid_t loginuid) if (state != 0 && state != 1) return -EINVAL; audit_enabled = state; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_enabled=%d old=%d by auid=%u", audit_enabled, old, loginuid); return old; @@ -262,7 +264,7 @@ static int audit_set_failure(int state, uid_t loginuid) && state != AUDIT_FAIL_PANIC) return -EINVAL; audit_failure = state; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_failure=%d old=%d by auid=%u", audit_failure, old, loginuid); return old; @@ -274,6 +276,7 @@ int kauditd_thread(void *dummy) while (1) { skb = skb_dequeue(&audit_skb_queue); + wake_up(&audit_backlog_wait); if (skb) { if (audit_pid) { int err = netlink_unicast(audit_sock, skb, audit_pid, 0); @@ -417,7 +420,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (status_get->mask & AUDIT_STATUS_PID) { int old = audit_pid; audit_pid = status_get->pid; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_pid=%d old=%d by auid=%u", audit_pid, old, loginuid); } @@ -435,7 +438,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = audit_filter_user(pid, msg_type); if (err == 1) { err = 0; - ab = audit_log_start(NULL, msg_type); + ab = audit_log_start(NULL, GFP_KERNEL, msg_type); if (ab) { audit_log_format(ab, "user pid=%d uid=%u auid=%u msg='%.1024s'", @@ -522,7 +525,7 @@ static int __init audit_init(void) skb_queue_head_init(&audit_skb_queue); audit_initialized = 1; audit_enabled = audit_default; - audit_log(NULL, AUDIT_KERNEL, "initialized"); + audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized"); return 0; } __initcall(audit_init); @@ -586,6 +589,7 @@ static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, goto err; ab->ctx = ctx; + ab->gfp_mask = gfp_mask; nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0)); nlh->nlmsg_type = type; nlh->nlmsg_flags = 0; @@ -644,17 +648,42 @@ static inline void audit_get_stamp(struct audit_context *ctx, * syscall, then the syscall is marked as auditable and an audit record * will be written at syscall exit. If there is no associated task, tsk * should be NULL. */ -struct audit_buffer *audit_log_start(struct audit_context *ctx, int type) + +struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, + int type) { struct audit_buffer *ab = NULL; struct timespec t; unsigned int serial; + int reserve; if (!audit_initialized) return NULL; - if (audit_backlog_limit - && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) { + if (gfp_mask & __GFP_WAIT) + reserve = 0; + else + reserve = 5; /* Allow atomic callers to go up to five + entries over the normal backlog limit */ + + while (audit_backlog_limit + && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { + if (gfp_mask & __GFP_WAIT) { + int ret = 1; + /* Wait for auditd to drain the queue a little */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&audit_backlog_wait, &wait); + + if (audit_backlog_limit && + skb_queue_len(&audit_skb_queue) > audit_backlog_limit) + ret = schedule_timeout(HZ * 60); + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&audit_backlog_wait, &wait); + if (ret) + continue; + } if (audit_rate_check()) printk(KERN_WARNING "audit: audit_backlog=%d > " @@ -665,7 +694,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int type) return NULL; } - ab = audit_buffer_alloc(ctx, GFP_ATOMIC, type); + ab = audit_buffer_alloc(ctx, gfp_mask, type); if (!ab) { audit_log_lost("out of memory in audit_log_start"); return NULL; @@ -689,7 +718,7 @@ static inline int audit_expand(struct audit_buffer *ab, int extra) { struct sk_buff *skb = ab->skb; int ret = pskb_expand_head(skb, skb_headroom(skb), extra, - GFP_ATOMIC); + ab->gfp_mask); if (ret < 0) { audit_log_lost("out of memory in audit_expand"); return 0; @@ -808,7 +837,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, audit_log_format(ab, " %s", prefix); /* We will allow 11 spaces for ' (deleted)' to be appended */ - path = kmalloc(PATH_MAX+11, GFP_KERNEL); + path = kmalloc(PATH_MAX+11, ab->gfp_mask); if (!path) { audit_log_format(ab, ""); return; @@ -849,12 +878,13 @@ void audit_log_end(struct audit_buffer *ab) /* Log an audit record. This is a convenience function that calls * audit_log_start, audit_log_vformat, and audit_log_end. It may be * called in any context. */ -void audit_log(struct audit_context *ctx, int type, const char *fmt, ...) +void audit_log(struct audit_context *ctx, int gfp_mask, int type, + const char *fmt, ...) { struct audit_buffer *ab; va_list args; - ab = audit_log_start(ctx, type); + ab = audit_log_start(ctx, gfp_mask, type); if (ab) { va_start(args, fmt); audit_log_vformat(ab, fmt, args); -- cgit v1.2.3 From 9470178e620fe8f512928eed34994572c1c44be4 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 22 Jun 2005 15:40:55 +0100 Subject: AUDIT: Remove stray declaration of tsk from audit_receive_msg(). It's not used any more. Signed-off-by: David Woodhouse --- kernel/audit.c | 1 - 1 file changed, 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 644ab825118..9af947a63ed 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -372,7 +372,6 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) u16 msg_type = nlh->nlmsg_type; uid_t loginuid; /* loginuid of sender */ struct audit_sig_info sig_data; - struct task_struct *tsk; err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); if (err) -- cgit v1.2.3 From 5bb289b5a0becb53ac3e1d60815ff8b779296b73 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 24 Jun 2005 14:14:05 +0100 Subject: AUDIT: Clean up user message filtering Don't look up the task by its pid and then use the syscall filtering helper. Just implement our own filter helper which operates solely on the information in the netlink_skb_parms. Signed-off-by: David Woodhouse --- kernel/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 9af947a63ed..6f1784dd80a 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -434,7 +434,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (!audit_enabled && msg_type != AUDIT_USER_AVC) return 0; - err = audit_filter_user(pid, msg_type); + err = audit_filter_user(&NETLINK_CB(skb), msg_type); if (err == 1) { err = 0; ab = audit_log_start(NULL, GFP_KERNEL, msg_type); -- cgit v1.2.3 From e1b09eba2686eca94a3a188042b518df6044a3c1 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 24 Jun 2005 17:24:11 +0100 Subject: AUDIT: Use KERN_NOTICE for printk of audit records They aren't errors. Signed-off-by: David Woodhouse --- kernel/audit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 6f1784dd80a..2617d055240 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -286,7 +286,7 @@ int kauditd_thread(void *dummy) audit_pid = 0; } } else { - printk(KERN_ERR "%s\n", skb->data + NLMSG_SPACE(0)); + printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0)); kfree_skb(skb); } } else { @@ -868,7 +868,7 @@ void audit_log_end(struct audit_buffer *ab) ab->skb = NULL; wake_up_interruptible(&kauditd_wait); } else { - printk("%s\n", ab->skb->data + NLMSG_SPACE(0)); + printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0)); } } audit_buffer_free(ab); -- cgit v1.2.3 From ac4cec443a80bfde829516e7a7db10f7325aa528 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 2 Jul 2005 14:08:48 +0100 Subject: AUDIT: Stop waiting for backlog after audit_panic() happens We force a rate-limit on auditable events by making them wait for space on the backlog queue. However, if auditd really is AWOL then this could potentially bring the entire system to a halt, depending on the audit rules in effect. Firstly, make sure the wait time is honoured correctly -- it's the maximum time the process should wait, rather than the time to wait _each_ time round the loop. We were getting re-woken _each_ time a packet was dequeued, and the timeout was being restarted each time. Secondly, reset the wait time after audit_panic() is called. In general this will be reset to zero, to allow progress to be made. If the system is configured to _actually_ panic on audit_panic() then that will already have happened; otherwise we know that audit records are being lost anyway. These two tunables can't be exposed via AUDIT_GET and AUDIT_SET because those aren't particularly well-designed. It probably should have been done by sysctls or sysfs anyway -- one for a later patch. Signed-off-by: David Woodhouse --- kernel/audit.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 2617d055240..b683f2b5e86 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -79,6 +79,8 @@ static int audit_rate_limit; /* Number of outstanding audit_buffers allowed. */ static int audit_backlog_limit = 64; +static int audit_backlog_wait_time = 60 * HZ; +static int audit_backlog_wait_overflow = 0; /* The identity of the user shutting down the audit system. */ uid_t audit_sig_uid = -1; @@ -655,6 +657,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, struct timespec t; unsigned int serial; int reserve; + unsigned long timeout_start = jiffies; if (!audit_initialized) return NULL; @@ -667,8 +670,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, while (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { - if (gfp_mask & __GFP_WAIT) { - int ret = 1; + if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time + && time_before(jiffies, timeout_start + audit_backlog_wait_time)) { + /* Wait for auditd to drain the queue a little */ DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_INTERRUPTIBLE); @@ -676,12 +680,11 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, if (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) - ret = schedule_timeout(HZ * 60); + schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies); __set_current_state(TASK_RUNNING); remove_wait_queue(&audit_backlog_wait, &wait); - if (ret) - continue; + continue; } if (audit_rate_check()) printk(KERN_WARNING @@ -690,6 +693,8 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, skb_queue_len(&audit_skb_queue), audit_backlog_limit); audit_log_lost("backlog limit exceeded"); + audit_backlog_wait_time = audit_backlog_wait_overflow; + wake_up(&audit_backlog_wait); return NULL; } -- cgit v1.2.3 From 6c8c8ba5d7e31b37d0184c388183a6039a672417 Mon Sep 17 00:00:00 2001 From: Victor Fusco Date: Wed, 13 Jul 2005 22:26:57 +0100 Subject: [AUDIT] Fix sparse warning about gfp_mask type Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco Signed-off-by: Domen Puncer Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- kernel/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index b683f2b5e86..518a833b676 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -564,7 +564,7 @@ static void audit_buffer_free(struct audit_buffer *ab) } static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, - int gfp_mask, int type) + unsigned int __nocast gfp_mask, int type) { unsigned long flags; struct audit_buffer *ab = NULL; -- cgit v1.2.3 From d5b454f2c40c9efd0cc113bc3220ebcb66b7c022 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 15 Jul 2005 12:56:03 +0100 Subject: AUDIT: Fix livelock in audit_serial(). The tricks with atomic_t were bizarre. Just do it sensibly instead. Signed-off-by: David Woodhouse --- kernel/audit.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 518a833b676..27ffcf363f8 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -610,26 +610,25 @@ err: * (timestamp,serial) tuple is unique for each syscall and is live from * syscall entry to syscall exit. * - * Atomic values are only guaranteed to be 24-bit, so we count down. - * * NOTE: Another possibility is to store the formatted records off the * audit context (for those records that have a context), and emit them * all at syscall exit. However, this could delay the reporting of * significant errors until syscall exit (or never, if the system * halts). */ + unsigned int audit_serial(void) { - static atomic_t serial = ATOMIC_INIT(0xffffff); - unsigned int a, b; + static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED; + static unsigned int serial = 0; + + unsigned long flags; + unsigned int ret; - do { - a = atomic_read(&serial); - if (atomic_dec_and_test(&serial)) - atomic_set(&serial, 0xffffff); - b = atomic_read(&serial); - } while (b != a - 1); + spin_lock_irqsave(&serial_lock, flags); + ret = serial++; + spin_unlock_irqrestore(&serial_lock, flags); - return 0xffffff - b; + return ret; } static inline void audit_get_stamp(struct audit_context *ctx, -- cgit v1.2.3 From ce625a801664d8ed7344117bbb57510e4e0e872c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 18 Jul 2005 14:24:46 -0400 Subject: AUDIT: Reduce contention in audit_serial() ... by generating serial numbers only if an audit context is actually _used_, rather than doing so at syscall entry even when the context isn't necessarily marked auditable. Signed-off-by: David Woodhouse --- kernel/audit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 27ffcf363f8..d321e251d32 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -625,7 +625,9 @@ unsigned int audit_serial(void) unsigned int ret; spin_lock_irqsave(&serial_lock, flags); - ret = serial++; + do { + ret = ++serial; + } while (unlikely(!ret)); spin_unlock_irqrestore(&serial_lock, flags); return ret; -- cgit v1.2.3 From 3c789a19054034847afe80af2f23ebb0eebfbad6 Mon Sep 17 00:00:00 2001 From: Amy Griffis Date: Wed, 17 Aug 2005 16:05:35 +0100 Subject: AUDIT: Prevent duplicate syscall rules The following patch against audit.81 prevents duplicate syscall rules in a given filter list by walking the list on each rule add. I also removed the unused struct audit_entry in audit.c and made the static inlines in auditsc.c consistent. Signed-off-by: Amy Griffis Signed-off-by: David Woodhouse --- kernel/audit.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index d321e251d32..8376ec10cf2 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -142,11 +142,6 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid) nlh->nlmsg_pid = pid; } -struct audit_entry { - struct list_head list; - struct audit_rule rule; -}; - static void audit_panic(const char *message) { switch (audit_failure) -- cgit v1.2.3