⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auditfilter.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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/mutex.h>#include <linux/fs.h>#include <linux/namei.h>#include <linux/netlink.h>#include <linux/sched.h>#include <linux/inotify.h>#include <linux/selinux.h>#include "audit.h"/* * Locking model: * * audit_filter_mutex: * 		Synchronizes writes and blocking reads of audit's filterlist * 		data.  Rcu is used to traverse the filterlist and access * 		contents of structs audit_entry, audit_watch and opaque * 		selinux rules during filtering.  If modified, these structures * 		must be copied and replace their counterparts in the filterlist. * 		An audit_parent struct is not accessed during filtering, so may * 		be written directly provided audit_filter_mutex is held. *//* * Reference counting: * * audit_parent: lifetime is from audit_init_parent() to receipt of an IN_IGNORED * 	event.  Each audit_watch holds a reference to its associated parent. * * audit_watch: if added to lists, lifetime is from audit_init_watch() to * 	audit_remove_watch().  Additionally, an audit_watch may exist * 	temporarily to assist in searching existing filter data.  Each * 	audit_krule holds a reference to its associated watch. */struct audit_parent {	struct list_head	ilist;	/* entry in inotify registration list */	struct list_head	watches; /* associated watches */	struct inotify_watch	wdata;	/* inotify watch data */	unsigned		flags;	/* status flags */};/* * audit_parent status flags: * * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to * a filesystem event to ensure we're adding audit watches to a valid parent. * Technically not needed for IN_DELETE_SELF or IN_UNMOUNT events, as we cannot * receive them while we have nameidata, but must be used for IN_MOVE_SELF which * we can receive while holding nameidata. */#define AUDIT_PARENT_INVALID	0x001/* Audit filter lists, defined in <linux/audit.h> */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 DEFINE_MUTEX(audit_filter_mutex);/* Inotify handle */extern struct inotify_handle *audit_ih;/* Inotify events we care about. */#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELFvoid audit_free_parent(struct inotify_watch *i_watch){	struct audit_parent *parent;	parent = container_of(i_watch, struct audit_parent, wdata);	WARN_ON(!list_empty(&parent->watches));	kfree(parent);}static inline void audit_get_watch(struct audit_watch *watch){	atomic_inc(&watch->count);}static void audit_put_watch(struct audit_watch *watch){	if (atomic_dec_and_test(&watch->count)) {		WARN_ON(watch->parent);		WARN_ON(!list_empty(&watch->rules));		kfree(watch->path);		kfree(watch);	}}static void audit_remove_watch(struct audit_watch *watch){	list_del(&watch->wlist);	put_inotify_watch(&watch->parent->wdata);	watch->parent = NULL;	audit_put_watch(watch); /* match initial get */}static inline void audit_free_rule(struct audit_entry *e){	int i;	/* some rules don't have associated watches */	if (e->rule.watch)		audit_put_watch(e->rule.watch);	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->rule.filterkey);	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 a parent watch entry. */static struct audit_parent *audit_init_parent(struct nameidata *ndp){	struct audit_parent *parent;	s32 wd;	parent = kzalloc(sizeof(*parent), GFP_KERNEL);	if (unlikely(!parent))		return ERR_PTR(-ENOMEM);	INIT_LIST_HEAD(&parent->watches);	parent->flags = 0;	inotify_init_watch(&parent->wdata);	/* grab a ref so inotify watch hangs around until we take audit_filter_mutex */	get_inotify_watch(&parent->wdata);	wd = inotify_add_watch(audit_ih, &parent->wdata, ndp->dentry->d_inode,			       AUDIT_IN_WATCH);	if (wd < 0) {		audit_free_parent(&parent->wdata);		return ERR_PTR(wd);	}	return parent;}/* Initialize a watch entry. */static struct audit_watch *audit_init_watch(char *path){	struct audit_watch *watch;	watch = kzalloc(sizeof(*watch), GFP_KERNEL);	if (unlikely(!watch))		return ERR_PTR(-ENOMEM);	INIT_LIST_HEAD(&watch->rules);	atomic_set(&watch->count, 1);	watch->path = path;	watch->dev = (dev_t)-1;	watch->ino = (unsigned long)-1;	return watch;}/* 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;}/* Translate an inode field to kernel respresentation. */static inline int audit_to_inode(struct audit_krule *krule,				 struct audit_field *f){	if (krule->listnr != AUDIT_FILTER_EXIT ||	    krule->watch || krule->inode_f)		return -EINVAL;	krule->inode_f = f;	return 0;}/* Translate a watch string to kernel respresentation. */static int audit_to_watch(struct audit_krule *krule, char *path, int len,			  u32 op){	struct audit_watch *watch;	if (!audit_ih)		return -EOPNOTSUPP;	if (path[0] != '/' || path[len-1] == '/' ||	    krule->listnr != AUDIT_FILTER_EXIT ||	    op & ~AUDIT_EQUAL ||	    krule->inode_f || krule->watch) /* 1 inode # per rule, for hash */		return -EINVAL;	watch = audit_init_watch(path);	if (unlikely(IS_ERR(watch)))		return PTR_ERR(watch);	audit_get_watch(watch);	krule->watch = watch;	return 0;}static __u32 *classes[AUDIT_SYSCALL_CLASSES];int __init audit_register_class(int class, unsigned *list){	__u32 *p = kzalloc(AUDIT_BITMASK_SIZE * sizeof(__u32), GFP_KERNEL);	if (!p)		return -ENOMEM;	while (*list != ~0U) {		unsigned n = *list++;		if (n >= AUDIT_BITMASK_SIZE * 32 - AUDIT_SYSCALL_CLASSES) {			kfree(p);			return -EINVAL;		}		p[AUDIT_WORD(n)] |= AUDIT_BIT(n);	}	if (class >= AUDIT_SYSCALL_CLASSES || classes[class]) {		kfree(p);		return -EINVAL;	}	classes[class] = p;	return 0;}int audit_match_class(int class, unsigned syscall){	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32)))		return 0;	if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class]))		return 0;	return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall);}#ifdef CONFIG_AUDITSYSCALLstatic inline int audit_match_class_bits(int class, u32 *mask){	int i;	if (classes[class]) {		for (i = 0; i < AUDIT_BITMASK_SIZE; i++)			if (mask[i] & classes[class][i])				return 0;	}	return 1;}static int audit_match_signal(struct audit_entry *entry){	struct audit_field *arch = entry->rule.arch_f;	if (!arch) {		/* When arch is unspecified, we must check both masks on biarch		 * as syscall number alone is ambiguous. */		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,					       entry->rule.mask) &&			audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,					       entry->rule.mask));	}	switch(audit_classify_arch(arch->val)) {	case 0: /* native */		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,					       entry->rule.mask));	case 1: /* 32bit on biarch */		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,					       entry->rule.mask));	default:		return 1;	}}#endif/* 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 (unlikely(rule->action == AUDIT_POSSIBLE)) {		printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n");		goto exit_err;	}	if (rule->action != AUDIT_NEVER && 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];	for (i = 0; i < AUDIT_SYSCALL_CLASSES; i++) {		int bit = AUDIT_BITMASK_SIZE * 32 - i - 1;		__u32 *p = &entry->rule.mask[AUDIT_WORD(bit)];		__u32 *class;		if (!(*p & AUDIT_BIT(bit)))			continue;		*p &= ~AUDIT_BIT(bit);		class = classes[i];		if (class) {			int j;			for (j = 0; j < AUDIT_BITMASK_SIZE; j++)				entry->rule.mask[j] |= class[j];		}	}	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;	struct audit_field *f;	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];		err = -EINVAL;		switch(f->type) {		default:			goto exit_free;		case AUDIT_PID:		case AUDIT_UID:		case AUDIT_EUID:		case AUDIT_SUID:		case AUDIT_FSUID:		case AUDIT_GID:		case AUDIT_EGID:		case AUDIT_SGID:		case AUDIT_FSGID:		case AUDIT_LOGINUID:		case AUDIT_PERS:		case AUDIT_MSGTYPE:		case AUDIT_PPID:		case AUDIT_DEVMAJOR:		case AUDIT_DEVMINOR:		case AUDIT_EXIT:		case AUDIT_SUCCESS:		case AUDIT_ARG0:		case AUDIT_ARG1:		case AUDIT_ARG2:		case AUDIT_ARG3:			break;		/* arch is only allowed to be = or != */		case AUDIT_ARCH:			if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL)					&& (f->op != AUDIT_NEGATE) && (f->op)) {				err = -EINVAL;				goto exit_free;			}			entry->rule.arch_f = f;			break;		case AUDIT_PERM:			if (f->val & ~15)				goto exit_free;			break;		case AUDIT_INODE:			err = audit_to_inode(&entry->rule, f);			if (err)				goto exit_free;			break;		}		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;		}	}	f = entry->rule.inode_f;	if (f) {		switch(f->op) {		case AUDIT_NOT_EQUAL:			entry->rule.inode_f = NULL;		case AUDIT_EQUAL:			break;		default:			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;	struct audit_field *f;	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_PID:		case AUDIT_UID:		case AUDIT_EUID:		case AUDIT_SUID:		case AUDIT_FSUID:		case AUDIT_GID:		case AUDIT_EGID:		case AUDIT_SGID:		case AUDIT_FSGID:		case AUDIT_LOGINUID:		case AUDIT_PERS:		case AUDIT_MSGTYPE:		case AUDIT_PPID:		case AUDIT_DEVMAJOR:		case AUDIT_DEVMINOR:		case AUDIT_EXIT:		case AUDIT_SUCCESS:		case AUDIT_ARG0:		case AUDIT_ARG1:		case AUDIT_ARG2:		case AUDIT_ARG3:			break;		case AUDIT_ARCH:			entry->rule.arch_f = f;			break;		case AUDIT_SUBJ_USER:		case AUDIT_SUBJ_ROLE:		case AUDIT_SUBJ_TYPE:		case AUDIT_SUBJ_SEN:		case AUDIT_SUBJ_CLR:		case AUDIT_OBJ_USER:		case AUDIT_OBJ_ROLE:		case AUDIT_OBJ_TYPE:		case AUDIT_OBJ_LEV_LOW:		case AUDIT_OBJ_LEV_HIGH:			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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -