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

📄 auditfilter.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 3 页
字号:
		ret = -ENOENT;	else		audit_add_to_parent(krule, parent);	/* match get in audit_init_parent or inotify_find_watch */	put_inotify_watch(&parent->wdata);	return ret;}/* Add rule to given filterlist if not a duplicate. */static inline int audit_add_rule(struct audit_entry *entry,				 struct list_head *list){	struct audit_entry *e;	struct audit_field *inode_f = entry->rule.inode_f;	struct audit_watch *watch = entry->rule.watch;	struct nameidata *ndp, *ndw;	int h, err, putnd_needed = 0;#ifdef CONFIG_AUDITSYSCALL	int dont_count = 0;	/* If either of these, don't count towards total */	if (entry->rule.listnr == AUDIT_FILTER_USER ||		entry->rule.listnr == AUDIT_FILTER_TYPE)		dont_count = 1;#endif	if (inode_f) {		h = audit_hash_ino(inode_f->val);		list = &audit_inode_hash[h];	}	mutex_lock(&audit_filter_mutex);	e = audit_find_rule(entry, list);	mutex_unlock(&audit_filter_mutex);	if (e) {		err = -EEXIST;		goto error;	}	/* Avoid calling path_lookup under audit_filter_mutex. */	if (watch) {		err = audit_get_nd(watch->path, &ndp, &ndw);		if (err)			goto error;		putnd_needed = 1;	}	mutex_lock(&audit_filter_mutex);	if (watch) {		/* audit_filter_mutex is dropped and re-taken during this call */		err = audit_add_watch(&entry->rule, ndp, ndw);		if (err) {			mutex_unlock(&audit_filter_mutex);			goto error;		}		h = audit_hash_ino((u32)watch->ino);		list = &audit_inode_hash[h];	}	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {		list_add_rcu(&entry->list, list);		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;	} else {		list_add_tail_rcu(&entry->list, list);	}#ifdef CONFIG_AUDITSYSCALL	if (!dont_count)		audit_n_rules++;	if (!audit_match_signal(entry))		audit_signals++;#endif	mutex_unlock(&audit_filter_mutex);	if (putnd_needed)		audit_put_nd(ndp, ndw); 	return 0;error:	if (putnd_needed)		audit_put_nd(ndp, ndw);	if (watch)		audit_put_watch(watch); /* tmp watch, matches initial get */	return err;}/* Remove an existing rule from filterlist. */static inline int audit_del_rule(struct audit_entry *entry,				 struct list_head *list){	struct audit_entry  *e;	struct audit_field *inode_f = entry->rule.inode_f;	struct audit_watch *watch, *tmp_watch = entry->rule.watch;	LIST_HEAD(inotify_list);	int h, ret = 0;#ifdef CONFIG_AUDITSYSCALL	int dont_count = 0;	/* If either of these, don't count towards total */	if (entry->rule.listnr == AUDIT_FILTER_USER ||		entry->rule.listnr == AUDIT_FILTER_TYPE)		dont_count = 1;#endif	if (inode_f) {		h = audit_hash_ino(inode_f->val);		list = &audit_inode_hash[h];	}	mutex_lock(&audit_filter_mutex);	e = audit_find_rule(entry, list);	if (!e) {		mutex_unlock(&audit_filter_mutex);		ret = -ENOENT;		goto out;	}	watch = e->rule.watch;	if (watch) {		struct audit_parent *parent = watch->parent;		list_del(&e->rule.rlist);		if (list_empty(&watch->rules)) {			audit_remove_watch(watch);			if (list_empty(&parent->watches)) {				/* Put parent on the inotify un-registration				 * list.  Grab a reference before releasing				 * audit_filter_mutex, to be released in				 * audit_inotify_unregister(). */				list_add(&parent->ilist, &inotify_list);				get_inotify_watch(&parent->wdata);			}		}	}	list_del_rcu(&e->list);	call_rcu(&e->rcu, audit_free_rule_rcu);#ifdef CONFIG_AUDITSYSCALL	if (!dont_count)		audit_n_rules--;	if (!audit_match_signal(entry))		audit_signals--;#endif	mutex_unlock(&audit_filter_mutex);	if (!list_empty(&inotify_list))		audit_inotify_unregister(&inotify_list);out:	if (tmp_watch)		audit_put_watch(tmp_watch); /* match initial get */	return ret;}/* List rules using struct audit_rule.  Exists for backward * compatibility with userspace. */static void audit_list(int pid, int seq, struct sk_buff_head *q){	struct sk_buff *skb;	struct audit_entry *entry;	int i;	/* This is a blocking read, so use audit_filter_mutex instead of rcu	 * iterator to sync with list writers. */	for (i=0; i<AUDIT_NR_FILTERS; i++) {		list_for_each_entry(entry, &audit_filter_list[i], list) {			struct audit_rule *rule;			rule = audit_krule_to_rule(&entry->rule);			if (unlikely(!rule))				break;			skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,					 rule, sizeof(*rule));			if (skb)				skb_queue_tail(q, skb);			kfree(rule);		}	}	for (i = 0; i < AUDIT_INODE_BUCKETS; i++) {		list_for_each_entry(entry, &audit_inode_hash[i], list) {			struct audit_rule *rule;			rule = audit_krule_to_rule(&entry->rule);			if (unlikely(!rule))				break;			skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,					 rule, sizeof(*rule));			if (skb)				skb_queue_tail(q, skb);			kfree(rule);		}	}	skb = audit_make_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);	if (skb)		skb_queue_tail(q, skb);}/* List rules using struct audit_rule_data. */static void audit_list_rules(int pid, int seq, struct sk_buff_head *q){	struct sk_buff *skb;	struct audit_entry *e;	int i;	/* This is a blocking read, so use audit_filter_mutex instead of rcu	 * iterator to sync with list writers. */	for (i=0; i<AUDIT_NR_FILTERS; i++) {		list_for_each_entry(e, &audit_filter_list[i], list) {			struct audit_rule_data *data;			data = audit_krule_to_data(&e->rule);			if (unlikely(!data))				break;			skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,					 data, sizeof(*data) + data->buflen);			if (skb)				skb_queue_tail(q, skb);			kfree(data);		}	}	for (i=0; i< AUDIT_INODE_BUCKETS; i++) {		list_for_each_entry(e, &audit_inode_hash[i], list) {			struct audit_rule_data *data;			data = audit_krule_to_data(&e->rule);			if (unlikely(!data))				break;			skb = audit_make_reply(pid, 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);	if (skb)		skb_queue_tail(q, skb);}/* Log rule additions and removals */static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,				  struct audit_krule *rule, int res){	struct audit_buffer *ab;	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);	if (!ab)		return;	audit_log_format(ab, "auid=%u", loginuid);	if (sid) {		char *ctx = NULL;		u32 len;		if (selinux_sid_to_string(sid, &ctx, &len))			audit_log_format(ab, " ssid=%u", sid);		else			audit_log_format(ab, " subj=%s", ctx);		kfree(ctx);	}	audit_log_format(ab, " op=%s rule key=", action);	if (rule->filterkey)		audit_log_untrustedstring(ab, rule->filterkey);	else		audit_log_format(ab, "(null)");	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);	audit_log_end(ab);}/** * audit_receive_filter - apply all rules to the specified message type * @type: audit message type * @pid: target pid for netlink audit messages * @uid: target uid for netlink audit messages * @seq: netlink audit message sequence (serial) number * @data: payload data * @datasz: size of payload data * @loginuid: loginuid of sender * @sid: SE Linux Security ID of sender */int audit_receive_filter(int type, int pid, int uid, int seq, void *data,			 size_t datasz, uid_t loginuid, u32 sid){	struct task_struct *tsk;	struct audit_netlink_list *dest;	int err = 0;	struct audit_entry *entry;	switch (type) {	case AUDIT_LIST:	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);		if (type == AUDIT_LIST)			audit_list(pid, seq, &dest->q);		else			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:	case AUDIT_ADD_RULE:		if (type == AUDIT_ADD)			entry = audit_rule_to_entry(data);		else			entry = audit_data_to_entry(data, datasz);		if (IS_ERR(entry))			return PTR_ERR(entry);		err = audit_add_rule(entry,				     &audit_filter_list[entry->rule.listnr]);		audit_log_rule_change(loginuid, sid, "add", &entry->rule, !err);		if (err)			audit_free_rule(entry);		break;	case AUDIT_DEL:	case AUDIT_DEL_RULE:		if (type == AUDIT_DEL)			entry = audit_rule_to_entry(data);		else			entry = audit_data_to_entry(data, datasz);		if (IS_ERR(entry))			return PTR_ERR(entry);		err = audit_del_rule(entry,				     &audit_filter_list[entry->rule.listnr]);		audit_log_rule_change(loginuid, sid, "remove", &entry->rule,				      !err);		audit_free_rule(entry);		break;	default:		return -EINVAL;	}	return err;}int audit_comparator(const u32 left, const u32 op, const u32 right){	switch (op) {	case AUDIT_EQUAL:		return (left == right);	case AUDIT_NOT_EQUAL:		return (left != right);	case AUDIT_LESS_THAN:		return (left < right);	case AUDIT_LESS_THAN_OR_EQUAL:		return (left <= right);	case AUDIT_GREATER_THAN:		return (left > right);	case AUDIT_GREATER_THAN_OR_EQUAL:		return (left >= right);	}	BUG();	return 0;}/* Compare given dentry name with last component in given path, * return of 0 indicates a match. */int audit_compare_dname_path(const char *dname, const char *path,			     int *dirlen){	int dlen, plen;	const char *p;	if (!dname || !path)		return 1;	dlen = strlen(dname);	plen = strlen(path);	if (plen < dlen)		return 1;	/* disregard trailing slashes */	p = path + plen - 1;	while ((*p == '/') && (p > path))		p--;	/* find last path component */	p = p - dlen + 1;	if (p < path)		return 1;	else if (p > path) {		if (*--p != '/')			return 1;		else			p++;	}	/* return length of path's directory component */	if (dirlen)		*dirlen = p - path;	return strncmp(p, dname, dlen);}static int audit_filter_user_rules(struct netlink_skb_parms *cb,				   struct audit_krule *rule,				   enum audit_state *state){	int i;	for (i = 0; i < rule->field_count; i++) {		struct audit_field *f = &rule->fields[i];		int result = 0;		switch (f->type) {		case AUDIT_PID:			result = audit_comparator(cb->creds.pid, f->op, f->val);			break;		case AUDIT_UID:			result = audit_comparator(cb->creds.uid, f->op, f->val);			break;		case AUDIT_GID:			result = audit_comparator(cb->creds.gid, f->op, f->val);			break;		case AUDIT_LOGINUID:			result = audit_comparator(cb->loginuid, f->op, f->val);			break;		}		if (!result)			return 0;	}	switch (rule->action) {	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;	}	return 1;}int audit_filter_user(struct netlink_skb_parms *cb, int type){	enum audit_state state = AUDIT_DISABLED;	struct audit_entry *e;	int ret = 1;	rcu_read_lock();	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {		if (audit_filter_user_rules(cb, &e->rule, &state)) {			if (state == AUDIT_DISABLED)				ret = 0;			break;		}	}	rcu_read_unlock();	return ret; /* Audit by default */}int audit_filter_type(int type){	struct audit_entry *e;	int result = 0;		rcu_read_lock();	if (list_empty(&audit_filter_list[AUDIT_FILTER_TYPE]))		goto unlock_and_return;	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TYPE],				list) {		int i;		for (i = 0; i < e->rule.field_count; i++) {			struct audit_field *f = &e->rule.fields[i];			if (f->type == AUDIT_MSGTYPE) {				result = audit_comparator(type, f->op, f->val);				if (!result)					break;			}		}		if (result)			goto unlock_and_return;	}unlock_and_return:	rcu_read_unlock();	return result;}/* Check to see if the rule contains any selinux fields.  Returns 1 if there   are selinux fields specified in the rule, 0 otherwise. */static inline int audit_rule_has_selinux(struct audit_krule *rule){	int i;	for (i = 0; i < rule->field_count; i++) {		struct audit_field *f = &rule->fields[i];		switch (f->type) {		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:			return 1;		}	}	return 0;}/* This function will re-initialize the se_rule field of all applicable rules. * It will traverse the filter lists serarching for rules that contain selinux * specific filter fields.  When such a rule is found, it is copied, the * selinux field is re-initialized, and the old rule is replaced with the * updated rule. */int selinux_audit_rule_update(void){	struct audit_entry *entry, *n, *nentry;	struct audit_watch *watch;	int i, err = 0;	/* audit_filter_mutex synchronizes the writers */	mutex_lock(&audit_filter_mutex);	for (i = 0; i < AUDIT_NR_FILTERS; i++) {		list_for_each_entry_safe(entry, n, &audit_filter_list[i], list) {			if (!audit_rule_has_selinux(&entry->rule))				continue;			watch = entry->rule.watch;			nentry = audit_dupe_rule(&entry->rule, watch);			if (unlikely(IS_ERR(nentry))) {				/* save the first error encountered for the				 * return value */				if (!err)					err = PTR_ERR(nentry);				audit_panic("error updating selinux filters");				if (watch)					list_del(&entry->rule.rlist);				list_del_rcu(&entry->list);			} else {				if (watch) {					list_add(&nentry->rule.rlist,						 &watch->rules);					list_del(&entry->rule.rlist);				}				list_replace_rcu(&entry->list, &nentry->list);			}			call_rcu(&entry->rcu, audit_free_rule_rcu);		}	}	mutex_unlock(&audit_filter_mutex);	return err;}/* Update watch data in audit rules based on inotify events. */void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,			 u32 cookie, const char *dname, struct inode *inode){	struct audit_parent *parent;	parent = container_of(i_watch, struct audit_parent, wdata);	if (mask & (IN_CREATE|IN_MOVED_TO) && inode)		audit_update_watch(parent, dname, inode->i_sb->s_dev,				   inode->i_ino, 0);	else if (mask & (IN_DELETE|IN_MOVED_FROM))		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);	/* inotify automatically removes the watch and sends IN_IGNORED */	else if (mask & (IN_DELETE_SELF|IN_UNMOUNT))		audit_remove_parent_watches(parent);	/* inotify does not remove the watch, so remove it manually */	else if(mask & IN_MOVE_SELF) {		audit_remove_parent_watches(parent);		inotify_remove_watch_locked(audit_ih, i_watch);	} else if (mask & IN_IGNORED)		put_inotify_watch(i_watch);}

⌨️ 快捷键说明

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