diff options
Diffstat (limited to 'kernel/auditfilter.c')
| -rw-r--r-- | kernel/auditfilter.c | 133 | 
1 files changed, 86 insertions, 47 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index f7aee8be7fb..8e9bc9c3dbb 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -19,6 +19,8 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/kernel.h>  #include <linux/audit.h>  #include <linux/kthread.h> @@ -29,6 +31,8 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/security.h> +#include <net/net_namespace.h> +#include <net/sock.h>  #include "audit.h"  /* @@ -224,7 +228,7 @@ static int audit_match_signal(struct audit_entry *entry)  #endif  /* Common user-space to kernel rule translation. */ -static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) +static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *rule)  {  	unsigned listnr;  	struct audit_entry *entry; @@ -247,7 +251,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)  		;  	}  	if (unlikely(rule->action == AUDIT_POSSIBLE)) { -		printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n"); +		pr_err("AUDIT_POSSIBLE is deprecated\n");  		goto exit_err;  	}  	if (rule->action != AUDIT_NEVER && rule->action != AUDIT_ALWAYS) @@ -343,6 +347,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)  	case AUDIT_DEVMINOR:  	case AUDIT_EXIT:  	case AUDIT_SUCCESS: +	case AUDIT_INODE:  		/* bit ops are only useful on syscall args */  		if (f->op == Audit_bitmask || f->op == Audit_bittest)  			return -EINVAL; @@ -400,7 +405,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,  	int i;  	char *str; -	entry = audit_to_entry_common((struct audit_rule *)data); +	entry = audit_to_entry_common(data);  	if (IS_ERR(entry))  		goto exit_nofree; @@ -423,11 +428,24 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,  		f->lsm_rule = NULL;  		/* Support legacy tests for a valid loginuid */ -		if ((f->type == AUDIT_LOGINUID) && (f->val == ~0U)) { +		if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {  			f->type = AUDIT_LOGINUID_SET;  			f->val = 0;  		} +		if ((f->type == AUDIT_PID) || (f->type == AUDIT_PPID)) { +			struct pid *pid; +			rcu_read_lock(); +			pid = find_vpid(f->val); +			if (!pid) { +				rcu_read_unlock(); +				err = -ESRCH; +				goto exit_free; +			} +			f->val = pid_nr(pid); +			rcu_read_unlock(); +		} +  		err = audit_field_valid(entry, f);  		if (err)  			goto exit_free; @@ -476,8 +494,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,  			/* Keep currently invalid fields around in case they  			 * become valid after a policy reload. */  			if (err == -EINVAL) { -				printk(KERN_WARNING "audit rule for LSM " -				       "\'%s\' is invalid\n",  str); +				pr_warn("audit rule for LSM \'%s\' is invalid\n", +					str);  				err = 0;  			}  			if (err) { @@ -706,8 +724,8 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,  	/* Keep currently invalid fields around in case they  	 * become valid after a policy reload. */  	if (ret == -EINVAL) { -		printk(KERN_WARNING "audit rule for LSM \'%s\' is " -		       "invalid\n", df->lsm_str); +		pr_warn("audit rule for LSM \'%s\' is invalid\n", +			df->lsm_str);  		ret = 0;  	} @@ -971,7 +989,7 @@ out:  }  /* List rules using struct audit_rule_data. */ -static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) +static void audit_list_rules(__u32 portid, int seq, struct sk_buff_head *q)  {  	struct sk_buff *skb;  	struct audit_krule *r; @@ -986,14 +1004,15 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)  			data = audit_krule_to_data(r);  			if (unlikely(!data))  				break; -			skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, -					 data, sizeof(*data) + data->buflen); +			skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, +					       0, 1, data, +					       sizeof(*data) + data->buflen);  			if (skb)  				skb_queue_tail(q, skb);  			kfree(data);  		}  	} -	skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0); +	skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);  	if (skb)  		skb_queue_tail(q, skb);  } @@ -1003,7 +1022,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re  {  	struct audit_buffer *ab;  	uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current)); -	u32 sessionid = audit_get_sessionid(current); +	unsigned int sessionid = audit_get_sessionid(current);  	if (!audit_enabled)  		return; @@ -1021,45 +1040,20 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re  }  /** - * audit_receive_filter - apply all rules to the specified message type + * audit_rule_change - apply all rules to the specified message type   * @type: audit message type - * @pid: target pid for netlink audit messages + * @portid: target port id for netlink audit messages   * @seq: netlink audit message sequence (serial) number   * @data: payload data   * @datasz: size of payload data   */ -int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz) +int audit_rule_change(int type, __u32 portid, int seq, void *data, +			size_t datasz)  { -	struct task_struct *tsk; -	struct audit_netlink_list *dest;  	int err = 0;  	struct audit_entry *entry;  	switch (type) { -	case AUDIT_LIST_RULES: -		/* We can't just spew out the rules here because we might fill -		 * the available socket buffer space and deadlock waiting for -		 * auditctl to read from it... which isn't ever going to -		 * happen if we're actually running in the context of auditctl -		 * trying to _send_ the stuff */ - -		dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL); -		if (!dest) -			return -ENOMEM; -		dest->pid = pid; -		skb_queue_head_init(&dest->q); - -		mutex_lock(&audit_filter_mutex); -		audit_list_rules(pid, seq, &dest->q); -		mutex_unlock(&audit_filter_mutex); - -		tsk = kthread_run(audit_send_list, dest, "audit_send_list"); -		if (IS_ERR(tsk)) { -			skb_queue_purge(&dest->q); -			kfree(dest); -			err = PTR_ERR(tsk); -		} -		break;  	case AUDIT_ADD_RULE:  		entry = audit_data_to_entry(data, datasz);  		if (IS_ERR(entry)) @@ -1086,6 +1080,46 @@ int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz)  	return err;  } +/** + * audit_list_rules_send - list the audit rules + * @request_skb: skb of request we are replying to (used to target the reply) + * @seq: netlink audit message sequence (serial) number + */ +int audit_list_rules_send(struct sk_buff *request_skb, int seq) +{ +	u32 portid = NETLINK_CB(request_skb).portid; +	struct net *net = sock_net(NETLINK_CB(request_skb).sk); +	struct task_struct *tsk; +	struct audit_netlink_list *dest; +	int err = 0; + +	/* We can't just spew out the rules here because we might fill +	 * the available socket buffer space and deadlock waiting for +	 * auditctl to read from it... which isn't ever going to +	 * happen if we're actually running in the context of auditctl +	 * trying to _send_ the stuff */ + +	dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL); +	if (!dest) +		return -ENOMEM; +	dest->net = get_net(net); +	dest->portid = portid; +	skb_queue_head_init(&dest->q); + +	mutex_lock(&audit_filter_mutex); +	audit_list_rules(portid, seq, &dest->q); +	mutex_unlock(&audit_filter_mutex); + +	tsk = kthread_run(audit_send_list, dest, "audit_send_list"); +	if (IS_ERR(tsk)) { +		skb_queue_purge(&dest->q); +		kfree(dest); +		err = PTR_ERR(tsk); +	} + +	return err; +} +  int audit_comparator(u32 left, u32 op, u32 right)  {  	switch (op) { @@ -1221,12 +1255,14 @@ static int audit_filter_user_rules(struct audit_krule *rule, int type,  	for (i = 0; i < rule->field_count; i++) {  		struct audit_field *f = &rule->fields[i]; +		pid_t pid;  		int result = 0;  		u32 sid;  		switch (f->type) {  		case AUDIT_PID: -			result = audit_comparator(task_pid_vnr(current), f->op, f->val); +			pid = task_pid_nr(current); +			result = audit_comparator(pid, f->op, f->val);  			break;  		case AUDIT_UID:  			result = audit_uid_comparator(current_uid(), f->op, f->uid); @@ -1275,19 +1311,22 @@ int audit_filter_user(int type)  {  	enum audit_state state = AUDIT_DISABLED;  	struct audit_entry *e; -	int ret = 1; +	int rc, ret; + +	ret = 1; /* Audit by default */  	rcu_read_lock();  	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { -		if (audit_filter_user_rules(&e->rule, type, &state)) { -			if (state == AUDIT_DISABLED) +		rc = audit_filter_user_rules(&e->rule, type, &state); +		if (rc) { +			if (rc > 0 && state == AUDIT_DISABLED)  				ret = 0;  			break;  		}  	}  	rcu_read_unlock(); -	return ret; /* Audit by default */ +	return ret;  }  int audit_filter_type(int type)  | 
