audit: netlink socket can be auto-bound to pid other than current->pid (v2)
authorPavel Emelyanov <xemul@openvz.org>
Thu, 20 Mar 2008 22:39:41 +0000 (15:39 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 20 Mar 2008 22:39:41 +0000 (15:39 -0700)
From: Pavel Emelyanov <xemul@openvz.org>

This patch is based on the one from Thomas.

The kauditd_thread() calls the netlink_unicast() and passes
the audit_pid to it. The audit_pid, in turn, is received from
the user space and the tool (I've checked the audit v1.6.9)
uses getpid() to pass one in the kernel. Besides, this tool
doesn't bind the netlink socket to this id, but simply creates
it allowing the kernel to auto-bind one.

That's the preamble.

The problem is that netlink_autobind() _does_not_ guarantees
that the socket will be auto-bound to the current pid. Instead
it uses the current pid as a hint to start looking for a free
id. So, in case of conflict, the audit messages can be sent
to a wrong socket. This can happen (it's unlikely, but can be)
in case some task opens more than one netlink sockets and then
the audit one starts - in this case the audit's pid can be busy
and its socket will be bound to another id.

The proposal is to introduce an audit_nlk_pid in audit subsys,
that will point to the netlink socket to send packets to. It
will most often be equal to audit_pid. The socket id can be
got from the skb's netlink CB right in the audit_receive_msg.
The audit_nlk_pid reset to 0 is not required, since all the
decisions are taken based on audit_pid value only.

Later, if the audit tools will bind the socket themselves, the
kernel will have to provide a way to setup the audit_nlk_pid
as well.

A good side effect of this patch is that audit_pid can later
be converted to struct pid, as it is not longer safe to use
pid_t-s in the presence of pid namespaces. But audit code still
uses the tgid from task_struct in the audit_signal_info and in
the audit_filter_syscall.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: Eric Paris <eparis@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
kernel/audit.c

index 10c4930c2bbfbe0e98a5b56ff61a953fd4017367..be55cb5036330afc4ab1b759c301cd85542ae6ac 100644 (file)
@@ -78,9 +78,13 @@ static int   audit_default;
 /* If auditing cannot proceed, audit_failure selects what happens. */
 static int     audit_failure = AUDIT_FAIL_PRINTK;
 
-/* If audit records are to be written to the netlink socket, audit_pid
- * contains the (non-zero) pid. */
+/*
+ * If audit records are to be written to the netlink socket, audit_pid
+ * contains the pid of the auditd process and audit_nlk_pid contains
+ * the pid to use to send netlink messages to that process.
+ */
 int            audit_pid;
+static int     audit_nlk_pid;
 
 /* If audit_rate_limit is non-zero, limit the rate of sending audit records
  * to that number per second.  This prevents DoS attacks, but results in
@@ -350,7 +354,7 @@ static int kauditd_thread(void *dummy)
                wake_up(&audit_backlog_wait);
                if (skb) {
                        if (audit_pid) {
-                               int err = netlink_unicast(audit_sock, skb, audit_pid, 0);
+                               int err = netlink_unicast(audit_sock, skb, audit_nlk_pid, 0);
                                if (err < 0) {
                                        BUG_ON(err != -ECONNREFUSED); /* Shoudn't happen */
                                        printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid);
@@ -626,6 +630,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                                        sid, 1);
 
                        audit_pid = new_pid;
+                       audit_nlk_pid = NETLINK_CB(skb).pid;
                }
                if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
                        err = audit_set_rate_limit(status_get->rate_limit,