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

📄 auditfilter.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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/security.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 * 		LSM 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};DEFINE_MUTEX(audit_filter_mutex);/* 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->lsm_str);			security_audit_rule_free(f->lsm_rule);		}	kfree(e->rule.fields);	kfree(e->rule.filterkey);	kfree(e);}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->path.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. */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 || krule->tree)		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 || krule->tree)		return -EINVAL;	watch = audit_init_watch(path);	if (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 * 32))		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 *ino_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:			/* bit ops are only useful on syscall args */			if (f->op == AUDIT_BIT_MASK ||						f->op == AUDIT_BIT_TEST) {				err = -EINVAL;				goto exit_free;			}			break;		case AUDIT_ARG0:

⌨️ 快捷键说明

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