mirror of https://github.com/torvalds/linux.git
VFS/audit: introduce kern_path_parent() for audit
audit_alloc_mark() and audit_get_nd() both need to perform a path lookup getting the parent dentry (which must exist) and the final target (following a LAST_NORM name) which sometimes doesn't need to exist. They don't need the parent to be locked, but use kern_path_locked() or kern_path_locked_negative() anyway. This is somewhat misleading to the casual reader. This patch introduces a more targeted function, kern_path_parent(), which returns not holding locks. On success the "path" will be set to the parent, which must be found, and the return value is the dentry of the target, which might be negative. This will clear the way to rename kern_path_locked() which is otherwise only used to prepare for removing something. It also allows us to remove kern_path_locked_negative(), which is transformed into the new kern_path_parent(). Signed-off-by: NeilBrown <neil@brown.name> Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
d7fb2c4102
commit
76a53de6f7
23
fs/namei.c
23
fs/namei.c
|
|
@ -2781,7 +2781,20 @@ static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dentry *kern_path_locked_negative(const char *name, struct path *path)
|
/**
|
||||||
|
* kern_path_parent: lookup path returning parent and target
|
||||||
|
* @name: path name
|
||||||
|
* @path: path to store parent in
|
||||||
|
*
|
||||||
|
* The path @name should end with a normal component, not "." or ".." or "/".
|
||||||
|
* A lookup is performed and if successful the parent information
|
||||||
|
* is store in @parent and the dentry is returned.
|
||||||
|
*
|
||||||
|
* The dentry maybe negative, the parent will be positive.
|
||||||
|
*
|
||||||
|
* Returns: dentry or error.
|
||||||
|
*/
|
||||||
|
struct dentry *kern_path_parent(const char *name, struct path *path)
|
||||||
{
|
{
|
||||||
struct path parent_path __free(path_put) = {};
|
struct path parent_path __free(path_put) = {};
|
||||||
struct filename *filename __free(putname) = getname_kernel(name);
|
struct filename *filename __free(putname) = getname_kernel(name);
|
||||||
|
|
@ -2794,12 +2807,10 @@ struct dentry *kern_path_locked_negative(const char *name, struct path *path)
|
||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
if (unlikely(type != LAST_NORM))
|
if (unlikely(type != LAST_NORM))
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
|
|
||||||
d = lookup_one_qstr_excl(&last, parent_path.dentry, LOOKUP_CREATE);
|
d = lookup_noperm_unlocked(&last, parent_path.dentry);
|
||||||
if (IS_ERR(d)) {
|
if (IS_ERR(d))
|
||||||
inode_unlock(parent_path.dentry->d_inode);
|
|
||||||
return d;
|
return d;
|
||||||
}
|
|
||||||
path->dentry = no_free_ptr(parent_path.dentry);
|
path->dentry = no_free_ptr(parent_path.dentry);
|
||||||
path->mnt = no_free_ptr(parent_path.mnt);
|
path->mnt = no_free_ptr(parent_path.mnt);
|
||||||
return d;
|
return d;
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,12 @@ struct dentry *lookup_one_qstr_excl(const struct qstr *name,
|
||||||
struct dentry *base,
|
struct dentry *base,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
extern int kern_path(const char *, unsigned, struct path *);
|
extern int kern_path(const char *, unsigned, struct path *);
|
||||||
|
struct dentry *kern_path_parent(const char *name, struct path *parent);
|
||||||
|
|
||||||
extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
|
extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
|
||||||
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
||||||
extern void done_path_create(struct path *, struct dentry *);
|
extern void done_path_create(struct path *, struct dentry *);
|
||||||
extern struct dentry *kern_path_locked(const char *, struct path *);
|
extern struct dentry *kern_path_locked(const char *, struct path *);
|
||||||
extern struct dentry *kern_path_locked_negative(const char *, struct path *);
|
|
||||||
extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
|
extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
|
||||||
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
|
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
|
||||||
struct path *parent, struct qstr *last, int *type,
|
struct path *parent, struct qstr *last, int *type,
|
||||||
|
|
|
||||||
|
|
@ -76,17 +76,18 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
|
||||||
struct audit_fsnotify_mark *audit_mark;
|
struct audit_fsnotify_mark *audit_mark;
|
||||||
struct path path;
|
struct path path;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct inode *inode;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (pathname[0] != '/' || pathname[len-1] == '/')
|
if (pathname[0] != '/' || pathname[len-1] == '/')
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
dentry = kern_path_locked(pathname, &path);
|
dentry = kern_path_parent(pathname, &path);
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
return ERR_CAST(dentry); /* returning an error */
|
return ERR_CAST(dentry); /* returning an error */
|
||||||
inode = path.dentry->d_inode;
|
if (d_really_is_negative(dentry)) {
|
||||||
inode_unlock(inode);
|
audit_mark = ERR_PTR(-ENOENT);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
|
audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
|
||||||
if (unlikely(!audit_mark)) {
|
if (unlikely(!audit_mark)) {
|
||||||
|
|
@ -100,7 +101,7 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
|
||||||
audit_update_mark(audit_mark, dentry->d_inode);
|
audit_update_mark(audit_mark, dentry->d_inode);
|
||||||
audit_mark->rule = krule;
|
audit_mark->rule = krule;
|
||||||
|
|
||||||
ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, 0);
|
ret = fsnotify_add_inode_mark(&audit_mark->mark, path.dentry->d_inode, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
audit_mark->path = NULL;
|
audit_mark->path = NULL;
|
||||||
fsnotify_put_mark(&audit_mark->mark);
|
fsnotify_put_mark(&audit_mark->mark);
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,7 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
|
||||||
{
|
{
|
||||||
struct dentry *d;
|
struct dentry *d;
|
||||||
|
|
||||||
d = kern_path_locked_negative(watch->path, parent);
|
d = kern_path_parent(watch->path, parent);
|
||||||
if (IS_ERR(d))
|
if (IS_ERR(d))
|
||||||
return PTR_ERR(d);
|
return PTR_ERR(d);
|
||||||
|
|
||||||
|
|
@ -359,7 +359,6 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
|
||||||
watch->ino = d_backing_inode(d)->i_ino;
|
watch->ino = d_backing_inode(d)->i_ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
inode_unlock(d_backing_inode(parent->dentry));
|
|
||||||
dput(d);
|
dput(d);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue