857 lines · 21.2 KB · C
RawDownload
/* auditfilter.c -- filtering of audit events * * Copyright 2003-2004 Red Hat, Inc. * Copyright 2005 Hewlett-Packard Development Company, L.P. * Copyright 2005 IBM Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */ #include <linux/kernel.h>#include <linux/audit.h>#include <linux/kthread.h>#include <linux/netlink.h>#include <linux/selinux.h>#include "audit.h" /* There are three lists of rules -- one to search at task creation * time, one to search at syscall entry time, and another to search at * syscall exit time. */struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {	LIST_HEAD_INIT(audit_filter_list[0]),	LIST_HEAD_INIT(audit_filter_list[1]),	LIST_HEAD_INIT(audit_filter_list[2]),	LIST_HEAD_INIT(audit_filter_list[3]),	LIST_HEAD_INIT(audit_filter_list[4]),	LIST_HEAD_INIT(audit_filter_list[5]),#if AUDIT_NR_FILTERS != 6#error Fix audit_filter_list initialiser#endif}; static inline void audit_free_rule(struct audit_entry *e){	int i;	if (e->rule.fields)		for (i = 0; i < e->rule.field_count; i++) {			struct audit_field *f = &e->rule.fields[i];			kfree(f->se_str);			selinux_audit_rule_free(f->se_rule);		}	kfree(e->rule.fields);	kfree(e);} static inline void audit_free_rule_rcu(struct rcu_head *head){	struct audit_entry *e = container_of(head, struct audit_entry, rcu);	audit_free_rule(e);} /* Initialize an audit filterlist entry. */static inline struct audit_entry *audit_init_entry(u32 field_count){	struct audit_entry *entry;	struct audit_field *fields; 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);	if (unlikely(!entry))		return NULL; 	fields = kzalloc(sizeof(*fields) * field_count, GFP_KERNEL);	if (unlikely(!fields)) {		kfree(entry);		return NULL;	}	entry->rule.fields = fields; 	return entry;} /* Unpack a filter field's string representation from user-space * buffer. */static char *audit_unpack_string(void **bufp, size_t *remain, size_t len){	char *str; 	if (!*bufp || (len == 0) || (len > *remain))		return ERR_PTR(-EINVAL); 	/* Of the currently implemented string fields, PATH_MAX	 * defines the longest valid length.	 */	if (len > PATH_MAX)		return ERR_PTR(-ENAMETOOLONG); 	str = kmalloc(len + 1, GFP_KERNEL);	if (unlikely(!str))		return ERR_PTR(-ENOMEM); 	memcpy(str, *bufp, len);	str[len] = 0;	*bufp += len;	*remain -= len; 	return str;} /* Common user-space to kernel rule translation. */static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule){	unsigned listnr;	struct audit_entry *entry;	int i, err; 	err = -EINVAL;	listnr = rule->flags & ~AUDIT_FILTER_PREPEND;	switch(listnr) {	default:		goto exit_err;	case AUDIT_FILTER_USER:	case AUDIT_FILTER_TYPE:#ifdef CONFIG_AUDITSYSCALL	case AUDIT_FILTER_ENTRY:	case AUDIT_FILTER_EXIT:	case AUDIT_FILTER_TASK:#endif		;	}	if (rule->action != AUDIT_NEVER && rule->action != AUDIT_POSSIBLE &&	    rule->action != AUDIT_ALWAYS)		goto exit_err;	if (rule->field_count > AUDIT_MAX_FIELDS)		goto exit_err; 	err = -ENOMEM;	entry = audit_init_entry(rule->field_count);	if (!entry)		goto exit_err; 	entry->rule.flags = rule->flags & AUDIT_FILTER_PREPEND;	entry->rule.listnr = listnr;	entry->rule.action = rule->action;	entry->rule.field_count = rule->field_count; 	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)		entry->rule.mask[i] = rule->mask[i]; 	return entry; exit_err:	return ERR_PTR(err);} /* Translate struct audit_rule to kernel's rule respresentation. * Exists for backward compatibility with userspace. */static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule){	struct audit_entry *entry;	int err = 0;	int i; 	entry = audit_to_entry_common(rule);	if (IS_ERR(entry))		goto exit_nofree; 	for (i = 0; i < rule->field_count; i++) {		struct audit_field *f = &entry->rule.fields[i]; 		f->op = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);		f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);		f->val = rule->values[i]; 		if (f->type & AUDIT_UNUSED_BITS ||		    f->type == AUDIT_SE_USER ||		    f->type == AUDIT_SE_ROLE ||		    f->type == AUDIT_SE_TYPE ||		    f->type == AUDIT_SE_SEN ||		    f->type == AUDIT_SE_CLR) {			err = -EINVAL;			goto exit_free;		} 		entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1; 		/* Support for legacy operators where		 * AUDIT_NEGATE bit signifies != and otherwise assumes == */		if (f->op & AUDIT_NEGATE)			f->op = AUDIT_NOT_EQUAL;		else if (!f->op)			f->op = AUDIT_EQUAL;		else if (f->op == AUDIT_OPERATORS) {			err = -EINVAL;			goto exit_free;		}	} exit_nofree:	return entry; exit_free:	audit_free_rule(entry);	return ERR_PTR(err);} /* Translate struct audit_rule_data to kernel's rule respresentation. */static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,					       size_t datasz){	int err = 0;	struct audit_entry *entry;	void *bufp;	size_t remain = datasz - sizeof(struct audit_rule_data);	int i;	char *str; 	entry = audit_to_entry_common((struct audit_rule *)data);	if (IS_ERR(entry))		goto exit_nofree; 	bufp = data->buf;	entry->rule.vers_ops = 2;	for (i = 0; i < data->field_count; i++) {		struct audit_field *f = &entry->rule.fields[i]; 		err = -EINVAL;		if (!(data->fieldflags[i] & AUDIT_OPERATORS) ||		    data->fieldflags[i] & ~AUDIT_OPERATORS)			goto exit_free; 		f->op = data->fieldflags[i] & AUDIT_OPERATORS;		f->type = data->fields[i];		f->val = data->values[i];		f->se_str = NULL;		f->se_rule = NULL;		switch(f->type) {		case AUDIT_SE_USER:		case AUDIT_SE_ROLE:		case AUDIT_SE_TYPE:		case AUDIT_SE_SEN:		case AUDIT_SE_CLR:			str = audit_unpack_string(&bufp, &remain, f->val);			if (IS_ERR(str))				goto exit_free;			entry->rule.buflen += f->val; 			err = selinux_audit_rule_init(f->type, f->op, str,						      &f->se_rule);			/* Keep currently invalid fields around in case they			 * become valid after a policy reload. */			if (err == -EINVAL) {				printk(KERN_WARNING "audit rule for selinux "				       "\'%s\' is invalid\n",  str);				err = 0;			}			if (err) {				kfree(str);				goto exit_free;			} else				f->se_str = str;			break;		}	} exit_nofree:	return entry; exit_free:	audit_free_rule(entry);	return ERR_PTR(err);} /* Pack a filter field's string representation into data block. */static inline size_t audit_pack_string(void **bufp, char *str){	size_t len = strlen(str); 	memcpy(*bufp, str, len);	*bufp += len; 	return len;} /* Translate kernel rule respresentation to struct audit_rule. * Exists for backward compatibility with userspace. */static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule){	struct audit_rule *rule;	int i; 	rule = kmalloc(sizeof(*rule), GFP_KERNEL);	if (unlikely(!rule))		return ERR_PTR(-ENOMEM);	memset(rule, 0, sizeof(*rule)); 	rule->flags = krule->flags | krule->listnr;	rule->action = krule->action;	rule->field_count = krule->field_count;	for (i = 0; i < rule->field_count; i++) {		rule->values[i] = krule->fields[i].val;		rule->fields[i] = krule->fields[i].type; 		if (krule->vers_ops == 1) {			if (krule->fields[i].op & AUDIT_NOT_EQUAL)				rule->fields[i] |= AUDIT_NEGATE;		} else {			rule->fields[i] |= krule->fields[i].op;		}	}	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i]; 	return rule;} /* Translate kernel rule respresentation to struct audit_rule_data. */static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule){	struct audit_rule_data *data;	void *bufp;	int i; 	data = kmalloc(sizeof(*data) + krule->buflen, GFP_KERNEL);	if (unlikely(!data))		return ERR_PTR(-ENOMEM);	memset(data, 0, sizeof(*data)); 	data->flags = krule->flags | krule->listnr;	data->action = krule->action;	data->field_count = krule->field_count;	bufp = data->buf;	for (i = 0; i < data->field_count; i++) {		struct audit_field *f = &krule->fields[i]; 		data->fields[i] = f->type;		data->fieldflags[i] = f->op;		switch(f->type) {		case AUDIT_SE_USER:		case AUDIT_SE_ROLE:		case AUDIT_SE_TYPE:		case AUDIT_SE_SEN:		case AUDIT_SE_CLR:			data->buflen += data->values[i] =				audit_pack_string(&bufp, f->se_str);			break;		default:			data->values[i] = f->val;		}	}	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i]; 	return data;} /* Compare two rules in kernel format.  Considered success if rules * don't match. */static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b){	int i; 	if (a->flags != b->flags ||	    a->listnr != b->listnr ||	    a->action != b->action ||	    a->field_count != b->field_count)		return 1; 	for (i = 0; i < a->field_count; i++) {		if (a->fields[i].type != b->fields[i].type ||		    a->fields[i].op != b->fields[i].op)			return 1; 		switch(a->fields[i].type) {		case AUDIT_SE_USER:		case AUDIT_SE_ROLE:		case AUDIT_SE_TYPE:		case AUDIT_SE_SEN:		case AUDIT_SE_CLR:			if (strcmp(a->fields[i].se_str, b->fields[i].se_str))				return 1;			break;		default:			if (a->fields[i].val != b->fields[i].val)				return 1;		}	} 	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)		if (a->mask[i] != b->mask[i])			return 1; 	return 0;} /* Duplicate selinux field information.  The se_rule is opaque, so must be * re-initialized. */static inline int audit_dupe_selinux_field(struct audit_field *df,					   struct audit_field *sf){	int ret = 0;	char *se_str; 	/* our own copy of se_str */	se_str = kstrdup(sf->se_str, GFP_KERNEL);	if (unlikely(IS_ERR(se_str)))	    return -ENOMEM;	df->se_str = se_str; 	/* our own (refreshed) copy of se_rule */	ret = selinux_audit_rule_init(df->type, df->op, df->se_str,				      &df->se_rule);	/* Keep currently invalid fields around in case they	 * become valid after a policy reload. */	if (ret == -EINVAL) {		printk(KERN_WARNING "audit rule for selinux \'%s\' is "		       "invalid\n", df->se_str);		ret = 0;	} 	return ret;} /* Duplicate an audit rule.  This will be a deep copy with the exception * of the watch - that pointer is carried over.  The selinux specific fields * will be updated in the copy.  The point is to be able to replace the old * rule with the new rule in the filterlist, then free the old rule. */static struct audit_entry *audit_dupe_rule(struct audit_krule *old){	u32 fcount = old->field_count;	struct audit_entry *entry;	struct audit_krule *new;	int i, err = 0; 	entry = audit_init_entry(fcount);	if (unlikely(!entry))		return ERR_PTR(-ENOMEM); 	new = &entry->rule;	new->vers_ops = old->vers_ops;	new->flags = old->flags;	new->listnr = old->listnr;	new->action = old->action;	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)		new->mask[i] = old->mask[i];	new->buflen = old->buflen;	new->field_count = old->field_count;	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount); 	/* deep copy this information, updating the se_rule fields, because	 * the originals will all be freed when the old rule is freed. */	for (i = 0; i < fcount; i++) {		switch (new->fields[i].type) {		case AUDIT_SE_USER:		case AUDIT_SE_ROLE:		case AUDIT_SE_TYPE:		case AUDIT_SE_SEN:		case AUDIT_SE_CLR:			err = audit_dupe_selinux_field(&new->fields[i],						       &old->fields[i]);		}		if (err) {			audit_free_rule(entry);			return ERR_PTR(err);		}	} 	return entry;} /* Add rule to given filterlist if not a duplicate.  Protected by * audit_netlink_mutex. */static inline int audit_add_rule(struct audit_entry *entry,				  struct list_head *list){	struct audit_entry *e; 	/* Do not use the _rcu iterator here, since this is the only	 * addition routine. */	list_for_each_entry(e, list, list) {		if (!audit_compare_rule(&entry->rule, &e->rule))			return -EEXIST;	} 	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {		list_add_rcu(&entry->list, list);	} else {		list_add_tail_rcu(&entry->list, list);	} 	return 0;} /* Remove an existing rule from filterlist.  Protected by * audit_netlink_mutex. */static inline int audit_del_rule(struct audit_entry *entry,				 struct list_head *list){	struct audit_entry  *e; 	/* Do not use the _rcu iterator here, since this is the only	 * deletion routine. */

Lines 1–500 of 857.