Skip to content

Commit

Permalink
audit: store the auditd PID as a pid struct instead of pid_t
Browse files Browse the repository at this point in the history
This is arguably the right thing to do, and will make it easier when
we start supporting multiple audit daemons in different namespaces.

Signed-off-by: Paul Moore <[email protected]>
  • Loading branch information
pcmoore committed May 2, 2017
1 parent 45a0642 commit b6c7c11
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 28 deletions.
84 changes: 57 additions & 27 deletions kernel/audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include <linux/rcupdate.h>
#include <linux/mutex.h>
#include <linux/gfp.h>
#include <linux/pid.h>

#include <linux/audit.h>

Expand Down Expand Up @@ -117,7 +118,7 @@ struct audit_net {
* or the included spinlock for writing.
*/
static struct auditd_connection {
int pid;
struct pid *pid;
u32 portid;
struct net *net;
spinlock_t lock;
Expand Down Expand Up @@ -220,17 +221,40 @@ struct audit_reply {
* Description:
* Return 1 if the task is a registered audit daemon, 0 otherwise.
*/
int auditd_test_task(const struct task_struct *task)
int auditd_test_task(struct task_struct *task)
{
int rc;

rcu_read_lock();
rc = (auditd_conn.pid && task->tgid == auditd_conn.pid ? 1 : 0);
rc = (auditd_conn.pid && auditd_conn.pid == task_tgid(task) ? 1 : 0);
rcu_read_unlock();

return rc;
}

/**
* auditd_pid_vnr - Return the auditd PID relative to the namespace
* @auditd: the auditd connection
*
* Description:
* Returns the PID in relation to the namespace, 0 on failure. This function
* takes the RCU read lock internally, but if the caller needs to protect the
* auditd_connection pointer it should take the RCU read lock as well.
*/
static pid_t auditd_pid_vnr(const struct auditd_connection *auditd)
{
pid_t pid;

rcu_read_lock();
if (!auditd || !auditd->pid)
pid = 0;
else
pid = pid_vnr(auditd->pid);
rcu_read_unlock();

return pid;
}

/**
* audit_get_sk - Return the audit socket for the given network namespace
* @net: the destination network namespace
Expand Down Expand Up @@ -428,12 +452,17 @@ static int audit_set_failure(u32 state)
* This function will obtain and drop network namespace references as
* necessary.
*/
static void auditd_set(int pid, u32 portid, struct net *net)
static void auditd_set(struct pid *pid, u32 portid, struct net *net)
{
unsigned long flags;

spin_lock_irqsave(&auditd_conn.lock, flags);
auditd_conn.pid = pid;
if (auditd_conn.pid)
put_pid(auditd_conn.pid);
if (pid)
auditd_conn.pid = get_pid(pid);
else
auditd_conn.pid = NULL;
auditd_conn.portid = portid;
if (auditd_conn.net)
put_net(auditd_conn.net);
Expand Down Expand Up @@ -1059,11 +1088,13 @@ static int audit_set_feature(struct sk_buff *skb)
return 0;
}

static int audit_replace(pid_t pid)
static int audit_replace(struct pid *pid)
{
pid_t pvnr;
struct sk_buff *skb;

skb = audit_make_reply(0, AUDIT_REPLACE, 0, 0, &pid, sizeof(pid));
pvnr = pid_vnr(pid);
skb = audit_make_reply(0, AUDIT_REPLACE, 0, 0, &pvnr, sizeof(pvnr));
if (!skb)
return -ENOMEM;
return auditd_send_unicast_skb(skb);
Expand Down Expand Up @@ -1093,9 +1124,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
memset(&s, 0, sizeof(s));
s.enabled = audit_enabled;
s.failure = audit_failure;
rcu_read_lock();
s.pid = auditd_conn.pid;
rcu_read_unlock();
/* NOTE: use pid_vnr() so the PID is relative to the current
* namespace */
s.pid = auditd_pid_vnr(&auditd_conn);
s.rate_limit = audit_rate_limit;
s.backlog_limit = audit_backlog_limit;
s.lost = atomic_read(&audit_lost);
Expand All @@ -1121,45 +1152,44 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return err;
}
if (s.mask & AUDIT_STATUS_PID) {
/* NOTE: we are using task_tgid_vnr() below because
* the s.pid value is relative to the namespace
* of the caller; at present this doesn't matter
* much since you can really only run auditd
* from the initial pid namespace, but something
* to keep in mind if this changes */
int new_pid = s.pid;
/* NOTE: we are using the vnr PID functions below
* because the s.pid value is relative to the
* namespace of the caller; at present this
* doesn't matter much since you can really only
* run auditd from the initial pid namespace, but
* something to keep in mind if this changes */
pid_t new_pid = s.pid;
pid_t auditd_pid;
pid_t requesting_pid = task_tgid_vnr(current);
struct pid *req_pid = task_tgid(current);

/* sanity check - PID values must match */
if (new_pid != pid_vnr(req_pid))
return -EINVAL;

/* test the auditd connection */
audit_replace(requesting_pid);
audit_replace(req_pid);

rcu_read_lock();
auditd_pid = auditd_conn.pid;
auditd_pid = auditd_pid_vnr(&auditd_conn);
/* only the current auditd can unregister itself */
if ((!new_pid) && (requesting_pid != auditd_pid)) {
rcu_read_unlock();
if ((!new_pid) && (new_pid != auditd_pid)) {
audit_log_config_change("audit_pid", new_pid,
auditd_pid, 0);
return -EACCES;
}
/* replacing a healthy auditd is not allowed */
if (auditd_pid && new_pid) {
rcu_read_unlock();
audit_log_config_change("audit_pid", new_pid,
auditd_pid, 0);
return -EEXIST;
}
rcu_read_unlock();

if (audit_enabled != AUDIT_OFF)
audit_log_config_change("audit_pid", new_pid,
auditd_pid, 1);

if (new_pid) {
/* register a new auditd connection */
auditd_set(new_pid,
NETLINK_CB(skb).portid,
auditd_set(req_pid, NETLINK_CB(skb).portid,
sock_net(NETLINK_CB(skb).sk));
/* try to process any backlog */
wake_up_interruptible(&kauditd_wait);
Expand Down
2 changes: 1 addition & 1 deletion kernel/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ extern void audit_log_name(struct audit_context *context,
struct audit_names *n, const struct path *path,
int record_num, int *call_panic);

extern int auditd_test_task(const struct task_struct *task);
extern int auditd_test_task(struct task_struct *task);

#define AUDIT_INODE_BUCKETS 32
extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
Expand Down

0 comments on commit b6c7c11

Please sign in to comment.