-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmH4I8oUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXP9zw//ZAU42ylQXvGfLJbCsbZHKq7H/Ljo
 QKbwlSKh+aP+IXcRxnh9fV3vTkc7LkHZfrhGx35aHlS1HK8XIa/XHHNTPHfaEKai
 iDiXwICP5j1JysWCKJXu0uhe7juW3ko7+bQyI8MYBAeLKrbC1F04oswSgVNuX2bq
 aMyD9+GdAv7PiVVw0oc5+hKFS/8q/VRdbCsJmESKUDhthS3hqH8wZJqy37aYIpF1
 /yqkvEIts+GzeQrSWvsGL+O720GIyZ8V2/cEH2y+pnGYgoYdlXhD1CccXOOCocb8
 M/6uQZTgQiEVf1LMuu/WIW6CzrRQIjOt4SNU0cXLkWlgxAN1p5b9sP+YcncWU23N
 zbIACFiFVz1ZhxHT0AEVs+thdZrF6CJX0xfsb+GvJJeYy9aw11s7VGlYhaM+1haG
 8oeYmtjQ+rjjkEKMUcOWQYxRvCZIsI6z5JlqoFC0zuJda1k3418LyDZARwCUrm1c
 6QY35M0HHxa8k7TWtvJ6aopxM4pg+ZL8WS0shULHRqw/NprvYc6KeZc0/VNyFojJ
 S4wa+Z6rXoYIvGReeDkUOiJjigW78/kyQR2rsxHWaGlDfL8+bALdnorkTbU2G4oG
 Jl1HQdOSuAeAT/D7w/UmKFXDBPXHU77sLnjxiCDMmbmVY6Vxja/hZD/wy9RyyK4K
 UAXDJNwhndHsgX4=
 =sFi4
 -----END PGP SIGNATURE-----

Merge tag 'audit-pr-20220131' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit

Pull audit fix from Paul Moore:
 "A single audit patch to fix problems relating to audit queuing and
  system responsiveness when "audit=1" is specified on the kernel
  command line and the audit daemon is SIGSTOP'd for an extended period
  of time"

* tag 'audit-pr-20220131' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
  audit: improve audit queue handling when "audit=1" on cmdline
This commit is contained in:
Linus Torvalds 2022-02-01 11:07:09 -08:00
Родитель 26291c54e1 f26d043313
Коммит 61fda95541
1 изменённых файлов: 43 добавлений и 19 удалений

Просмотреть файл

@ -541,20 +541,22 @@ static void kauditd_printk_skb(struct sk_buff *skb)
/** /**
* kauditd_rehold_skb - Handle a audit record send failure in the hold queue * kauditd_rehold_skb - Handle a audit record send failure in the hold queue
* @skb: audit record * @skb: audit record
* @error: error code (unused)
* *
* Description: * Description:
* This should only be used by the kauditd_thread when it fails to flush the * This should only be used by the kauditd_thread when it fails to flush the
* hold queue. * hold queue.
*/ */
static void kauditd_rehold_skb(struct sk_buff *skb) static void kauditd_rehold_skb(struct sk_buff *skb, __always_unused int error)
{ {
/* put the record back in the queue at the same place */ /* put the record back in the queue */
skb_queue_head(&audit_hold_queue, skb); skb_queue_tail(&audit_hold_queue, skb);
} }
/** /**
* kauditd_hold_skb - Queue an audit record, waiting for auditd * kauditd_hold_skb - Queue an audit record, waiting for auditd
* @skb: audit record * @skb: audit record
* @error: error code
* *
* Description: * Description:
* Queue the audit record, waiting for an instance of auditd. When this * Queue the audit record, waiting for an instance of auditd. When this
@ -564,19 +566,31 @@ static void kauditd_rehold_skb(struct sk_buff *skb)
* and queue it, if we have room. If we want to hold on to the record, but we * and queue it, if we have room. If we want to hold on to the record, but we
* don't have room, record a record lost message. * don't have room, record a record lost message.
*/ */
static void kauditd_hold_skb(struct sk_buff *skb) static void kauditd_hold_skb(struct sk_buff *skb, int error)
{ {
/* at this point it is uncertain if we will ever send this to auditd so /* at this point it is uncertain if we will ever send this to auditd so
* try to send the message via printk before we go any further */ * try to send the message via printk before we go any further */
kauditd_printk_skb(skb); kauditd_printk_skb(skb);
/* can we just silently drop the message? */ /* can we just silently drop the message? */
if (!audit_default) { if (!audit_default)
kfree_skb(skb); goto drop;
return;
/* the hold queue is only for when the daemon goes away completely,
* not -EAGAIN failures; if we are in a -EAGAIN state requeue the
* record on the retry queue unless it's full, in which case drop it
*/
if (error == -EAGAIN) {
if (!audit_backlog_limit ||
skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
skb_queue_tail(&audit_retry_queue, skb);
return;
}
audit_log_lost("kauditd retry queue overflow");
goto drop;
} }
/* if we have room, queue the message */ /* if we have room in the hold queue, queue the message */
if (!audit_backlog_limit || if (!audit_backlog_limit ||
skb_queue_len(&audit_hold_queue) < audit_backlog_limit) { skb_queue_len(&audit_hold_queue) < audit_backlog_limit) {
skb_queue_tail(&audit_hold_queue, skb); skb_queue_tail(&audit_hold_queue, skb);
@ -585,24 +599,32 @@ static void kauditd_hold_skb(struct sk_buff *skb)
/* we have no other options - drop the message */ /* we have no other options - drop the message */
audit_log_lost("kauditd hold queue overflow"); audit_log_lost("kauditd hold queue overflow");
drop:
kfree_skb(skb); kfree_skb(skb);
} }
/** /**
* kauditd_retry_skb - Queue an audit record, attempt to send again to auditd * kauditd_retry_skb - Queue an audit record, attempt to send again to auditd
* @skb: audit record * @skb: audit record
* @error: error code (unused)
* *
* Description: * Description:
* Not as serious as kauditd_hold_skb() as we still have a connected auditd, * Not as serious as kauditd_hold_skb() as we still have a connected auditd,
* but for some reason we are having problems sending it audit records so * but for some reason we are having problems sending it audit records so
* queue the given record and attempt to resend. * queue the given record and attempt to resend.
*/ */
static void kauditd_retry_skb(struct sk_buff *skb) static void kauditd_retry_skb(struct sk_buff *skb, __always_unused int error)
{ {
/* NOTE: because records should only live in the retry queue for a if (!audit_backlog_limit ||
* short period of time, before either being sent or moved to the hold skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
* queue, we don't currently enforce a limit on this queue */ skb_queue_tail(&audit_retry_queue, skb);
skb_queue_tail(&audit_retry_queue, skb); return;
}
/* we have to drop the record, send it via printk as a last effort */
kauditd_printk_skb(skb);
audit_log_lost("kauditd retry queue overflow");
kfree_skb(skb);
} }
/** /**
@ -640,7 +662,7 @@ static void auditd_reset(const struct auditd_connection *ac)
/* flush the retry queue to the hold queue, but don't touch the main /* flush the retry queue to the hold queue, but don't touch the main
* queue since we need to process that normally for multicast */ * queue since we need to process that normally for multicast */
while ((skb = skb_dequeue(&audit_retry_queue))) while ((skb = skb_dequeue(&audit_retry_queue)))
kauditd_hold_skb(skb); kauditd_hold_skb(skb, -ECONNREFUSED);
} }
/** /**
@ -714,16 +736,18 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
struct sk_buff_head *queue, struct sk_buff_head *queue,
unsigned int retry_limit, unsigned int retry_limit,
void (*skb_hook)(struct sk_buff *skb), void (*skb_hook)(struct sk_buff *skb),
void (*err_hook)(struct sk_buff *skb)) void (*err_hook)(struct sk_buff *skb, int error))
{ {
int rc = 0; int rc = 0;
struct sk_buff *skb; struct sk_buff *skb = NULL;
struct sk_buff *skb_tail;
unsigned int failed = 0; unsigned int failed = 0;
/* NOTE: kauditd_thread takes care of all our locking, we just use /* NOTE: kauditd_thread takes care of all our locking, we just use
* the netlink info passed to us (e.g. sk and portid) */ * the netlink info passed to us (e.g. sk and portid) */
while ((skb = skb_dequeue(queue))) { skb_tail = skb_peek_tail(queue);
while ((skb != skb_tail) && (skb = skb_dequeue(queue))) {
/* call the skb_hook for each skb we touch */ /* call the skb_hook for each skb we touch */
if (skb_hook) if (skb_hook)
(*skb_hook)(skb); (*skb_hook)(skb);
@ -731,7 +755,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
/* can we send to anyone via unicast? */ /* can we send to anyone via unicast? */
if (!sk) { if (!sk) {
if (err_hook) if (err_hook)
(*err_hook)(skb); (*err_hook)(skb, -ECONNREFUSED);
continue; continue;
} }
@ -745,7 +769,7 @@ retry:
rc == -ECONNREFUSED || rc == -EPERM) { rc == -ECONNREFUSED || rc == -EPERM) {
sk = NULL; sk = NULL;
if (err_hook) if (err_hook)
(*err_hook)(skb); (*err_hook)(skb, rc);
if (rc == -EAGAIN) if (rc == -EAGAIN)
rc = 0; rc = 0;
/* continue to drain the queue */ /* continue to drain the queue */