Skip to content

Commit 022732e

Browse files
cjrichespcmoore
authored andcommitted
audit: Send netlink ACK before setting connection in auditd_set
When auditd_set sets the auditd_conn pointer, audit messages can immediately be put on the socket by other kernel threads. If the backlog is large or the rate is high, this can immediately fill the socket buffer. If the audit daemon requested an ACK for this operation, a full socket buffer causes the ACK to get dropped, also setting ENOBUFS on the socket. To avoid this race and ensure ACKs get through, fast-track the ACK in this specific case to ensure it is sent before auditd_conn is set. Signed-off-by: Chris Riches <[email protected]> [PM: fix some tab vs space damage] Signed-off-by: Paul Moore <[email protected]>
1 parent b85ea95 commit 022732e

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

kernel/audit.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -487,15 +487,19 @@ static void auditd_conn_free(struct rcu_head *rcu)
487487
* @pid: auditd PID
488488
* @portid: auditd netlink portid
489489
* @net: auditd network namespace pointer
490+
* @skb: the netlink command from the audit daemon
491+
* @ack: netlink ack flag, cleared if ack'd here
490492
*
491493
* Description:
492494
* This function will obtain and drop network namespace references as
493495
* necessary. Returns zero on success, negative values on failure.
494496
*/
495-
static int auditd_set(struct pid *pid, u32 portid, struct net *net)
497+
static int auditd_set(struct pid *pid, u32 portid, struct net *net,
498+
struct sk_buff *skb, bool *ack)
496499
{
497500
unsigned long flags;
498501
struct auditd_connection *ac_old, *ac_new;
502+
struct nlmsghdr *nlh;
499503

500504
if (!pid || !net)
501505
return -EINVAL;
@@ -507,6 +511,13 @@ static int auditd_set(struct pid *pid, u32 portid, struct net *net)
507511
ac_new->portid = portid;
508512
ac_new->net = get_net(net);
509513

514+
/* send the ack now to avoid a race with the queue backlog */
515+
if (*ack) {
516+
nlh = nlmsg_hdr(skb);
517+
netlink_ack(skb, nlh, 0, NULL);
518+
*ack = false;
519+
}
520+
510521
spin_lock_irqsave(&auditd_conn_lock, flags);
511522
ac_old = rcu_dereference_protected(auditd_conn,
512523
lockdep_is_held(&auditd_conn_lock));
@@ -1200,7 +1211,8 @@ static int audit_replace(struct pid *pid)
12001211
return auditd_send_unicast_skb(skb);
12011212
}
12021213

1203-
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1214+
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
1215+
bool *ack)
12041216
{
12051217
u32 seq;
12061218
void *data;
@@ -1293,7 +1305,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
12931305
/* register a new auditd connection */
12941306
err = auditd_set(req_pid,
12951307
NETLINK_CB(skb).portid,
1296-
sock_net(NETLINK_CB(skb).sk));
1308+
sock_net(NETLINK_CB(skb).sk),
1309+
skb, ack);
12971310
if (audit_enabled != AUDIT_OFF)
12981311
audit_log_config_change("audit_pid",
12991312
new_pid,
@@ -1538,9 +1551,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
15381551
* Parse the provided skb and deal with any messages that may be present,
15391552
* malformed skbs are discarded.
15401553
*/
1541-
static void audit_receive(struct sk_buff *skb)
1554+
static void audit_receive(struct sk_buff *skb)
15421555
{
15431556
struct nlmsghdr *nlh;
1557+
bool ack;
15441558
/*
15451559
* len MUST be signed for nlmsg_next to be able to dec it below 0
15461560
* if the nlmsg_len was not aligned
@@ -1553,9 +1567,12 @@ static void audit_receive(struct sk_buff *skb)
15531567

15541568
audit_ctl_lock();
15551569
while (nlmsg_ok(nlh, len)) {
1556-
err = audit_receive_msg(skb, nlh);
1557-
/* if err or if this message says it wants a response */
1558-
if (err || (nlh->nlmsg_flags & NLM_F_ACK))
1570+
ack = nlh->nlmsg_flags & NLM_F_ACK;
1571+
err = audit_receive_msg(skb, nlh, &ack);
1572+
1573+
/* send an ack if the user asked for one and audit_receive_msg
1574+
* didn't already do it, or if there was an error. */
1575+
if (ack || err)
15591576
netlink_ack(skb, nlh, err, NULL);
15601577

15611578
nlh = nlmsg_next(nlh, &len);

0 commit comments

Comments
 (0)