diff options
Diffstat (limited to 'kernel/audit.c')
| -rw-r--r-- | kernel/audit.c | 114 | 
1 files changed, 79 insertions, 35 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 227db99b0f19..670665c6e2a6 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -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 @@ -227,6 +240,36 @@ int auditd_test_task(struct task_struct *task)  }  /** + * 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   *   * Description: @@ -443,15 +486,15 @@ static int audit_set_failure(u32 state)   * Drop any references inside the auditd connection tracking struct and free   * the memory.   */ - static void auditd_conn_free(struct rcu_head *rcu) - { +static void auditd_conn_free(struct rcu_head *rcu) +{  	struct auditd_connection *ac;  	ac = container_of(rcu, struct auditd_connection, rcu);  	put_pid(ac->pid);  	put_net(ac->net);  	kfree(ac); - } +}  /**   * auditd_set - Set/Reset the auditd connection state @@ -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);  }  /**  | 
