mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 02:36:21 +00:00
audit: track the owner of the command mutex ourselves
Evidently the __mutex_owner() function was never intended for use outside the core mutex code, so build a thing locking wrapper around the mutex code which allows us to track the mutex owner. One, arguably positive, side effect is that this allows us to hide the audit_cmd_mutex inside of kernel/audit.c behind the lock/unlock functions. Reported-by: Peter Zijlstra <peterz@infradead.org> Reviewed-by: Richard Guy Briggs <rgb@redhat.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
parent
23138ead27
commit
ce423631ce
@ -181,9 +181,21 @@ static char *audit_feature_names[2] = {
|
|||||||
"loginuid_immutable",
|
"loginuid_immutable",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
/* Serialize requests from userspace. */
|
* struct audit_ctl_mutex - serialize requests from userspace
|
||||||
DEFINE_MUTEX(audit_cmd_mutex);
|
* @lock: the mutex used for locking
|
||||||
|
* @owner: the task which owns the lock
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This is the lock struct used to ensure we only process userspace requests
|
||||||
|
* in an orderly fashion. We can't simply use a mutex/lock here because we
|
||||||
|
* need to track lock ownership so we don't end up blocking the lock owner in
|
||||||
|
* audit_log_start() or similar.
|
||||||
|
*/
|
||||||
|
static struct audit_ctl_mutex {
|
||||||
|
struct mutex lock;
|
||||||
|
void *owner;
|
||||||
|
} audit_cmd_mutex;
|
||||||
|
|
||||||
/* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
|
/* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
|
||||||
* audit records. Since printk uses a 1024 byte buffer, this buffer
|
* audit records. Since printk uses a 1024 byte buffer, this buffer
|
||||||
@ -227,6 +239,36 @@ int auditd_test_task(struct task_struct *task)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audit_ctl_lock - Take the audit control lock
|
||||||
|
*/
|
||||||
|
void audit_ctl_lock(void)
|
||||||
|
{
|
||||||
|
mutex_lock(&audit_cmd_mutex.lock);
|
||||||
|
audit_cmd_mutex.owner = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audit_ctl_unlock - Drop the audit control lock
|
||||||
|
*/
|
||||||
|
void audit_ctl_unlock(void)
|
||||||
|
{
|
||||||
|
audit_cmd_mutex.owner = NULL;
|
||||||
|
mutex_unlock(&audit_cmd_mutex.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audit_ctl_owner_current - Test to see if the current task owns the lock
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Return true if the current task owns the audit control lock, false if it
|
||||||
|
* doesn't own the lock.
|
||||||
|
*/
|
||||||
|
static bool audit_ctl_owner_current(void)
|
||||||
|
{
|
||||||
|
return (current == audit_cmd_mutex.owner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* auditd_pid_vnr - Return the auditd PID relative to the namespace
|
* auditd_pid_vnr - Return the auditd PID relative to the namespace
|
||||||
*
|
*
|
||||||
@ -861,8 +903,8 @@ int audit_send_list(void *_dest)
|
|||||||
struct sock *sk = audit_get_sk(dest->net);
|
struct sock *sk = audit_get_sk(dest->net);
|
||||||
|
|
||||||
/* wait for parent to finish and send an ACK */
|
/* wait for parent to finish and send an ACK */
|
||||||
mutex_lock(&audit_cmd_mutex);
|
audit_ctl_lock();
|
||||||
mutex_unlock(&audit_cmd_mutex);
|
audit_ctl_unlock();
|
||||||
|
|
||||||
while ((skb = __skb_dequeue(&dest->q)) != NULL)
|
while ((skb = __skb_dequeue(&dest->q)) != NULL)
|
||||||
netlink_unicast(sk, skb, dest->portid, 0);
|
netlink_unicast(sk, skb, dest->portid, 0);
|
||||||
@ -903,8 +945,8 @@ static int audit_send_reply_thread(void *arg)
|
|||||||
struct audit_reply *reply = (struct audit_reply *)arg;
|
struct audit_reply *reply = (struct audit_reply *)arg;
|
||||||
struct sock *sk = audit_get_sk(reply->net);
|
struct sock *sk = audit_get_sk(reply->net);
|
||||||
|
|
||||||
mutex_lock(&audit_cmd_mutex);
|
audit_ctl_lock();
|
||||||
mutex_unlock(&audit_cmd_mutex);
|
audit_ctl_unlock();
|
||||||
|
|
||||||
/* Ignore failure. It'll only happen if the sender goes away,
|
/* Ignore failure. It'll only happen if the sender goes away,
|
||||||
because our timeout is set to infinite. */
|
because our timeout is set to infinite. */
|
||||||
@ -1469,7 +1511,7 @@ static void audit_receive(struct sk_buff *skb)
|
|||||||
nlh = nlmsg_hdr(skb);
|
nlh = nlmsg_hdr(skb);
|
||||||
len = skb->len;
|
len = skb->len;
|
||||||
|
|
||||||
mutex_lock(&audit_cmd_mutex);
|
audit_ctl_lock();
|
||||||
while (nlmsg_ok(nlh, len)) {
|
while (nlmsg_ok(nlh, len)) {
|
||||||
err = audit_receive_msg(skb, nlh);
|
err = audit_receive_msg(skb, nlh);
|
||||||
/* if err or if this message says it wants a response */
|
/* if err or if this message says it wants a response */
|
||||||
@ -1478,7 +1520,7 @@ static void audit_receive(struct sk_buff *skb)
|
|||||||
|
|
||||||
nlh = nlmsg_next(nlh, &len);
|
nlh = nlmsg_next(nlh, &len);
|
||||||
}
|
}
|
||||||
mutex_unlock(&audit_cmd_mutex);
|
audit_ctl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run custom bind function on netlink socket group connect or bind requests. */
|
/* Run custom bind function on netlink socket group connect or bind requests. */
|
||||||
@ -1550,6 +1592,9 @@ static int __init audit_init(void)
|
|||||||
for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
|
for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
|
||||||
INIT_LIST_HEAD(&audit_inode_hash[i]);
|
INIT_LIST_HEAD(&audit_inode_hash[i]);
|
||||||
|
|
||||||
|
mutex_init(&audit_cmd_mutex.lock);
|
||||||
|
audit_cmd_mutex.owner = NULL;
|
||||||
|
|
||||||
pr_info("initializing netlink subsys (%s)\n",
|
pr_info("initializing netlink subsys (%s)\n",
|
||||||
audit_default ? "enabled" : "disabled");
|
audit_default ? "enabled" : "disabled");
|
||||||
register_pernet_subsys(&audit_net_ops);
|
register_pernet_subsys(&audit_net_ops);
|
||||||
@ -1713,8 +1758,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
|
|||||||
* using a PID anchored in the caller's namespace
|
* using a PID anchored in the caller's namespace
|
||||||
* 2. generator holding the audit_cmd_mutex - we don't want to block
|
* 2. generator holding the audit_cmd_mutex - we don't want to block
|
||||||
* while holding the mutex */
|
* while holding the mutex */
|
||||||
if (!(auditd_test_task(current) ||
|
if (!(auditd_test_task(current) || audit_ctl_owner_current())) {
|
||||||
(current == __mutex_owner(&audit_cmd_mutex)))) {
|
|
||||||
long stime = audit_backlog_wait_time;
|
long stime = audit_backlog_wait_time;
|
||||||
|
|
||||||
while (audit_backlog_limit &&
|
while (audit_backlog_limit &&
|
||||||
|
@ -341,4 +341,5 @@ extern struct list_head *audit_killed_trees(void);
|
|||||||
#define audit_filter_inodes(t,c) AUDIT_DISABLED
|
#define audit_filter_inodes(t,c) AUDIT_DISABLED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct mutex audit_cmd_mutex;
|
extern void audit_ctl_lock(void);
|
||||||
|
extern void audit_ctl_unlock(void);
|
||||||
|
@ -709,7 +709,7 @@ static int prune_tree_thread(void *unused)
|
|||||||
schedule();
|
schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&audit_cmd_mutex);
|
audit_ctl_lock();
|
||||||
mutex_lock(&audit_filter_mutex);
|
mutex_lock(&audit_filter_mutex);
|
||||||
|
|
||||||
while (!list_empty(&prune_list)) {
|
while (!list_empty(&prune_list)) {
|
||||||
@ -727,7 +727,7 @@ static int prune_tree_thread(void *unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&audit_filter_mutex);
|
mutex_unlock(&audit_filter_mutex);
|
||||||
mutex_unlock(&audit_cmd_mutex);
|
audit_ctl_unlock();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -924,7 +924,7 @@ static void audit_schedule_prune(void)
|
|||||||
*/
|
*/
|
||||||
void audit_kill_trees(struct list_head *list)
|
void audit_kill_trees(struct list_head *list)
|
||||||
{
|
{
|
||||||
mutex_lock(&audit_cmd_mutex);
|
audit_ctl_lock();
|
||||||
mutex_lock(&audit_filter_mutex);
|
mutex_lock(&audit_filter_mutex);
|
||||||
|
|
||||||
while (!list_empty(list)) {
|
while (!list_empty(list)) {
|
||||||
@ -942,7 +942,7 @@ void audit_kill_trees(struct list_head *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&audit_filter_mutex);
|
mutex_unlock(&audit_filter_mutex);
|
||||||
mutex_unlock(&audit_cmd_mutex);
|
audit_ctl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user