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 <[email protected]> Signed-off-by: Andrea Righi <[email protected]> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

