|
Enzo Matsumiya |
05326b |
From: Paul Moore <paul@paul-moore.com>
|
|
Enzo Matsumiya |
05326b |
Date: Thu, 13 Jan 2022 18:54:38 -0500
|
|
Enzo Matsumiya |
05326b |
Subject: [PATCH] audit: improve audit queue handling when "audit=1" on cmdline
|
|
Enzo Matsumiya |
05326b |
Git-commit: f26d04331360d42dbd6b58448bd98e4edbfbe1c5
|
|
Enzo Matsumiya |
05326b |
References: bsc#1209969
|
|
Enzo Matsumiya |
05326b |
Patch-mainline: v5.17-rc2
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
When an admin enables audit at early boot via the "audit=1" kernel
|
|
Enzo Matsumiya |
05326b |
command line the audit queue behavior is slightly different; the
|
|
Enzo Matsumiya |
05326b |
audit subsystem goes to greater lengths to avoid dropping records,
|
|
Enzo Matsumiya |
05326b |
which unfortunately can result in problems when the audit daemon is
|
|
Enzo Matsumiya |
05326b |
forcibly stopped for an extended period of time.
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
This patch makes a number of changes designed to improve the audit
|
|
Enzo Matsumiya |
05326b |
queuing behavior so that leaving the audit daemon in a stopped state
|
|
Enzo Matsumiya |
05326b |
for an extended period does not cause a significant impact to the
|
|
Enzo Matsumiya |
05326b |
system.
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
- kauditd_send_queue() is now limited to looping through the
|
|
Enzo Matsumiya |
05326b |
passed queue only once per call. This not only prevents the
|
|
Enzo Matsumiya |
05326b |
function from looping indefinitely when records are returned
|
|
Enzo Matsumiya |
05326b |
to the current queue, it also allows any recovery handling in
|
|
Enzo Matsumiya |
05326b |
kauditd_thread() to take place when kauditd_send_queue()
|
|
Enzo Matsumiya |
05326b |
returns.
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
- Transient netlink send errors seen as -EAGAIN now cause the
|
|
Enzo Matsumiya |
05326b |
record to be returned to the retry queue instead of going to
|
|
Enzo Matsumiya |
05326b |
the hold queue. The intention of the hold queue is to store,
|
|
Enzo Matsumiya |
05326b |
perhaps for an extended period of time, the events which led
|
|
Enzo Matsumiya |
05326b |
up to the audit daemon going offline. The retry queue remains
|
|
Enzo Matsumiya |
05326b |
a temporary queue intended to protect against transient issues
|
|
Enzo Matsumiya |
05326b |
between the kernel and the audit daemon.
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
- The retry queue is now limited by the audit_backlog_limit
|
|
Enzo Matsumiya |
05326b |
setting, the same as the other queues. This allows admins
|
|
Enzo Matsumiya |
05326b |
to bound the size of all of the audit queues on the system.
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
- kauditd_rehold_skb() now returns records to the end of the
|
|
Enzo Matsumiya |
05326b |
hold queue to ensure ordering is preserved in the face of
|
|
Enzo Matsumiya |
05326b |
recent changes to kauditd_send_queue().
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
Cc: stable@vger.kernel.org
|
|
Enzo Matsumiya |
05326b |
Fixes: 5b52330bbfe63 ("audit: fix auditd/kernel connection state tracking")
|
|
Enzo Matsumiya |
05326b |
Fixes: f4b3ee3c85551 ("audit: improve robustness of the audit queue handling")
|
|
Enzo Matsumiya |
05326b |
Reported-by: Gaosheng Cui <cuigaosheng1@huawei.com>
|
|
Enzo Matsumiya |
05326b |
Tested-by: Gaosheng Cui <cuigaosheng1@huawei.com>
|
|
Enzo Matsumiya |
05326b |
Reviewed-by: Richard Guy Briggs <rgb@redhat.com>
|
|
Enzo Matsumiya |
05326b |
Signed-off-by: Paul Moore <paul@paul-moore.com>
|
|
Enzo Matsumiya |
05326b |
Acked-by: Enzo Matsumiya <ematsumiya@suse.de>
|
|
Enzo Matsumiya |
05326b |
---
|
|
Enzo Matsumiya |
05326b |
kernel/audit.c | 64 +++++++++++++++++++++++++++++++++++++++------------------
|
|
Enzo Matsumiya |
05326b |
1 file changed, 44 insertions(+), 20 deletions(-)
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
--- a/kernel/audit.c
|
|
Enzo Matsumiya |
05326b |
+++ b/kernel/audit.c
|
|
Enzo Matsumiya |
05326b |
@@ -509,20 +509,22 @@ static void kauditd_printk_skb(struct sk
|
|
Enzo Matsumiya |
05326b |
/**
|
|
Enzo Matsumiya |
05326b |
* kauditd_rehold_skb - Handle a audit record send failure in the hold queue
|
|
Enzo Matsumiya |
05326b |
* @skb: audit record
|
|
Enzo Matsumiya |
05326b |
+ * @error: error code (unused)
|
|
Enzo Matsumiya |
05326b |
*
|
|
Enzo Matsumiya |
05326b |
* Description:
|
|
Enzo Matsumiya |
05326b |
* This should only be used by the kauditd_thread when it fails to flush the
|
|
Enzo Matsumiya |
05326b |
* hold queue.
|
|
Enzo Matsumiya |
05326b |
*/
|
|
Enzo Matsumiya |
05326b |
-static void kauditd_rehold_skb(struct sk_buff *skb)
|
|
Enzo Matsumiya |
05326b |
+static void kauditd_rehold_skb(struct sk_buff *skb, __always_unused int error)
|
|
Enzo Matsumiya |
05326b |
{
|
|
Enzo Matsumiya |
05326b |
- /* put the record back in the queue at the same place */
|
|
Enzo Matsumiya |
05326b |
- skb_queue_head(&audit_hold_queue, skb);
|
|
Enzo Matsumiya |
05326b |
+ /* put the record back in the queue */
|
|
Enzo Matsumiya |
05326b |
+ skb_queue_tail(&audit_hold_queue, skb);
|
|
Enzo Matsumiya |
05326b |
}
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/**
|
|
Enzo Matsumiya |
05326b |
* kauditd_hold_skb - Queue an audit record, waiting for auditd
|
|
Enzo Matsumiya |
05326b |
* @skb: audit record
|
|
Enzo Matsumiya |
05326b |
+ * @error: error code
|
|
Enzo Matsumiya |
05326b |
*
|
|
Enzo Matsumiya |
05326b |
* Description:
|
|
Enzo Matsumiya |
05326b |
* Queue the audit record, waiting for an instance of auditd. When this
|
|
Enzo Matsumiya |
05326b |
@@ -532,19 +534,31 @@ static void kauditd_rehold_skb(struct sk
|
|
Enzo Matsumiya |
05326b |
* and queue it, if we have room. If we want to hold on to the record, but we
|
|
Enzo Matsumiya |
05326b |
* don't have room, record a record lost message.
|
|
Enzo Matsumiya |
05326b |
*/
|
|
Enzo Matsumiya |
05326b |
-static void kauditd_hold_skb(struct sk_buff *skb)
|
|
Enzo Matsumiya |
05326b |
+static void kauditd_hold_skb(struct sk_buff *skb, int error)
|
|
Enzo Matsumiya |
05326b |
{
|
|
Enzo Matsumiya |
05326b |
/* at this point it is uncertain if we will ever send this to auditd so
|
|
Enzo Matsumiya |
05326b |
* try to send the message via printk before we go any further */
|
|
Enzo Matsumiya |
05326b |
kauditd_printk_skb(skb);
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/* can we just silently drop the message? */
|
|
Enzo Matsumiya |
05326b |
- if (!audit_default) {
|
|
Enzo Matsumiya |
05326b |
- kfree_skb(skb);
|
|
Enzo Matsumiya |
05326b |
- return;
|
|
Enzo Matsumiya |
05326b |
+ if (!audit_default)
|
|
Enzo Matsumiya |
05326b |
+ goto drop;
|
|
Enzo Matsumiya |
05326b |
+
|
|
Enzo Matsumiya |
05326b |
+ /* the hold queue is only for when the daemon goes away completely,
|
|
Enzo Matsumiya |
05326b |
+ * not -EAGAIN failures; if we are in a -EAGAIN state requeue the
|
|
Enzo Matsumiya |
05326b |
+ * record on the retry queue unless it's full, in which case drop it
|
|
Enzo Matsumiya |
05326b |
+ */
|
|
Enzo Matsumiya |
05326b |
+ if (error == -EAGAIN) {
|
|
Enzo Matsumiya |
05326b |
+ if (!audit_backlog_limit ||
|
|
Enzo Matsumiya |
05326b |
+ skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
|
|
Enzo Matsumiya |
05326b |
+ skb_queue_tail(&audit_retry_queue, skb);
|
|
Enzo Matsumiya |
05326b |
+ return;
|
|
Enzo Matsumiya |
05326b |
+ }
|
|
Enzo Matsumiya |
05326b |
+ audit_log_lost("kauditd retry queue overflow");
|
|
Enzo Matsumiya |
05326b |
+ goto drop;
|
|
Enzo Matsumiya |
05326b |
}
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
- /* if we have room, queue the message */
|
|
Enzo Matsumiya |
05326b |
+ /* if we have room in the hold queue, queue the message */
|
|
Enzo Matsumiya |
05326b |
if (!audit_backlog_limit ||
|
|
Enzo Matsumiya |
05326b |
skb_queue_len(&audit_hold_queue) < audit_backlog_limit) {
|
|
Enzo Matsumiya |
05326b |
skb_queue_tail(&audit_hold_queue, skb);
|
|
Enzo Matsumiya |
05326b |
@@ -553,24 +567,32 @@ static void kauditd_hold_skb(struct sk_b
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/* we have no other options - drop the message */
|
|
Enzo Matsumiya |
05326b |
audit_log_lost("kauditd hold queue overflow");
|
|
Enzo Matsumiya |
05326b |
+drop:
|
|
Enzo Matsumiya |
05326b |
kfree_skb(skb);
|
|
Enzo Matsumiya |
05326b |
}
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/**
|
|
Enzo Matsumiya |
05326b |
* kauditd_retry_skb - Queue an audit record, attempt to send again to auditd
|
|
Enzo Matsumiya |
05326b |
* @skb: audit record
|
|
Enzo Matsumiya |
05326b |
+ * @error: error code (unused)
|
|
Enzo Matsumiya |
05326b |
*
|
|
Enzo Matsumiya |
05326b |
* Description:
|
|
Enzo Matsumiya |
05326b |
* Not as serious as kauditd_hold_skb() as we still have a connected auditd,
|
|
Enzo Matsumiya |
05326b |
* but for some reason we are having problems sending it audit records so
|
|
Enzo Matsumiya |
05326b |
* queue the given record and attempt to resend.
|
|
Enzo Matsumiya |
05326b |
*/
|
|
Enzo Matsumiya |
05326b |
-static void kauditd_retry_skb(struct sk_buff *skb)
|
|
Enzo Matsumiya |
05326b |
+static void kauditd_retry_skb(struct sk_buff *skb, __always_unused int error)
|
|
Enzo Matsumiya |
05326b |
{
|
|
Enzo Matsumiya |
05326b |
- /* NOTE: because records should only live in the retry queue for a
|
|
Enzo Matsumiya |
05326b |
- * short period of time, before either being sent or moved to the hold
|
|
Enzo Matsumiya |
05326b |
- * queue, we don't currently enforce a limit on this queue */
|
|
Enzo Matsumiya |
05326b |
- skb_queue_tail(&audit_retry_queue, skb);
|
|
Enzo Matsumiya |
05326b |
+ if (!audit_backlog_limit ||
|
|
Enzo Matsumiya |
05326b |
+ skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
|
|
Enzo Matsumiya |
05326b |
+ skb_queue_tail(&audit_retry_queue, skb);
|
|
Enzo Matsumiya |
05326b |
+ return;
|
|
Enzo Matsumiya |
05326b |
+ }
|
|
Enzo Matsumiya |
05326b |
+
|
|
Enzo Matsumiya |
05326b |
+ /* we have to drop the record, send it via printk as a last effort */
|
|
Enzo Matsumiya |
05326b |
+ kauditd_printk_skb(skb);
|
|
Enzo Matsumiya |
05326b |
+ audit_log_lost("kauditd retry queue overflow");
|
|
Enzo Matsumiya |
05326b |
+ kfree_skb(skb);
|
|
Enzo Matsumiya |
05326b |
}
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/**
|
|
Enzo Matsumiya |
05326b |
@@ -607,9 +629,9 @@ static void auditd_reset(const struct au
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/* flush all of the main and retry queues to the hold queue */
|
|
Enzo Matsumiya |
05326b |
while ((skb = skb_dequeue(&audit_retry_queue)))
|
|
Enzo Matsumiya |
05326b |
- kauditd_hold_skb(skb);
|
|
Enzo Matsumiya |
05326b |
+ kauditd_hold_skb(skb, -ECONNREFUSED);
|
|
Enzo Matsumiya |
05326b |
while ((skb = skb_dequeue(&audit_queue)))
|
|
Enzo Matsumiya |
05326b |
- kauditd_hold_skb(skb);
|
|
Enzo Matsumiya |
05326b |
+ kauditd_hold_skb(skb, -ECONNREFUSED);
|
|
Enzo Matsumiya |
05326b |
}
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/**
|
|
Enzo Matsumiya |
05326b |
@@ -683,16 +705,18 @@ static int kauditd_send_queue(struct soc
|
|
Enzo Matsumiya |
05326b |
struct sk_buff_head *queue,
|
|
Enzo Matsumiya |
05326b |
unsigned int retry_limit,
|
|
Enzo Matsumiya |
05326b |
void (*skb_hook)(struct sk_buff *skb),
|
|
Enzo Matsumiya |
05326b |
- void (*err_hook)(struct sk_buff *skb))
|
|
Enzo Matsumiya |
05326b |
+ void (*err_hook)(struct sk_buff *skb, int error))
|
|
Enzo Matsumiya |
05326b |
{
|
|
Enzo Matsumiya |
05326b |
int rc = 0;
|
|
Enzo Matsumiya |
05326b |
- struct sk_buff *skb;
|
|
Enzo Matsumiya |
05326b |
+ struct sk_buff *skb = NULL;
|
|
Enzo Matsumiya |
05326b |
+ struct sk_buff *skb_tail;
|
|
Enzo Matsumiya |
05326b |
unsigned int failed = 0;
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
/* NOTE: kauditd_thread takes care of all our locking, we just use
|
|
Enzo Matsumiya |
05326b |
* the netlink info passed to us (e.g. sk and portid) */
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
- while ((skb = skb_dequeue(queue))) {
|
|
Enzo Matsumiya |
05326b |
+ skb_tail = skb_peek_tail(queue);
|
|
Enzo Matsumiya |
05326b |
+ while ((skb != skb_tail) && (skb = skb_dequeue(queue))) {
|
|
Enzo Matsumiya |
05326b |
/* call the skb_hook for each skb we touch */
|
|
Enzo Matsumiya |
05326b |
if (skb_hook)
|
|
Enzo Matsumiya |
05326b |
(*skb_hook)(skb);
|
|
Enzo Matsumiya |
05326b |
@@ -700,7 +724,7 @@ static int kauditd_send_queue(struct soc
|
|
Enzo Matsumiya |
05326b |
/* can we send to anyone via unicast? */
|
|
Enzo Matsumiya |
05326b |
if (!sk) {
|
|
Enzo Matsumiya |
05326b |
if (err_hook)
|
|
Enzo Matsumiya |
05326b |
- (*err_hook)(skb);
|
|
Enzo Matsumiya |
05326b |
+ (*err_hook)(skb, -ECONNREFUSED);
|
|
Enzo Matsumiya |
05326b |
continue;
|
|
Enzo Matsumiya |
05326b |
}
|
|
Enzo Matsumiya |
05326b |
|
|
Enzo Matsumiya |
05326b |
@@ -714,7 +738,7 @@ retry:
|
|
Enzo Matsumiya |
05326b |
rc == -ECONNREFUSED || rc == -EPERM) {
|
|
Enzo Matsumiya |
05326b |
sk = NULL;
|
|
Enzo Matsumiya |
05326b |
if (err_hook)
|
|
Enzo Matsumiya |
05326b |
- (*err_hook)(skb);
|
|
Enzo Matsumiya |
05326b |
+ (*err_hook)(skb, rc);
|
|
Enzo Matsumiya |
05326b |
if (rc == -EAGAIN)
|
|
Enzo Matsumiya |
05326b |
rc = 0;
|
|
Enzo Matsumiya |
05326b |
/* continue to drain the queue */
|