Messages in this thread Patch in this message | | | From | Andrea Righi <> | Subject | [PATCH] audit: fix wrong timeout value in audit_log_start | Date | Tue, 7 Aug 2012 11:51:42 +0200 |
| |
audit_log_start() does not properly check timeout values when audit_backlog_limit is exceeded, for example it is possible to use negative timeout values with schedule_timeout() triggering error messages like this:
schedule_timeout: wrong timeout value ffffffffffff54e4
Be sure to never set negative values for the timeout.
Also, do a small refactoring to improve code readability.
Reported-by: Sean Jenkins <sean@bluehost.com> Signed-off-by: Andrea Righi <andrea@betterlinux.com> --- kernel/audit.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/kernel/audit.c b/kernel/audit.c index ea3b7b6..362d9b4 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1123,6 +1123,28 @@ static inline void audit_get_stamp(struct audit_context *ctx, } } +/* Wait for auditd to drain the queue a little */ +static void audit_log_congestion_wait(unsigned long timeout_start) +{ + 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) { + unsigned long deadline, now = ACCESS_ONCE(jiffies); + + WARN_ON(time_after(timeout_start, now)); + deadline = timeout_start + audit_backlog_wait_time; + if (time_before(now, deadline)) + schedule_timeout(deadline - now); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&audit_backlog_wait, &wait); +} + /* Obtain an audit buffer. This routine does locking to obtain the * audit buffer, but then no locking is required for calls to * audit_log_*format. If the tsk is a task that is currently in a @@ -1166,22 +1188,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, 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 && 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); - add_wait_queue(&audit_backlog_wait, &wait); - - if (audit_backlog_limit && - skb_queue_len(&audit_skb_queue) > audit_backlog_limit) - schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies); - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&audit_backlog_wait, &wait); + while (audit_backlog_limit && + skb_queue_len(&audit_skb_queue) > + audit_backlog_limit + reserve) { + if ((gfp_mask & __GFP_WAIT) && + audit_backlog_wait_time && + time_is_after_jiffies(timeout_start + + audit_backlog_wait_time)) { + audit_log_congestion_wait(timeout_start); continue; } if (audit_rate_check() && printk_ratelimit()) -- 1.7.9.5
| |