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:
commit
53e5e7a7a7
|
@ -76,7 +76,7 @@ static void hypfs_remove(struct dentry *dentry)
|
|||
else
|
||||
simple_unlink(d_inode(parent), dentry);
|
||||
}
|
||||
d_delete(dentry);
|
||||
d_drop(dentry);
|
||||
dput(dentry);
|
||||
inode_unlock(d_inode(parent));
|
||||
}
|
||||
|
|
|
@ -493,7 +493,7 @@ static int remove_device_files(struct super_block *sb,
|
|||
remove_file(dir, "flash");
|
||||
inode_unlock(d_inode(dir));
|
||||
ret = simple_rmdir(d_inode(root), dir);
|
||||
d_delete(dir);
|
||||
d_drop(dir);
|
||||
dput(dir);
|
||||
|
||||
bail:
|
||||
|
|
|
@ -63,11 +63,8 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
|
|||
* Look up the pathname. Note that the pathname is in
|
||||
* user memory, and namei takes care of this
|
||||
*/
|
||||
if (data.follow)
|
||||
error = user_path(data.path, &path);
|
||||
else
|
||||
error = user_lpath(data.path, &path);
|
||||
|
||||
error = user_path_at(AT_FDCWD, data.path,
|
||||
data.follow ? LOOKUP_FOLLOW : 0, &path);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -622,7 +622,7 @@ void devpts_pty_kill(struct dentry *dentry)
|
|||
dentry->d_fsdata = NULL;
|
||||
drop_nlink(dentry->d_inode);
|
||||
fsnotify_unlink(d_inode(dentry->d_parent), dentry);
|
||||
d_delete(dentry);
|
||||
d_drop(dentry);
|
||||
dput(dentry); /* d_alloc_name() in devpts_pty_new() */
|
||||
}
|
||||
|
||||
|
|
64
fs/namei.c
64
fs/namei.c
|
@ -596,14 +596,12 @@ static void terminate_walk(struct nameidata *nd)
|
|||
path_put(&nd->path);
|
||||
for (i = 0; i < nd->depth; i++)
|
||||
path_put(&nd->stack[i].link);
|
||||
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
|
||||
if (nd->flags & LOOKUP_ROOT_GRABBED) {
|
||||
path_put(&nd->root);
|
||||
nd->root.mnt = NULL;
|
||||
nd->flags &= ~LOOKUP_ROOT_GRABBED;
|
||||
}
|
||||
} else {
|
||||
nd->flags &= ~LOOKUP_RCU;
|
||||
if (!(nd->flags & LOOKUP_ROOT))
|
||||
nd->root.mnt = NULL;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
nd->depth = 0;
|
||||
|
@ -641,6 +639,14 @@ static bool legitimize_links(struct nameidata *nd)
|
|||
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
|
||||
* 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;
|
||||
if (unlikely(!legitimize_links(nd)))
|
||||
goto out2;
|
||||
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
|
||||
goto out1;
|
||||
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
|
||||
if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq)))
|
||||
goto out;
|
||||
}
|
||||
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
|
||||
goto out;
|
||||
if (unlikely(!legitimize_root(nd)))
|
||||
goto out;
|
||||
rcu_read_unlock();
|
||||
BUG_ON(nd->inode != parent->d_inode);
|
||||
return 0;
|
||||
|
||||
out2:
|
||||
out1:
|
||||
nd->path.mnt = NULL;
|
||||
nd->path.dentry = NULL;
|
||||
out1:
|
||||
if (!(nd->flags & LOOKUP_ROOT))
|
||||
nd->root.mnt = NULL;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
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)))
|
||||
goto out;
|
||||
if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) {
|
||||
rcu_read_unlock();
|
||||
dput(dentry);
|
||||
goto drop_root_mnt;
|
||||
}
|
||||
if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
|
||||
goto out_dput;
|
||||
/*
|
||||
* Sequence counts matched. Now make sure that the root is
|
||||
* still valid and get it if required.
|
||||
*/
|
||||
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
|
||||
if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq))) {
|
||||
rcu_read_unlock();
|
||||
dput(dentry);
|
||||
return -ECHILD;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!legitimize_root(nd)))
|
||||
goto out_dput;
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
|
||||
|
@ -753,9 +745,10 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se
|
|||
nd->path.dentry = NULL;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
drop_root_mnt:
|
||||
if (!(nd->flags & LOOKUP_ROOT))
|
||||
nd->root.mnt = NULL;
|
||||
return -ECHILD;
|
||||
out_dput:
|
||||
rcu_read_unlock();
|
||||
dput(dentry);
|
||||
return -ECHILD;
|
||||
}
|
||||
|
||||
|
@ -819,6 +812,7 @@ static void set_root(struct nameidata *nd)
|
|||
} while (read_seqcount_retry(&fs->seq, seq));
|
||||
} else {
|
||||
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->path.mnt = NULL;
|
||||
nd->path.dentry = NULL;
|
||||
if (!(nd->flags & LOOKUP_ROOT))
|
||||
nd->root.mnt = NULL;
|
||||
rcu_read_unlock();
|
||||
} else if (likely(unlazy_walk(nd)) == 0)
|
||||
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);
|
||||
|
||||
if (likely(!retval))
|
||||
audit_inode(name, path->dentry, flags & LOOKUP_PARENT);
|
||||
audit_inode(name, path->dentry, 0);
|
||||
restore_nameidata();
|
||||
putname(name);
|
||||
return retval;
|
||||
|
@ -2391,7 +2383,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
|
|||
if (likely(!retval)) {
|
||||
*last = nd.last;
|
||||
*type = nd.last_type;
|
||||
audit_inode(name, parent->dentry, LOOKUP_PARENT);
|
||||
audit_inode(name, parent->dentry, AUDIT_INODE_PARENT);
|
||||
} else {
|
||||
putname(name);
|
||||
name = ERR_PTR(retval);
|
||||
|
@ -2718,7 +2710,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path,
|
|||
if (unlikely(error == -ESTALE))
|
||||
error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path);
|
||||
if (likely(!error))
|
||||
audit_inode(name, path->dentry, flags & LOOKUP_NO_EVAL);
|
||||
audit_inode(name, path->dentry, AUDIT_INODE_NOEVAL);
|
||||
restore_nameidata();
|
||||
putname(name);
|
||||
return error;
|
||||
|
@ -3299,7 +3291,7 @@ static int do_last(struct nameidata *nd,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
audit_inode(nd->name, dir, LOOKUP_PARENT);
|
||||
audit_inode(nd->name, dir, AUDIT_INODE_PARENT);
|
||||
/* trailing slashes? */
|
||||
if (unlikely(nd->last.name[nd->last.len]))
|
||||
return -EISDIR;
|
||||
|
|
|
@ -1675,8 +1675,6 @@ int ksys_umount(char __user *name, int flags)
|
|||
if (!(flags & UMOUNT_NOFOLLOW))
|
||||
lookup_flags |= LOOKUP_FOLLOW;
|
||||
|
||||
lookup_flags |= LOOKUP_NO_EVAL;
|
||||
|
||||
retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
@ -3046,7 +3044,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
|
|||
return -EINVAL;
|
||||
|
||||
/* ... and get the mountpoint */
|
||||
retval = user_path(dir_name, &path);
|
||||
retval = user_path_at(AT_FDCWD, dir_name, LOOKUP_FOLLOW, &path);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -3593,11 +3591,13 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
|
|||
if (!may_mount())
|
||||
return -EPERM;
|
||||
|
||||
error = user_path_dir(new_root, &new);
|
||||
error = user_path_at(AT_FDCWD, new_root,
|
||||
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new);
|
||||
if (error)
|
||||
goto out0;
|
||||
|
||||
error = user_path_dir(put_old, &old);
|
||||
error = user_path_at(AT_FDCWD, put_old,
|
||||
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old);
|
||||
if (error)
|
||||
goto out1;
|
||||
|
||||
|
|
|
@ -207,7 +207,6 @@ TRACE_DEFINE_ENUM(LOOKUP_PARENT);
|
|||
TRACE_DEFINE_ENUM(LOOKUP_REVAL);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_RCU);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_NO_REVAL);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_NO_EVAL);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_OPEN);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_CREATE);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_EXCL);
|
||||
|
@ -226,7 +225,6 @@ TRACE_DEFINE_ENUM(LOOKUP_DOWN);
|
|||
{ LOOKUP_REVAL, "REVAL" }, \
|
||||
{ LOOKUP_RCU, "RCU" }, \
|
||||
{ LOOKUP_NO_REVAL, "NO_REVAL" }, \
|
||||
{ LOOKUP_NO_EVAL, "NO_EVAL" }, \
|
||||
{ LOOKUP_OPEN, "OPEN" }, \
|
||||
{ LOOKUP_CREATE, "CREATE" }, \
|
||||
{ LOOKUP_EXCL, "EXCL" }, \
|
||||
|
|
|
@ -67,7 +67,7 @@ xfs_find_handle(
|
|||
return -EBADF;
|
||||
inode = file_inode(f.file);
|
||||
} else {
|
||||
error = user_lpath((const char __user *)hreq->path, &path);
|
||||
error = user_path_at(AT_FDCWD, hreq->path, 0, &path);
|
||||
if (error)
|
||||
return error;
|
||||
inode = d_inode(path.dentry);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/namei.h> /* LOOKUP_* */
|
||||
#include <uapi/linux/audit.h>
|
||||
|
||||
#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
|
||||
#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
|
||||
#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 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,
|
||||
unsigned int flags);
|
||||
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,
|
||||
const struct dentry *dentry,
|
||||
unsigned int flags) {
|
||||
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;
|
||||
unsigned int aflags) {
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
__audit_inode(name, dentry, aflags);
|
||||
}
|
||||
}
|
||||
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,
|
||||
const struct dentry *dentry,
|
||||
unsigned int parent)
|
||||
unsigned int aflags)
|
||||
{ }
|
||||
static inline void audit_file(struct file *file)
|
||||
{
|
||||
|
|
|
@ -16,39 +16,28 @@ enum { MAX_NESTED_LINKS = 8 };
|
|||
*/
|
||||
enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||
|
||||
/*
|
||||
* The bitmask for a lookup event:
|
||||
* - follow links at the end
|
||||
* - require a directory
|
||||
* - ending slashes ok even for nonexistent files
|
||||
* - internal "there are more path components" flag
|
||||
* - 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
|
||||
/* pathwalk mode */
|
||||
#define LOOKUP_FOLLOW 0x0001 /* follow links at the end */
|
||||
#define LOOKUP_DIRECTORY 0x0002 /* require a directory */
|
||||
#define LOOKUP_AUTOMOUNT 0x0004 /* force terminal automount */
|
||||
#define LOOKUP_EMPTY 0x4000 /* accept empty path [user_... only] */
|
||||
#define LOOKUP_DOWN 0x8000 /* follow mounts in the starting point */
|
||||
|
||||
#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_REVAL 0x0020
|
||||
#define LOOKUP_RCU 0x0040
|
||||
#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_ROOT 0x2000
|
||||
#define LOOKUP_EMPTY 0x4000
|
||||
#define LOOKUP_DOWN 0x8000
|
||||
#define LOOKUP_ROOT_GRABBED 0x0008
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
|
||||
|
|
Loading…
Reference in New Issue