From ac4cec443a80bfde829516e7a7db10f7325aa528 Mon Sep 17 00:00:00 2001
From: David Woodhouse <dwmw2@shinybook.infradead.org>
Date: Sat, 2 Jul 2005 14:08:48 +0100
Subject: [PATCH] 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 <dwmw2@infradead.org>
---
 kernel/audit.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 2617d05524002..b683f2b5e8665 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;
 	}
 
-- 
GitLab