From 133e1e5acd4a63c4a0dcc413e90d5decdbce9c4a Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 25 Jan 2016 18:04:15 -0500 Subject: audit: stop an old auditd being starved out by a new auditd Nothing prevents a new auditd starting up and replacing a valid audit_pid when an old auditd is still running, effectively starving out the old auditd since audit_pid no longer points to the old valid auditd. If no message to auditd has been attempted since auditd died unnaturally or got killed, audit_pid will still indicate it is alive. There isn't an easy way to detect if an old auditd is still running on the existing audit_pid other than attempting to send a message to see if it fails. An -ECONNREFUSED almost certainly means it disappeared and can be replaced. Other errors are not so straightforward and may indicate transient problems that will resolve themselves and the old auditd will recover. Yet others will likely need manual intervention for which a new auditd will not solve the problem. Send a new message type (AUDIT_REPLACE) to the old auditd containing a u32 with the PID of the new auditd. If the audit replace message succeeds (or doesn't fail with certainty), fail to register the new auditd and return an error (-EEXIST). This is expected to make the patch preventing an old auditd orphaning a new auditd redundant. V3: Switch audit message type from 1000 to 1300 block. Signed-off-by: Richard Guy Briggs Signed-off-by: Paul Moore --- kernel/audit.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index d6dd95cc59e6..2fd63d6879c5 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -809,6 +809,16 @@ static int audit_set_feature(struct sk_buff *skb) return 0; } +static int audit_replace(pid_t pid) +{ + struct sk_buff *skb = audit_make_reply(0, 0, AUDIT_REPLACE, 0, 0, + &pid, sizeof(pid)); + + if (!skb) + return -ENOMEM; + return netlink_unicast(audit_sock, skb, audit_nlk_portid, 0); +} + static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { u32 seq; @@ -870,9 +880,13 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } if (s.mask & AUDIT_STATUS_PID) { int new_pid = s.pid; + pid_t requesting_pid = task_tgid_vnr(current); - if ((!new_pid) && (task_tgid_vnr(current) != audit_pid)) + if ((!new_pid) && (requesting_pid != audit_pid)) return -EACCES; + if (audit_pid && new_pid && + audit_replace(requesting_pid) != -ECONNREFUSED) + return -EEXIST; if (audit_enabled != AUDIT_OFF) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); audit_pid = new_pid; -- cgit v1.2.3 From 935c9e7ff06abf12c45155f75ec2f712d3768095 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 25 Jan 2016 18:04:15 -0500 Subject: audit: log failed attempts to change audit_pid configuration Failed attempts to change the audit_pid configuration are not presently logged. One case is an attempt to starve an old auditd by starting up a new auditd when the old one is still alive and active. The other case is an attempt to orphan a new auditd when an old auditd shuts down. Log both as AUDIT_CONFIG_CHANGE messages with failure result. Signed-off-by: Richard Guy Briggs Signed-off-by: Paul Moore --- kernel/audit.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'kernel/audit.c') diff --git a/kernel/audit.c b/kernel/audit.c index 2fd63d6879c5..8fa7533bf106 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -882,11 +882,15 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) int new_pid = s.pid; pid_t requesting_pid = task_tgid_vnr(current); - if ((!new_pid) && (requesting_pid != audit_pid)) + if ((!new_pid) && (requesting_pid != audit_pid)) { + audit_log_config_change("audit_pid", new_pid, audit_pid, 0); return -EACCES; + } if (audit_pid && new_pid && - audit_replace(requesting_pid) != -ECONNREFUSED) + audit_replace(requesting_pid) != -ECONNREFUSED) { + audit_log_config_change("audit_pid", new_pid, audit_pid, 0); return -EEXIST; + } if (audit_enabled != AUDIT_OFF) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); audit_pid = new_pid; -- cgit v1.2.3