diff options
Diffstat (limited to 'kernel/audit_watch.c')
| -rw-r--r-- | kernel/audit_watch.c | 115 | 
1 files changed, 33 insertions, 82 deletions
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index d2e3c786646..70b4554d2fb 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -144,9 +144,9 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)  }  /* Initialize a parent watch entry. */ -static struct audit_parent *audit_init_parent(struct nameidata *ndp) +static struct audit_parent *audit_init_parent(struct path *path)  { -	struct inode *inode = ndp->path.dentry->d_inode; +	struct inode *inode = path->dentry->d_inode;  	struct audit_parent *parent;  	int ret; @@ -240,8 +240,10 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc  	if (audit_enabled) {  		struct audit_buffer *ab;  		ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE); +		if (unlikely(!ab)) +			return;  		audit_log_format(ab, "auid=%u ses=%u op=", -				 audit_get_loginuid(current), +				 from_kuid(&init_user_ns, audit_get_loginuid(current)),  				 audit_get_sessionid(current));  		audit_log_string(ab, op);  		audit_log_format(ab, " path="); @@ -265,7 +267,8 @@ static void audit_update_watch(struct audit_parent *parent,  	/* Run all of the watches on this parent looking for the one that  	 * matches the given dname */  	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { -		if (audit_compare_dname_path(dname, owatch->path, NULL)) +		if (audit_compare_dname_path(dname, owatch->path, +					     AUDIT_NAME_FULL))  			continue;  		/* If the update involves invalidating rules, do the inode-based @@ -349,57 +352,25 @@ static void audit_remove_parent_watches(struct audit_parent *parent)  	}  	mutex_unlock(&audit_filter_mutex); -	fsnotify_destroy_mark(&parent->mark); +	fsnotify_destroy_mark(&parent->mark, audit_watch_group);  }  /* Get path information necessary for adding watches. */ -static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw) +static int audit_get_nd(struct audit_watch *watch, struct path *parent)  { -	struct nameidata *ndparent, *ndwatch; -	int err; - -	ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL); -	if (unlikely(!ndparent)) -		return -ENOMEM; - -	ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL); -	if (unlikely(!ndwatch)) { -		kfree(ndparent); -		return -ENOMEM; -	} - -	err = path_lookup(path, LOOKUP_PARENT, ndparent); -	if (err) { -		kfree(ndparent); -		kfree(ndwatch); -		return err; +	struct dentry *d = kern_path_locked(watch->path, parent); +	if (IS_ERR(d)) +		return PTR_ERR(d); +	mutex_unlock(&parent->dentry->d_inode->i_mutex); +	if (d->d_inode) { +		/* update watch filter fields */ +		watch->dev = d->d_inode->i_sb->s_dev; +		watch->ino = d->d_inode->i_ino;  	} - -	err = path_lookup(path, 0, ndwatch); -	if (err) { -		kfree(ndwatch); -		ndwatch = NULL; -	} - -	*ndp = ndparent; -	*ndw = ndwatch; - +	dput(d);  	return 0;  } -/* Release resources used for watch path information. */ -static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw) -{ -	if (ndp) { -		path_put(&ndp->path); -		kfree(ndp); -	} -	if (ndw) { -		path_put(&ndw->path); -		kfree(ndw); -	} -} -  /* Associate the given rule with an existing parent.   * Caller must hold audit_filter_mutex. */  static void audit_add_to_parent(struct audit_krule *krule, @@ -440,31 +411,24 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)  {  	struct audit_watch *watch = krule->watch;  	struct audit_parent *parent; -	struct nameidata *ndp = NULL, *ndw = NULL; +	struct path parent_path;  	int h, ret = 0;  	mutex_unlock(&audit_filter_mutex);  	/* Avoid calling path_lookup under audit_filter_mutex. */ -	ret = audit_get_nd(watch->path, &ndp, &ndw); -	if (ret) { -		/* caller expects mutex locked */ -		mutex_lock(&audit_filter_mutex); -		goto error; -	} +	ret = audit_get_nd(watch, &parent_path); +	/* caller expects mutex locked */  	mutex_lock(&audit_filter_mutex); -	/* update watch filter fields */ -	if (ndw) { -		watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev; -		watch->ino = ndw->path.dentry->d_inode->i_ino; -	} +	if (ret) +		return ret;  	/* either find an old parent or attach a new one */ -	parent = audit_find_parent(ndp->path.dentry->d_inode); +	parent = audit_find_parent(parent_path.dentry->d_inode);  	if (!parent) { -		parent = audit_init_parent(ndp); +		parent = audit_init_parent(&parent_path);  		if (IS_ERR(parent)) {  			ret = PTR_ERR(parent);  			goto error; @@ -479,9 +443,8 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)  	h = audit_hash_ino((u32)watch->ino);  	*list = &audit_inode_hash[h];  error: -	audit_put_nd(ndp, ndw);		/* NULL args OK */ +	path_put(&parent_path);  	return ret; -  }  void audit_remove_watch_rule(struct audit_krule *krule) @@ -496,41 +459,33 @@ void audit_remove_watch_rule(struct audit_krule *krule)  		if (list_empty(&parent->watches)) {  			audit_get_parent(parent); -			fsnotify_destroy_mark(&parent->mark); +			fsnotify_destroy_mark(&parent->mark, audit_watch_group);  			audit_put_parent(parent);  		}  	}  } -static bool audit_watch_should_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 true; -} -  /* Update watch data in audit rules based on fsnotify events. */  static int audit_watch_handle_event(struct fsnotify_group *group, +				    struct inode *to_tell,  				    struct fsnotify_mark *inode_mark,  				    struct fsnotify_mark *vfsmount_mark, -				    struct fsnotify_event *event) +				    u32 mask, void *data, int data_type, +				    const unsigned char *dname, u32 cookie)  {  	struct inode *inode; -	__u32 mask = event->mask; -	const char *dname = event->file_name;  	struct audit_parent *parent;  	parent = container_of(inode_mark, struct audit_parent, mark);  	BUG_ON(group != audit_watch_group); -	switch (event->data_type) { +	switch (data_type) {  	case (FSNOTIFY_EVENT_PATH): -		inode = event->path.dentry->d_inode; +		inode = ((struct path *)data)->dentry->d_inode;  		break;  	case (FSNOTIFY_EVENT_INODE): -		inode = event->inode; +		inode = (struct inode *)data;  		break;  	default:  		BUG(); @@ -549,11 +504,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,  }  static const struct fsnotify_ops audit_watch_fsnotify_ops = { -	.should_send_event = 	audit_watch_should_send_event,  	.handle_event = 	audit_watch_handle_event, -	.free_group_priv = 	NULL, -	.freeing_mark = 	NULL, -	.free_event_priv = 	NULL,  };  static int __init audit_watch_init(void)  | 
