diff options
Diffstat (limited to 'kernel/audit_tree.c')
| -rw-r--r-- | kernel/audit_tree.c | 96 | 
1 files changed, 47 insertions, 49 deletions
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 37b2bea170c..135944a7b28 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -93,16 +93,10 @@ static inline void get_tree(struct audit_tree *tree)  	atomic_inc(&tree->count);  } -static void __put_tree(struct rcu_head *rcu) -{ -	struct audit_tree *tree = container_of(rcu, struct audit_tree, head); -	kfree(tree); -} -  static inline void put_tree(struct audit_tree *tree)  {  	if (atomic_dec_and_test(&tree->count)) -		call_rcu(&tree->head, __put_tree); +		kfree_rcu(tree, head);  }  /* to avoid bringing the entire thing in audit.h */ @@ -255,8 +249,7 @@ static void untag_chunk(struct node *p)  		list_del_rcu(&chunk->hash);  		spin_unlock(&hash_lock);  		spin_unlock(&entry->lock); -		fsnotify_destroy_mark(entry); -		fsnotify_put_mark(entry); +		fsnotify_destroy_mark(entry, audit_tree_group);  		goto out;  	} @@ -265,7 +258,7 @@ static void untag_chunk(struct node *p)  	fsnotify_duplicate_mark(&new->mark, entry);  	if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { -		free_chunk(new); +		fsnotify_put_mark(&new->mark);  		goto Fallback;  	} @@ -298,8 +291,8 @@ static void untag_chunk(struct node *p)  		owner->root = new;  	spin_unlock(&hash_lock);  	spin_unlock(&entry->lock); -	fsnotify_destroy_mark(entry); -	fsnotify_put_mark(entry); +	fsnotify_destroy_mark(entry, audit_tree_group); +	fsnotify_put_mark(&new->mark);	/* drop initial reference */  	goto out;  Fallback: @@ -328,7 +321,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)  	entry = &chunk->mark;  	if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) { -		free_chunk(chunk); +		fsnotify_put_mark(entry);  		return -ENOSPC;  	} @@ -338,7 +331,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)  		spin_unlock(&hash_lock);  		chunk->dead = 1;  		spin_unlock(&entry->lock); -		fsnotify_destroy_mark(entry); +		fsnotify_destroy_mark(entry, audit_tree_group);  		fsnotify_put_mark(entry);  		return 0;  	} @@ -353,6 +346,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)  	insert_hash(chunk);  	spin_unlock(&hash_lock);  	spin_unlock(&entry->lock); +	fsnotify_put_mark(entry);	/* drop initial reference */  	return 0;  } @@ -402,7 +396,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)  	fsnotify_duplicate_mark(chunk_entry, old_entry);  	if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) {  		spin_unlock(&old_entry->lock); -		free_chunk(chunk); +		fsnotify_put_mark(chunk_entry);  		fsnotify_put_mark(old_entry);  		return -ENOSPC;  	} @@ -418,7 +412,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)  		spin_unlock(&chunk_entry->lock);  		spin_unlock(&old_entry->lock); -		fsnotify_destroy_mark(chunk_entry); +		fsnotify_destroy_mark(chunk_entry, audit_tree_group);  		fsnotify_put_mark(chunk_entry);  		fsnotify_put_mark(old_entry); @@ -449,17 +443,32 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)  	spin_unlock(&hash_lock);  	spin_unlock(&chunk_entry->lock);  	spin_unlock(&old_entry->lock); -	fsnotify_destroy_mark(old_entry); +	fsnotify_destroy_mark(old_entry, audit_tree_group); +	fsnotify_put_mark(chunk_entry);	/* drop initial reference */  	fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ -	fsnotify_put_mark(old_entry); /* and kill it */  	return 0;  } +static void audit_log_remove_rule(struct audit_krule *rule) +{ +	struct audit_buffer *ab; + +	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); +	if (unlikely(!ab)) +		return; +	audit_log_format(ab, "op="); +	audit_log_string(ab, "remove rule"); +	audit_log_format(ab, " dir="); +	audit_log_untrustedstring(ab, rule->tree->pathname); +	audit_log_key(ab, rule->filterkey); +	audit_log_format(ab, " list=%d res=1", rule->listnr); +	audit_log_end(ab); +} +  static void kill_rules(struct audit_tree *tree)  {  	struct audit_krule *rule, *next;  	struct audit_entry *entry; -	struct audit_buffer *ab;  	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {  		entry = container_of(rule, struct audit_entry, rule); @@ -467,14 +476,7 @@ static void kill_rules(struct audit_tree *tree)  		list_del_init(&rule->rlist);  		if (rule->tree) {  			/* not a half-baked one */ -			ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); -			audit_log_format(ab, "op="); -			audit_log_string(ab, "remove rule"); -			audit_log_format(ab, " dir="); -			audit_log_untrustedstring(ab, rule->tree->pathname); -			audit_log_key(ab, rule->filterkey); -			audit_log_format(ab, " list=%d res=1", rule->listnr); -			audit_log_end(ab); +			audit_log_remove_rule(rule);  			rule->tree = NULL;  			list_del_rcu(&entry->list);  			list_del(&entry->rule.list); @@ -601,13 +603,13 @@ void audit_trim_trees(void)  		root_mnt = collect_mounts(&path);  		path_put(&path); -		if (!root_mnt) +		if (IS_ERR(root_mnt))  			goto skip_it;  		spin_lock(&hash_lock);  		list_for_each_entry(node, &tree->chunks, list) {  			struct audit_chunk *chunk = find_chunk(node); -			/* this could be NULL if the watch is dieing else where... */ +			/* this could be NULL if the watch is dying else where... */  			struct inode *inode = chunk->mark.i.inode;  			node->index |= 1U<<31;  			if (iterate_mounts(compare_root, inode, root_mnt)) @@ -615,9 +617,9 @@ void audit_trim_trees(void)  		}  		spin_unlock(&hash_lock);  		trim_marked(tree); -		put_tree(tree);  		drop_collected_mounts(root_mnt);  skip_it: +		put_tree(tree);  		mutex_lock(&audit_filter_mutex);  	}  	list_del(&cursor); @@ -656,6 +658,7 @@ int audit_add_tree_rule(struct audit_krule *rule)  	struct vfsmount *mnt;  	int err; +	rule->tree = NULL;  	list_for_each_entry(tree, &tree_list, list) {  		if (!strcmp(seed->pathname, tree->pathname)) {  			put_tree(seed); @@ -675,8 +678,8 @@ int audit_add_tree_rule(struct audit_krule *rule)  		goto Err;  	mnt = collect_mounts(&path);  	path_put(&path); -	if (!mnt) { -		err = -ENOMEM; +	if (IS_ERR(mnt)) { +		err = PTR_ERR(mnt);  		goto Err;  	} @@ -725,8 +728,8 @@ int audit_tag_tree(char *old, char *new)  		return err;  	tagged = collect_mounts(&path2);  	path_put(&path2); -	if (!tagged) -		return -ENOMEM; +	if (IS_ERR(tagged)) +		return PTR_ERR(tagged);  	err = kern_path(old, 0, &path1);  	if (err) { @@ -909,12 +912,13 @@ static void evict_chunk(struct audit_chunk *chunk)  }  static int audit_tree_handle_event(struct fsnotify_group *group, +				   struct inode *to_tell,  				   struct fsnotify_mark *inode_mark, -				   struct fsnotify_mark *vfsmonut_mark, -				   struct fsnotify_event *event) +				   struct fsnotify_mark *vfsmount_mark, +				   u32 mask, void *data, int data_type, +				   const unsigned char *file_name, u32 cookie)  { -	BUG(); -	return -EOPNOTSUPP; +	return 0;  }  static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group) @@ -922,22 +926,16 @@ static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify  	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);  	evict_chunk(chunk); -	fsnotify_put_mark(entry); -} -static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, -				  struct fsnotify_mark *inode_mark, -				  struct fsnotify_mark *vfsmount_mark, -				  __u32 mask, void *data, int data_type) -{ -	return false; +	/* +	 * We are guaranteed to have at least one reference to the mark from +	 * either the inode or the caller of fsnotify_destroy_mark(). +	 */ +	BUG_ON(atomic_read(&entry->refcnt) < 1);  }  static const struct fsnotify_ops audit_tree_ops = {  	.handle_event = audit_tree_handle_event, -	.should_send_event = audit_tree_send_event, -	.free_group_priv = NULL, -	.free_event_priv = NULL,  	.freeing_mark = audit_tree_freeing_mark,  };  | 
