Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs namei updates from Al Viro:
 "Pathwalk-related stuff"

[ Audit-related cleanups, misc simplifications, and easier to follow
  nd->root refcounts     - Linus ]

* 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  devpts_pty_kill(): don't bother with d_delete()
  infiniband: don't bother with d_delete()
  hypfs: don't bother with d_delete()
  fs/namei.c: keep track of nd->root refcount status
  fs/namei.c: new helper - legitimize_root()
  kill the last users of user_{path,lpath,path_dir}()
  namei.h: get the comments on LOOKUP_... in sync with reality
  kill LOOKUP_NO_EVAL, don't bother including namei.h from audit.h
  audit_inode(): switch to passing AUDIT_INODE_...
  filename_mountpoint(): make LOOKUP_NO_EVAL unconditional there
  filename_lookup(): audit_inode() argument is always 0
This commit is contained in:
Linus Torvalds 2019-09-18 13:03:01 -07:00
commit 53e5e7a7a7
10 changed files with 63 additions and 110 deletions

View File

@ -76,7 +76,7 @@ static void hypfs_remove(struct dentry *dentry)
else else
simple_unlink(d_inode(parent), dentry); simple_unlink(d_inode(parent), dentry);
} }
d_delete(dentry); d_drop(dentry);
dput(dentry); dput(dentry);
inode_unlock(d_inode(parent)); inode_unlock(d_inode(parent));
} }

View File

@ -493,7 +493,7 @@ static int remove_device_files(struct super_block *sb,
remove_file(dir, "flash"); remove_file(dir, "flash");
inode_unlock(d_inode(dir)); inode_unlock(d_inode(dir));
ret = simple_rmdir(d_inode(root), dir); ret = simple_rmdir(d_inode(root), dir);
d_delete(dir); d_drop(dir);
dput(dir); dput(dir);
bail: bail:

View File

@ -63,11 +63,8 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
* Look up the pathname. Note that the pathname is in * Look up the pathname. Note that the pathname is in
* user memory, and namei takes care of this * user memory, and namei takes care of this
*/ */
if (data.follow) error = user_path_at(AT_FDCWD, data.path,
error = user_path(data.path, &path); data.follow ? LOOKUP_FOLLOW : 0, &path);
else
error = user_lpath(data.path, &path);
if (error) if (error)
return error; return error;

View File

@ -622,7 +622,7 @@ void devpts_pty_kill(struct dentry *dentry)
dentry->d_fsdata = NULL; dentry->d_fsdata = NULL;
drop_nlink(dentry->d_inode); drop_nlink(dentry->d_inode);
fsnotify_unlink(d_inode(dentry->d_parent), dentry); fsnotify_unlink(d_inode(dentry->d_parent), dentry);
d_delete(dentry); d_drop(dentry);
dput(dentry); /* d_alloc_name() in devpts_pty_new() */ dput(dentry); /* d_alloc_name() in devpts_pty_new() */
} }

View File

@ -596,14 +596,12 @@ static void terminate_walk(struct nameidata *nd)
path_put(&nd->path); path_put(&nd->path);
for (i = 0; i < nd->depth; i++) for (i = 0; i < nd->depth; i++)
path_put(&nd->stack[i].link); path_put(&nd->stack[i].link);
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { if (nd->flags & LOOKUP_ROOT_GRABBED) {
path_put(&nd->root); path_put(&nd->root);
nd->root.mnt = NULL; nd->flags &= ~LOOKUP_ROOT_GRABBED;
} }
} else { } else {
nd->flags &= ~LOOKUP_RCU; nd->flags &= ~LOOKUP_RCU;
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
rcu_read_unlock(); rcu_read_unlock();
} }
nd->depth = 0; nd->depth = 0;
@ -641,6 +639,14 @@ static bool legitimize_links(struct nameidata *nd)
return true; return true;
} }
static bool legitimize_root(struct nameidata *nd)
{
if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))
return true;
nd->flags |= LOOKUP_ROOT_GRABBED;
return legitimize_path(nd, &nd->root, nd->root_seq);
}
/* /*
* Path walking has 2 modes, rcu-walk and ref-walk (see * Path walking has 2 modes, rcu-walk and ref-walk (see
* Documentation/filesystems/path-lookup.txt). In situations when we can't * Documentation/filesystems/path-lookup.txt). In situations when we can't
@ -671,23 +677,18 @@ static int unlazy_walk(struct nameidata *nd)
nd->flags &= ~LOOKUP_RCU; nd->flags &= ~LOOKUP_RCU;
if (unlikely(!legitimize_links(nd))) if (unlikely(!legitimize_links(nd)))
goto out2;
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
goto out1; goto out1;
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq))) goto out;
goto out; if (unlikely(!legitimize_root(nd)))
} goto out;
rcu_read_unlock(); rcu_read_unlock();
BUG_ON(nd->inode != parent->d_inode); BUG_ON(nd->inode != parent->d_inode);
return 0; return 0;
out2: out1:
nd->path.mnt = NULL; nd->path.mnt = NULL;
nd->path.dentry = NULL; nd->path.dentry = NULL;
out1:
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
out: out:
rcu_read_unlock(); rcu_read_unlock();
return -ECHILD; return -ECHILD;
@ -727,23 +728,14 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se
*/ */
if (unlikely(!lockref_get_not_dead(&dentry->d_lockref))) if (unlikely(!lockref_get_not_dead(&dentry->d_lockref)))
goto out; goto out;
if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) { if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
rcu_read_unlock(); goto out_dput;
dput(dentry);
goto drop_root_mnt;
}
/* /*
* Sequence counts matched. Now make sure that the root is * Sequence counts matched. Now make sure that the root is
* still valid and get it if required. * still valid and get it if required.
*/ */
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { if (unlikely(!legitimize_root(nd)))
if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq))) { goto out_dput;
rcu_read_unlock();
dput(dentry);
return -ECHILD;
}
}
rcu_read_unlock(); rcu_read_unlock();
return 0; return 0;
@ -753,9 +745,10 @@ out1:
nd->path.dentry = NULL; nd->path.dentry = NULL;
out: out:
rcu_read_unlock(); rcu_read_unlock();
drop_root_mnt: return -ECHILD;
if (!(nd->flags & LOOKUP_ROOT)) out_dput:
nd->root.mnt = NULL; rcu_read_unlock();
dput(dentry);
return -ECHILD; return -ECHILD;
} }
@ -819,6 +812,7 @@ static void set_root(struct nameidata *nd)
} while (read_seqcount_retry(&fs->seq, seq)); } while (read_seqcount_retry(&fs->seq, seq));
} else { } else {
get_fs_root(fs, &nd->root); get_fs_root(fs, &nd->root);
nd->flags |= LOOKUP_ROOT_GRABBED;
} }
} }
@ -1735,8 +1729,6 @@ static int pick_link(struct nameidata *nd, struct path *link,
nd->flags &= ~LOOKUP_RCU; nd->flags &= ~LOOKUP_RCU;
nd->path.mnt = NULL; nd->path.mnt = NULL;
nd->path.dentry = NULL; nd->path.dentry = NULL;
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
rcu_read_unlock(); rcu_read_unlock();
} else if (likely(unlazy_walk(nd)) == 0) } else if (likely(unlazy_walk(nd)) == 0)
error = nd_alloc_stack(nd); error = nd_alloc_stack(nd);
@ -2350,7 +2342,7 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path); retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path);
if (likely(!retval)) if (likely(!retval))
audit_inode(name, path->dentry, flags & LOOKUP_PARENT); audit_inode(name, path->dentry, 0);
restore_nameidata(); restore_nameidata();
putname(name); putname(name);
return retval; return retval;
@ -2391,7 +2383,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
if (likely(!retval)) { if (likely(!retval)) {
*last = nd.last; *last = nd.last;
*type = nd.last_type; *type = nd.last_type;
audit_inode(name, parent->dentry, LOOKUP_PARENT); audit_inode(name, parent->dentry, AUDIT_INODE_PARENT);
} else { } else {
putname(name); putname(name);
name = ERR_PTR(retval); name = ERR_PTR(retval);
@ -2718,7 +2710,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path,
if (unlikely(error == -ESTALE)) if (unlikely(error == -ESTALE))
error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path); error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path);
if (likely(!error)) if (likely(!error))
audit_inode(name, path->dentry, flags & LOOKUP_NO_EVAL); audit_inode(name, path->dentry, AUDIT_INODE_NOEVAL);
restore_nameidata(); restore_nameidata();
putname(name); putname(name);
return error; return error;
@ -3299,7 +3291,7 @@ static int do_last(struct nameidata *nd,
if (error) if (error)
return error; return error;
audit_inode(nd->name, dir, LOOKUP_PARENT); audit_inode(nd->name, dir, AUDIT_INODE_PARENT);
/* trailing slashes? */ /* trailing slashes? */
if (unlikely(nd->last.name[nd->last.len])) if (unlikely(nd->last.name[nd->last.len]))
return -EISDIR; return -EISDIR;

View File

@ -1675,8 +1675,6 @@ int ksys_umount(char __user *name, int flags)
if (!(flags & UMOUNT_NOFOLLOW)) if (!(flags & UMOUNT_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW; lookup_flags |= LOOKUP_FOLLOW;
lookup_flags |= LOOKUP_NO_EVAL;
retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path); retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
if (retval) if (retval)
goto out; goto out;
@ -3046,7 +3044,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
return -EINVAL; return -EINVAL;
/* ... and get the mountpoint */ /* ... and get the mountpoint */
retval = user_path(dir_name, &path); retval = user_path_at(AT_FDCWD, dir_name, LOOKUP_FOLLOW, &path);
if (retval) if (retval)
return retval; return retval;
@ -3593,11 +3591,13 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
if (!may_mount()) if (!may_mount())
return -EPERM; return -EPERM;
error = user_path_dir(new_root, &new); error = user_path_at(AT_FDCWD, new_root,
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new);
if (error) if (error)
goto out0; goto out0;
error = user_path_dir(put_old, &old); error = user_path_at(AT_FDCWD, put_old,
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old);
if (error) if (error)
goto out1; goto out1;

View File

@ -207,7 +207,6 @@ TRACE_DEFINE_ENUM(LOOKUP_PARENT);
TRACE_DEFINE_ENUM(LOOKUP_REVAL); TRACE_DEFINE_ENUM(LOOKUP_REVAL);
TRACE_DEFINE_ENUM(LOOKUP_RCU); TRACE_DEFINE_ENUM(LOOKUP_RCU);
TRACE_DEFINE_ENUM(LOOKUP_NO_REVAL); TRACE_DEFINE_ENUM(LOOKUP_NO_REVAL);
TRACE_DEFINE_ENUM(LOOKUP_NO_EVAL);
TRACE_DEFINE_ENUM(LOOKUP_OPEN); TRACE_DEFINE_ENUM(LOOKUP_OPEN);
TRACE_DEFINE_ENUM(LOOKUP_CREATE); TRACE_DEFINE_ENUM(LOOKUP_CREATE);
TRACE_DEFINE_ENUM(LOOKUP_EXCL); TRACE_DEFINE_ENUM(LOOKUP_EXCL);
@ -226,7 +225,6 @@ TRACE_DEFINE_ENUM(LOOKUP_DOWN);
{ LOOKUP_REVAL, "REVAL" }, \ { LOOKUP_REVAL, "REVAL" }, \
{ LOOKUP_RCU, "RCU" }, \ { LOOKUP_RCU, "RCU" }, \
{ LOOKUP_NO_REVAL, "NO_REVAL" }, \ { LOOKUP_NO_REVAL, "NO_REVAL" }, \
{ LOOKUP_NO_EVAL, "NO_EVAL" }, \
{ LOOKUP_OPEN, "OPEN" }, \ { LOOKUP_OPEN, "OPEN" }, \
{ LOOKUP_CREATE, "CREATE" }, \ { LOOKUP_CREATE, "CREATE" }, \
{ LOOKUP_EXCL, "EXCL" }, \ { LOOKUP_EXCL, "EXCL" }, \

View File

@ -67,7 +67,7 @@ xfs_find_handle(
return -EBADF; return -EBADF;
inode = file_inode(f.file); inode = file_inode(f.file);
} else { } else {
error = user_lpath((const char __user *)hreq->path, &path); error = user_path_at(AT_FDCWD, hreq->path, 0, &path);
if (error) if (error)
return error; return error;
inode = d_inode(path.dentry); inode = d_inode(path.dentry);

View File

@ -11,7 +11,6 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/namei.h> /* LOOKUP_* */
#include <uapi/linux/audit.h> #include <uapi/linux/audit.h>
#define AUDIT_INO_UNSET ((unsigned long)-1) #define AUDIT_INO_UNSET ((unsigned long)-1)
@ -252,6 +251,10 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
#define audit_is_compat(arch) false #define audit_is_compat(arch) false
#endif #endif
#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */
#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
#define AUDIT_INODE_NOEVAL 4 /* audit record incomplete */
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
#include <asm/syscall.h> /* for syscall_get_arch() */ #include <asm/syscall.h> /* for syscall_get_arch() */
@ -265,9 +268,6 @@ extern void __audit_syscall_exit(int ret_success, long ret_value);
extern struct filename *__audit_reusename(const __user char *uptr); extern struct filename *__audit_reusename(const __user char *uptr);
extern void __audit_getname(struct filename *name); extern void __audit_getname(struct filename *name);
#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */
#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
#define AUDIT_INODE_NOEVAL 4 /* audit record incomplete */
extern void __audit_inode(struct filename *name, const struct dentry *dentry, extern void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int flags); unsigned int flags);
extern void __audit_file(const struct file *); extern void __audit_file(const struct file *);
@ -328,16 +328,9 @@ static inline void audit_getname(struct filename *name)
} }
static inline void audit_inode(struct filename *name, static inline void audit_inode(struct filename *name,
const struct dentry *dentry, const struct dentry *dentry,
unsigned int flags) { unsigned int aflags) {
if (unlikely(!audit_dummy_context())) { if (unlikely(!audit_dummy_context()))
unsigned int aflags = 0;
if (flags & LOOKUP_PARENT)
aflags |= AUDIT_INODE_PARENT;
if (flags & LOOKUP_NO_EVAL)
aflags |= AUDIT_INODE_NOEVAL;
__audit_inode(name, dentry, aflags); __audit_inode(name, dentry, aflags);
}
} }
static inline void audit_file(struct file *file) static inline void audit_file(struct file *file)
{ {
@ -561,7 +554,7 @@ static inline void __audit_inode_child(struct inode *parent,
{ } { }
static inline void audit_inode(struct filename *name, static inline void audit_inode(struct filename *name,
const struct dentry *dentry, const struct dentry *dentry,
unsigned int parent) unsigned int aflags)
{ } { }
static inline void audit_file(struct file *file) static inline void audit_file(struct file *file)
{ {

View File

@ -16,39 +16,28 @@ enum { MAX_NESTED_LINKS = 8 };
*/ */
enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
/* /* pathwalk mode */
* The bitmask for a lookup event: #define LOOKUP_FOLLOW 0x0001 /* follow links at the end */
* - follow links at the end #define LOOKUP_DIRECTORY 0x0002 /* require a directory */
* - require a directory #define LOOKUP_AUTOMOUNT 0x0004 /* force terminal automount */
* - ending slashes ok even for nonexistent files #define LOOKUP_EMPTY 0x4000 /* accept empty path [user_... only] */
* - internal "there are more path components" flag #define LOOKUP_DOWN 0x8000 /* follow mounts in the starting point */
* - dentry cache is untrusted; force a real lookup
* - suppress terminal automount
* - skip revalidation
* - don't fetch xattrs on audit_inode
*/
#define LOOKUP_FOLLOW 0x0001
#define LOOKUP_DIRECTORY 0x0002
#define LOOKUP_AUTOMOUNT 0x0004
#define LOOKUP_REVAL 0x0020 /* tell ->d_revalidate() to trust no cache */
#define LOOKUP_RCU 0x0040 /* RCU pathwalk mode; semi-internal */
/* These tell filesystem methods that we are dealing with the final component... */
#define LOOKUP_OPEN 0x0100 /* ... in open */
#define LOOKUP_CREATE 0x0200 /* ... in object creation */
#define LOOKUP_EXCL 0x0400 /* ... in exclusive creation */
#define LOOKUP_RENAME_TARGET 0x0800 /* ... in destination of rename() */
/* internal use only */
#define LOOKUP_PARENT 0x0010 #define LOOKUP_PARENT 0x0010
#define LOOKUP_REVAL 0x0020
#define LOOKUP_RCU 0x0040
#define LOOKUP_NO_REVAL 0x0080 #define LOOKUP_NO_REVAL 0x0080
#define LOOKUP_NO_EVAL 0x0100
/*
* Intent data
*/
#define LOOKUP_OPEN 0x0100
#define LOOKUP_CREATE 0x0200
#define LOOKUP_EXCL 0x0400
#define LOOKUP_RENAME_TARGET 0x0800
#define LOOKUP_JUMPED 0x1000 #define LOOKUP_JUMPED 0x1000
#define LOOKUP_ROOT 0x2000 #define LOOKUP_ROOT 0x2000
#define LOOKUP_EMPTY 0x4000 #define LOOKUP_ROOT_GRABBED 0x0008
#define LOOKUP_DOWN 0x8000
extern int path_pts(struct path *path); extern int path_pts(struct path *path);
@ -60,22 +49,6 @@ static inline int user_path_at(int dfd, const char __user *name, unsigned flags,
return user_path_at_empty(dfd, name, flags, path, NULL); return user_path_at_empty(dfd, name, flags, path, NULL);
} }
static inline int user_path(const char __user *name, struct path *path)
{
return user_path_at_empty(AT_FDCWD, name, LOOKUP_FOLLOW, path, NULL);
}
static inline int user_lpath(const char __user *name, struct path *path)
{
return user_path_at_empty(AT_FDCWD, name, 0, path, NULL);
}
static inline int user_path_dir(const char __user *name, struct path *path)
{
return user_path_at_empty(AT_FDCWD, name,
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path, NULL);
}
extern int kern_path(const char *, unsigned, struct path *); extern int kern_path(const char *, unsigned, struct path *);
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);