|
@@ -144,9 +144,9 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
|
|
}
|
|
}
|
|
|
|
|
|
/* Initialize a parent watch entry. */
|
|
/* 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;
|
|
struct audit_parent *parent;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
@@ -353,53 +353,40 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
|
|
}
|
|
}
|
|
|
|
|
|
/* Get path information necessary for adding watches. */
|
|
/* 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;
|
|
|
|
|
|
+ struct nameidata nd;
|
|
|
|
+ struct dentry *d;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
- ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
|
|
|
|
- if (unlikely(!ndparent))
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ err = path_lookup(watch->path, LOOKUP_PARENT, &nd);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
|
|
- ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
|
|
|
|
- if (unlikely(!ndwatch)) {
|
|
|
|
- kfree(ndparent);
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ if (nd.last_type != LAST_NORM) {
|
|
|
|
+ path_put(&nd.path);
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
- err = path_lookup(path, LOOKUP_PARENT, ndparent);
|
|
|
|
- if (err) {
|
|
|
|
- kfree(ndparent);
|
|
|
|
- kfree(ndwatch);
|
|
|
|
- return err;
|
|
|
|
|
|
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
|
|
|
+ d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
|
|
|
|
+ if (IS_ERR(d)) {
|
|
|
|
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
|
|
|
+ path_put(&nd.path);
|
|
|
|
+ return PTR_ERR(d);
|
|
}
|
|
}
|
|
-
|
|
|
|
- err = path_lookup(path, 0, ndwatch);
|
|
|
|
- if (err) {
|
|
|
|
- kfree(ndwatch);
|
|
|
|
- ndwatch = NULL;
|
|
|
|
|
|
+ if (d->d_inode) {
|
|
|
|
+ /* update watch filter fields */
|
|
|
|
+ watch->dev = d->d_inode->i_sb->s_dev;
|
|
|
|
+ watch->ino = d->d_inode->i_ino;
|
|
}
|
|
}
|
|
|
|
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
|
|
|
|
|
- *ndp = ndparent;
|
|
|
|
- *ndw = ndwatch;
|
|
|
|
-
|
|
|
|
|
|
+ *parent = nd.path;
|
|
|
|
+ dput(d);
|
|
return 0;
|
|
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.
|
|
/* Associate the given rule with an existing parent.
|
|
* Caller must hold audit_filter_mutex. */
|
|
* Caller must hold audit_filter_mutex. */
|
|
static void audit_add_to_parent(struct audit_krule *krule,
|
|
static void audit_add_to_parent(struct audit_krule *krule,
|
|
@@ -440,31 +427,24 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
|
|
{
|
|
{
|
|
struct audit_watch *watch = krule->watch;
|
|
struct audit_watch *watch = krule->watch;
|
|
struct audit_parent *parent;
|
|
struct audit_parent *parent;
|
|
- struct nameidata *ndp = NULL, *ndw = NULL;
|
|
|
|
|
|
+ struct path parent_path;
|
|
int h, ret = 0;
|
|
int h, ret = 0;
|
|
|
|
|
|
mutex_unlock(&audit_filter_mutex);
|
|
mutex_unlock(&audit_filter_mutex);
|
|
|
|
|
|
/* Avoid calling path_lookup under 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);
|
|
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 */
|
|
/* 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) {
|
|
if (!parent) {
|
|
- parent = audit_init_parent(ndp);
|
|
|
|
|
|
+ parent = audit_init_parent(&parent_path);
|
|
if (IS_ERR(parent)) {
|
|
if (IS_ERR(parent)) {
|
|
ret = PTR_ERR(parent);
|
|
ret = PTR_ERR(parent);
|
|
goto error;
|
|
goto error;
|
|
@@ -479,9 +459,8 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
|
|
h = audit_hash_ino((u32)watch->ino);
|
|
h = audit_hash_ino((u32)watch->ino);
|
|
*list = &audit_inode_hash[h];
|
|
*list = &audit_inode_hash[h];
|
|
error:
|
|
error:
|
|
- audit_put_nd(ndp, ndw); /* NULL args OK */
|
|
|
|
|
|
+ path_put(&parent_path);
|
|
return ret;
|
|
return ret;
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void audit_remove_watch_rule(struct audit_krule *krule)
|
|
void audit_remove_watch_rule(struct audit_krule *krule)
|