|
@@ -38,7 +38,8 @@
|
|
|
* 6) Support low-overhead kernel-based filtering to minimize the
|
|
|
* information that must be passed to user-space.
|
|
|
*
|
|
|
- * Example user-space utilities: http://people.redhat.com/sgrubb/audit/
|
|
|
+ * Audit userspace, documentation, tests, and bug/issue trackers:
|
|
|
+ * https://github.com/linux-audit
|
|
|
*/
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
@@ -180,9 +181,21 @@ static char *audit_feature_names[2] = {
|
|
|
"loginuid_immutable",
|
|
|
};
|
|
|
|
|
|
-
|
|
|
-/* Serialize requests from userspace. */
|
|
|
-DEFINE_MUTEX(audit_cmd_mutex);
|
|
|
+/**
|
|
|
+ * struct audit_ctl_mutex - serialize requests from userspace
|
|
|
+ * @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 records. Since printk uses a 1024 byte buffer, this buffer
|
|
@@ -226,6 +239,36 @@ int auditd_test_task(struct task_struct *task)
|
|
|
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
|
|
|
*
|
|
@@ -860,8 +903,8 @@ int audit_send_list(void *_dest)
|
|
|
struct sock *sk = audit_get_sk(dest->net);
|
|
|
|
|
|
/* wait for parent to finish and send an ACK */
|
|
|
- mutex_lock(&audit_cmd_mutex);
|
|
|
- mutex_unlock(&audit_cmd_mutex);
|
|
|
+ audit_ctl_lock();
|
|
|
+ audit_ctl_unlock();
|
|
|
|
|
|
while ((skb = __skb_dequeue(&dest->q)) != NULL)
|
|
|
netlink_unicast(sk, skb, dest->portid, 0);
|
|
@@ -902,8 +945,8 @@ static int audit_send_reply_thread(void *arg)
|
|
|
struct audit_reply *reply = (struct audit_reply *)arg;
|
|
|
struct sock *sk = audit_get_sk(reply->net);
|
|
|
|
|
|
- mutex_lock(&audit_cmd_mutex);
|
|
|
- mutex_unlock(&audit_cmd_mutex);
|
|
|
+ audit_ctl_lock();
|
|
|
+ audit_ctl_unlock();
|
|
|
|
|
|
/* Ignore failure. It'll only happen if the sender goes away,
|
|
|
because our timeout is set to infinite. */
|
|
@@ -1058,6 +1101,8 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature
|
|
|
return;
|
|
|
|
|
|
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
|
|
|
+ if (!ab)
|
|
|
+ return;
|
|
|
audit_log_task_info(ab, current);
|
|
|
audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d",
|
|
|
audit_feature_names[which], !!old_feature, !!new_feature,
|
|
@@ -1466,7 +1511,7 @@ static void audit_receive(struct sk_buff *skb)
|
|
|
nlh = nlmsg_hdr(skb);
|
|
|
len = skb->len;
|
|
|
|
|
|
- mutex_lock(&audit_cmd_mutex);
|
|
|
+ audit_ctl_lock();
|
|
|
while (nlmsg_ok(nlh, len)) {
|
|
|
err = audit_receive_msg(skb, nlh);
|
|
|
/* if err or if this message says it wants a response */
|
|
@@ -1475,7 +1520,7 @@ static void audit_receive(struct sk_buff *skb)
|
|
|
|
|
|
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. */
|
|
@@ -1547,6 +1592,9 @@ static int __init audit_init(void)
|
|
|
for (i = 0; i < AUDIT_INODE_BUCKETS; 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",
|
|
|
audit_default ? "enabled" : "disabled");
|
|
|
register_pernet_subsys(&audit_net_ops);
|
|
@@ -1567,19 +1615,26 @@ static int __init audit_init(void)
|
|
|
}
|
|
|
postcore_initcall(audit_init);
|
|
|
|
|
|
-/* Process kernel command-line parameter at boot time. audit=0 or audit=1. */
|
|
|
+/*
|
|
|
+ * Process kernel command-line parameter at boot time.
|
|
|
+ * audit={0|off} or audit={1|on}.
|
|
|
+ */
|
|
|
static int __init audit_enable(char *str)
|
|
|
{
|
|
|
- long val;
|
|
|
-
|
|
|
- if (kstrtol(str, 0, &val))
|
|
|
- panic("audit: invalid 'audit' parameter value (%s)\n", str);
|
|
|
- audit_default = (val ? AUDIT_ON : AUDIT_OFF);
|
|
|
+ if (!strcasecmp(str, "off") || !strcmp(str, "0"))
|
|
|
+ audit_default = AUDIT_OFF;
|
|
|
+ else if (!strcasecmp(str, "on") || !strcmp(str, "1"))
|
|
|
+ audit_default = AUDIT_ON;
|
|
|
+ else {
|
|
|
+ pr_err("audit: invalid 'audit' parameter value (%s)\n", str);
|
|
|
+ audit_default = AUDIT_ON;
|
|
|
+ }
|
|
|
|
|
|
if (audit_default == AUDIT_OFF)
|
|
|
audit_initialized = AUDIT_DISABLED;
|
|
|
if (audit_set_enabled(audit_default))
|
|
|
- panic("audit: error setting audit state (%d)\n", audit_default);
|
|
|
+ pr_err("audit: error setting audit state (%d)\n",
|
|
|
+ audit_default);
|
|
|
|
|
|
pr_info("%s\n", audit_default ?
|
|
|
"enabled (after initialization)" : "disabled (until reboot)");
|
|
@@ -1710,8 +1765,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
|
|
|
* using a PID anchored in the caller's namespace
|
|
|
* 2. generator holding the audit_cmd_mutex - we don't want to block
|
|
|
* while holding the mutex */
|
|
|
- if (!(auditd_test_task(current) ||
|
|
|
- (current == __mutex_owner(&audit_cmd_mutex)))) {
|
|
|
+ if (!(auditd_test_task(current) || audit_ctl_owner_current())) {
|
|
|
long stime = audit_backlog_wait_time;
|
|
|
|
|
|
while (audit_backlog_limit &&
|
|
@@ -2254,33 +2308,23 @@ EXPORT_SYMBOL(audit_log_task_info);
|
|
|
/**
|
|
|
* audit_log_link_denied - report a link restriction denial
|
|
|
* @operation: specific link operation
|
|
|
- * @link: the path that triggered the restriction
|
|
|
*/
|
|
|
-void audit_log_link_denied(const char *operation, const struct path *link)
|
|
|
+void audit_log_link_denied(const char *operation)
|
|
|
{
|
|
|
struct audit_buffer *ab;
|
|
|
- struct audit_names *name;
|
|
|
|
|
|
- name = kzalloc(sizeof(*name), GFP_NOFS);
|
|
|
- if (!name)
|
|
|
+ if (!audit_enabled || audit_dummy_context())
|
|
|
return;
|
|
|
|
|
|
/* Generate AUDIT_ANOM_LINK with subject, operation, outcome. */
|
|
|
ab = audit_log_start(current->audit_context, GFP_KERNEL,
|
|
|
AUDIT_ANOM_LINK);
|
|
|
if (!ab)
|
|
|
- goto out;
|
|
|
+ return;
|
|
|
audit_log_format(ab, "op=%s", operation);
|
|
|
audit_log_task_info(ab, current);
|
|
|
audit_log_format(ab, " res=0");
|
|
|
audit_log_end(ab);
|
|
|
-
|
|
|
- /* Generate AUDIT_PATH record with object. */
|
|
|
- name->type = AUDIT_TYPE_NORMAL;
|
|
|
- audit_copy_inode(name, link->dentry, d_backing_inode(link->dentry));
|
|
|
- audit_log_name(current->audit_context, name, link, 0, NULL);
|
|
|
-out:
|
|
|
- kfree(name);
|
|
|
}
|
|
|
|
|
|
/**
|