mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
[PATCH] sanitize __user_walk_fd() et.al.
* do not pass nameidata; struct path is all the callers want. * switch to new helpers: user_path_at(dfd, pathname, flags, &path) user_path(pathname, &path) user_lpath(pathname, &path) user_path_dir(pathname, &path) (fail if not a directory) The last 3 are trivial macro wrappers for the first one. * remove nameidata in callers. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
256984a838
commit
2d8f30380a
13 changed files with 235 additions and 238 deletions
|
@ -253,15 +253,15 @@ do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage int
|
asmlinkage int
|
||||||
osf_statfs(char __user *path, struct osf_statfs __user *buffer, unsigned long bufsiz)
|
osf_statfs(char __user *pathname, struct osf_statfs __user *buffer, unsigned long bufsiz)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = user_path_walk(path, &nd);
|
retval = user_path(pathname, &path);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = do_osf_statfs(nd.path.dentry, buffer, bufsiz);
|
retval = do_osf_statfs(path.dentry, buffer, bufsiz);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,19 +210,19 @@ static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hpux statfs */
|
/* hpux statfs */
|
||||||
asmlinkage long hpux_statfs(const char __user *path,
|
asmlinkage long hpux_statfs(const char __user *pathname,
|
||||||
struct hpux_statfs __user *buf)
|
struct hpux_statfs __user *buf)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct hpux_statfs tmp;
|
struct hpux_statfs tmp;
|
||||||
error = vfs_statfs_hpux(nd.path.dentry, &tmp);
|
error = vfs_statfs_hpux(path.dentry, &tmp);
|
||||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ static int coda_ioctl_permission(struct inode *inode, int mask)
|
||||||
static int coda_pioctl(struct inode * inode, struct file * filp,
|
static int coda_pioctl(struct inode * inode, struct file * filp,
|
||||||
unsigned int cmd, unsigned long user_data)
|
unsigned int cmd, unsigned long user_data)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
struct PioctlData data;
|
struct PioctlData data;
|
||||||
struct inode *target_inode = NULL;
|
struct inode *target_inode = NULL;
|
||||||
|
@ -64,21 +64,21 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
|
||||||
* 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 ) {
|
if (data.follow) {
|
||||||
error = user_path_walk(data.path, &nd);
|
error = user_path(data.path, &path);
|
||||||
} else {
|
} else {
|
||||||
error = user_path_walk_link(data.path, &nd);
|
error = user_lpath(data.path, &path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( error ) {
|
if ( error ) {
|
||||||
return error;
|
return error;
|
||||||
} else {
|
} else {
|
||||||
target_inode = nd.path.dentry->d_inode;
|
target_inode = path.dentry->d_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return if it is not a Coda inode */
|
/* return if it is not a Coda inode */
|
||||||
if ( target_inode->i_sb != inode->i_sb ) {
|
if ( target_inode->i_sb != inode->i_sb ) {
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
|
||||||
|
|
||||||
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
|
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
|
||||||
|
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
fs/compat.c
20
fs/compat.c
|
@ -234,18 +234,18 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
|
||||||
* The following statfs calls are copies of code from fs/open.c and
|
* The following statfs calls are copies of code from fs/open.c and
|
||||||
* should be checked against those from time to time
|
* should be checked against those from time to time
|
||||||
*/
|
*/
|
||||||
asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf)
|
asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct kstatfs tmp;
|
struct kstatfs tmp;
|
||||||
error = vfs_statfs(nd.path.dentry, &tmp);
|
error = vfs_statfs(path.dentry, &tmp);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = put_compat_statfs(buf, &tmp);
|
error = put_compat_statfs(buf, &tmp);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -299,21 +299,21 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf)
|
asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (sz != sizeof(*buf))
|
if (sz != sizeof(*buf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct kstatfs tmp;
|
struct kstatfs tmp;
|
||||||
error = vfs_statfs(nd.path.dentry, &tmp);
|
error = vfs_statfs(path.dentry, &tmp);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = put_compat_statfs64(buf, &tmp);
|
error = put_compat_statfs64(buf, &tmp);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,20 +354,20 @@ static void inotify_dev_event_dequeue(struct inotify_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_inode - resolve a user-given path to a specific inode and return a nd
|
* find_inode - resolve a user-given path to a specific inode
|
||||||
*/
|
*/
|
||||||
static int find_inode(const char __user *dirname, struct nameidata *nd,
|
static int find_inode(const char __user *dirname, struct path *path,
|
||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = __user_walk(dirname, flags, nd);
|
error = user_path_at(AT_FDCWD, dirname, flags, path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
/* you can only watch an inode if you have read permissions on it */
|
/* you can only watch an inode if you have read permissions on it */
|
||||||
error = inode_permission(nd->path.dentry->d_inode, MAY_READ);
|
error = inode_permission(path->dentry->d_inode, MAY_READ);
|
||||||
if (error)
|
if (error)
|
||||||
path_put(&nd->path);
|
path_put(path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,11 +650,11 @@ asmlinkage long sys_inotify_init(void)
|
||||||
return sys_inotify_init1(0);
|
return sys_inotify_init1(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
|
asmlinkage long sys_inotify_add_watch(int fd, const char __user *pathname, u32 mask)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct inotify_device *dev;
|
struct inotify_device *dev;
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
int ret, fput_needed;
|
int ret, fput_needed;
|
||||||
unsigned flags = 0;
|
unsigned flags = 0;
|
||||||
|
@ -674,12 +674,12 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
|
||||||
if (mask & IN_ONLYDIR)
|
if (mask & IN_ONLYDIR)
|
||||||
flags |= LOOKUP_DIRECTORY;
|
flags |= LOOKUP_DIRECTORY;
|
||||||
|
|
||||||
ret = find_inode(path, &nd, flags);
|
ret = find_inode(pathname, &path, flags);
|
||||||
if (unlikely(ret))
|
if (unlikely(ret))
|
||||||
goto fput_and_out;
|
goto fput_and_out;
|
||||||
|
|
||||||
/* inode held in place by reference to nd; dev by fget on fd */
|
/* inode held in place by reference to path; dev by fget on fd */
|
||||||
inode = nd.path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
dev = filp->private_data;
|
dev = filp->private_data;
|
||||||
|
|
||||||
mutex_lock(&dev->up_mutex);
|
mutex_lock(&dev->up_mutex);
|
||||||
|
@ -688,7 +688,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
|
||||||
ret = create_watch(dev, inode, mask);
|
ret = create_watch(dev, inode, mask);
|
||||||
mutex_unlock(&dev->up_mutex);
|
mutex_unlock(&dev->up_mutex);
|
||||||
|
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
fput_and_out:
|
fput_and_out:
|
||||||
fput_light(filp, fput_needed);
|
fput_light(filp, fput_needed);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
36
fs/namei.c
36
fs/namei.c
|
@ -1334,24 +1334,24 @@ struct dentry *lookup_one_noperm(const char *name, struct dentry *base)
|
||||||
return __lookup_hash(&this, base, NULL);
|
return __lookup_hash(&this, base, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __user_walk_fd(int dfd, const char __user *name, unsigned flags,
|
int user_path_at(int dfd, const char __user *name, unsigned flags,
|
||||||
struct nameidata *nd)
|
struct path *path)
|
||||||
{
|
{
|
||||||
|
struct nameidata nd;
|
||||||
char *tmp = getname(name);
|
char *tmp = getname(name);
|
||||||
int err = PTR_ERR(tmp);
|
int err = PTR_ERR(tmp);
|
||||||
|
|
||||||
if (!IS_ERR(tmp)) {
|
if (!IS_ERR(tmp)) {
|
||||||
err = do_path_lookup(dfd, tmp, flags, nd);
|
|
||||||
|
BUG_ON(flags & LOOKUP_PARENT);
|
||||||
|
|
||||||
|
err = do_path_lookup(dfd, tmp, flags, &nd);
|
||||||
putname(tmp);
|
putname(tmp);
|
||||||
|
if (!err)
|
||||||
|
*path = nd.path;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
|
|
||||||
{
|
|
||||||
return __user_walk_fd(AT_FDCWD, name, flags, nd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's inline, so penalty for filesystems that don't use sticky bit is
|
* It's inline, so penalty for filesystems that don't use sticky bit is
|
||||||
* minimal.
|
* minimal.
|
||||||
|
@ -2446,7 +2446,8 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct dentry *new_dentry;
|
struct dentry *new_dentry;
|
||||||
struct nameidata nd, old_nd;
|
struct nameidata nd;
|
||||||
|
struct path old_path;
|
||||||
int error;
|
int error;
|
||||||
char * to;
|
char * to;
|
||||||
|
|
||||||
|
@ -2457,16 +2458,16 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
|
||||||
if (IS_ERR(to))
|
if (IS_ERR(to))
|
||||||
return PTR_ERR(to);
|
return PTR_ERR(to);
|
||||||
|
|
||||||
error = __user_walk_fd(olddfd, oldname,
|
error = user_path_at(olddfd, oldname,
|
||||||
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
|
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
|
||||||
&old_nd);
|
&old_path);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit;
|
goto exit;
|
||||||
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
|
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
error = -EXDEV;
|
error = -EXDEV;
|
||||||
if (old_nd.path.mnt != nd.path.mnt)
|
if (old_path.mnt != nd.path.mnt)
|
||||||
goto out_release;
|
goto out_release;
|
||||||
new_dentry = lookup_create(&nd, 0);
|
new_dentry = lookup_create(&nd, 0);
|
||||||
error = PTR_ERR(new_dentry);
|
error = PTR_ERR(new_dentry);
|
||||||
|
@ -2475,7 +2476,7 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(nd.path.mnt);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_dput;
|
goto out_dput;
|
||||||
error = vfs_link(old_nd.path.dentry, nd.path.dentry->d_inode, new_dentry);
|
error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(nd.path.mnt);
|
||||||
out_dput:
|
out_dput:
|
||||||
dput(new_dentry);
|
dput(new_dentry);
|
||||||
|
@ -2484,7 +2485,7 @@ out_unlock:
|
||||||
out_release:
|
out_release:
|
||||||
path_put(&nd.path);
|
path_put(&nd.path);
|
||||||
out:
|
out:
|
||||||
path_put(&old_nd.path);
|
path_put(&old_path);
|
||||||
exit:
|
exit:
|
||||||
putname(to);
|
putname(to);
|
||||||
|
|
||||||
|
@ -2877,8 +2878,7 @@ const struct inode_operations page_symlink_inode_operations = {
|
||||||
.put_link = page_put_link,
|
.put_link = page_put_link,
|
||||||
};
|
};
|
||||||
|
|
||||||
EXPORT_SYMBOL(__user_walk);
|
EXPORT_SYMBOL(user_path_at);
|
||||||
EXPORT_SYMBOL(__user_walk_fd);
|
|
||||||
EXPORT_SYMBOL(follow_down);
|
EXPORT_SYMBOL(follow_down);
|
||||||
EXPORT_SYMBOL(follow_up);
|
EXPORT_SYMBOL(follow_up);
|
||||||
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
|
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
|
||||||
|
|
|
@ -1130,27 +1130,27 @@ static int do_umount(struct vfsmount *mnt, int flags)
|
||||||
|
|
||||||
asmlinkage long sys_umount(char __user * name, int flags)
|
asmlinkage long sys_umount(char __user * name, int flags)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = __user_walk(name, LOOKUP_FOLLOW, &nd);
|
retval = user_path(name, &path);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
goto out;
|
||||||
retval = -EINVAL;
|
retval = -EINVAL;
|
||||||
if (nd.path.dentry != nd.path.mnt->mnt_root)
|
if (path.dentry != path.mnt->mnt_root)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
if (!check_mnt(nd.path.mnt))
|
if (!check_mnt(path.mnt))
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
retval = -EPERM;
|
retval = -EPERM;
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
retval = do_umount(nd.path.mnt, flags);
|
retval = do_umount(path.mnt, flags);
|
||||||
dput_and_out:
|
dput_and_out:
|
||||||
/* we mustn't call path_put() as that would clear mnt_expiry_mark */
|
/* we mustn't call path_put() as that would clear mnt_expiry_mark */
|
||||||
dput(nd.path.dentry);
|
dput(path.dentry);
|
||||||
mntput_no_expire(nd.path.mnt);
|
mntput_no_expire(path.mnt);
|
||||||
out:
|
out:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -2179,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
|
||||||
const char __user * put_old)
|
const char __user * put_old)
|
||||||
{
|
{
|
||||||
struct vfsmount *tmp;
|
struct vfsmount *tmp;
|
||||||
struct nameidata new_nd, old_nd;
|
struct path new, old, parent_path, root_parent, root;
|
||||||
struct path parent_path, root_parent, root;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
|
error = user_path_dir(new_root, &new);
|
||||||
&new_nd);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto out0;
|
goto out0;
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (!check_mnt(new_nd.path.mnt))
|
if (!check_mnt(new.mnt))
|
||||||
goto out1;
|
goto out1;
|
||||||
|
|
||||||
error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd);
|
error = user_path_dir(put_old, &old);
|
||||||
if (error)
|
if (error)
|
||||||
goto out1;
|
goto out1;
|
||||||
|
|
||||||
error = security_sb_pivotroot(&old_nd.path, &new_nd.path);
|
error = security_sb_pivotroot(&old, &new);
|
||||||
if (error) {
|
if (error) {
|
||||||
path_put(&old_nd.path);
|
path_put(&old);
|
||||||
goto out1;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2209,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
|
||||||
path_get(¤t->fs->root);
|
path_get(¤t->fs->root);
|
||||||
read_unlock(¤t->fs->lock);
|
read_unlock(¤t->fs->lock);
|
||||||
down_write(&namespace_sem);
|
down_write(&namespace_sem);
|
||||||
mutex_lock(&old_nd.path.dentry->d_inode->i_mutex);
|
mutex_lock(&old.dentry->d_inode->i_mutex);
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (IS_MNT_SHARED(old_nd.path.mnt) ||
|
if (IS_MNT_SHARED(old.mnt) ||
|
||||||
IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) ||
|
IS_MNT_SHARED(new.mnt->mnt_parent) ||
|
||||||
IS_MNT_SHARED(root.mnt->mnt_parent))
|
IS_MNT_SHARED(root.mnt->mnt_parent))
|
||||||
goto out2;
|
goto out2;
|
||||||
if (!check_mnt(root.mnt))
|
if (!check_mnt(root.mnt))
|
||||||
goto out2;
|
goto out2;
|
||||||
error = -ENOENT;
|
error = -ENOENT;
|
||||||
if (IS_DEADDIR(new_nd.path.dentry->d_inode))
|
if (IS_DEADDIR(new.dentry->d_inode))
|
||||||
goto out2;
|
goto out2;
|
||||||
if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry))
|
if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry))
|
||||||
goto out2;
|
goto out2;
|
||||||
if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry))
|
if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry))
|
||||||
goto out2;
|
goto out2;
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
if (new_nd.path.mnt == root.mnt ||
|
if (new.mnt == root.mnt ||
|
||||||
old_nd.path.mnt == root.mnt)
|
old.mnt == root.mnt)
|
||||||
goto out2; /* loop, on the same file system */
|
goto out2; /* loop, on the same file system */
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (root.mnt->mnt_root != root.dentry)
|
if (root.mnt->mnt_root != root.dentry)
|
||||||
goto out2; /* not a mountpoint */
|
goto out2; /* not a mountpoint */
|
||||||
if (root.mnt->mnt_parent == root.mnt)
|
if (root.mnt->mnt_parent == root.mnt)
|
||||||
goto out2; /* not attached */
|
goto out2; /* not attached */
|
||||||
if (new_nd.path.mnt->mnt_root != new_nd.path.dentry)
|
if (new.mnt->mnt_root != new.dentry)
|
||||||
goto out2; /* not a mountpoint */
|
goto out2; /* not a mountpoint */
|
||||||
if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt)
|
if (new.mnt->mnt_parent == new.mnt)
|
||||||
goto out2; /* not attached */
|
goto out2; /* not attached */
|
||||||
/* make sure we can reach put_old from new_root */
|
/* make sure we can reach put_old from new_root */
|
||||||
tmp = old_nd.path.mnt;
|
tmp = old.mnt;
|
||||||
spin_lock(&vfsmount_lock);
|
spin_lock(&vfsmount_lock);
|
||||||
if (tmp != new_nd.path.mnt) {
|
if (tmp != new.mnt) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (tmp->mnt_parent == tmp)
|
if (tmp->mnt_parent == tmp)
|
||||||
goto out3; /* already mounted on put_old */
|
goto out3; /* already mounted on put_old */
|
||||||
if (tmp->mnt_parent == new_nd.path.mnt)
|
if (tmp->mnt_parent == new.mnt)
|
||||||
break;
|
break;
|
||||||
tmp = tmp->mnt_parent;
|
tmp = tmp->mnt_parent;
|
||||||
}
|
}
|
||||||
if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry))
|
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
|
||||||
goto out3;
|
goto out3;
|
||||||
} else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry))
|
} else if (!is_subdir(old.dentry, new.dentry))
|
||||||
goto out3;
|
goto out3;
|
||||||
detach_mnt(new_nd.path.mnt, &parent_path);
|
detach_mnt(new.mnt, &parent_path);
|
||||||
detach_mnt(root.mnt, &root_parent);
|
detach_mnt(root.mnt, &root_parent);
|
||||||
/* mount old root on put_old */
|
/* mount old root on put_old */
|
||||||
attach_mnt(root.mnt, &old_nd.path);
|
attach_mnt(root.mnt, &old);
|
||||||
/* mount new_root on / */
|
/* mount new_root on / */
|
||||||
attach_mnt(new_nd.path.mnt, &root_parent);
|
attach_mnt(new.mnt, &root_parent);
|
||||||
touch_mnt_namespace(current->nsproxy->mnt_ns);
|
touch_mnt_namespace(current->nsproxy->mnt_ns);
|
||||||
spin_unlock(&vfsmount_lock);
|
spin_unlock(&vfsmount_lock);
|
||||||
chroot_fs_refs(&root, &new_nd.path);
|
chroot_fs_refs(&root, &new);
|
||||||
security_sb_post_pivotroot(&root, &new_nd.path);
|
security_sb_post_pivotroot(&root, &new);
|
||||||
error = 0;
|
error = 0;
|
||||||
path_put(&root_parent);
|
path_put(&root_parent);
|
||||||
path_put(&parent_path);
|
path_put(&parent_path);
|
||||||
out2:
|
out2:
|
||||||
mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex);
|
mutex_unlock(&old.dentry->d_inode->i_mutex);
|
||||||
up_write(&namespace_sem);
|
up_write(&namespace_sem);
|
||||||
path_put(&root);
|
path_put(&root);
|
||||||
path_put(&old_nd.path);
|
path_put(&old);
|
||||||
out1:
|
out1:
|
||||||
path_put(&new_nd.path);
|
path_put(&new);
|
||||||
out0:
|
out0:
|
||||||
return error;
|
return error;
|
||||||
out3:
|
out3:
|
||||||
|
|
124
fs/open.c
124
fs/open.c
|
@ -122,37 +122,37 @@ static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf)
|
asmlinkage long sys_statfs(const char __user *pathname, struct statfs __user * buf)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct statfs tmp;
|
struct statfs tmp;
|
||||||
error = vfs_statfs_native(nd.path.dentry, &tmp);
|
error = vfs_statfs_native(path.dentry, &tmp);
|
||||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf)
|
asmlinkage long sys_statfs64(const char __user *pathname, size_t sz, struct statfs64 __user *buf)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
long error;
|
long error;
|
||||||
|
|
||||||
if (sz != sizeof(*buf))
|
if (sz != sizeof(*buf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct statfs64 tmp;
|
struct statfs64 tmp;
|
||||||
error = vfs_statfs64(nd.path.dentry, &tmp);
|
error = vfs_statfs64(path.dentry, &tmp);
|
||||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -223,20 +223,20 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long do_sys_truncate(const char __user * path, loff_t length)
|
static long do_sys_truncate(const char __user *pathname, loff_t length)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
struct inode * inode;
|
struct inode *inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (length < 0) /* sorry, but loff_t says... */
|
if (length < 0) /* sorry, but loff_t says... */
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
inode = nd.path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
|
|
||||||
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
|
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
|
||||||
error = -EISDIR;
|
error = -EISDIR;
|
||||||
|
@ -247,7 +247,7 @@ static long do_sys_truncate(const char __user * path, loff_t length)
|
||||||
if (!S_ISREG(inode->i_mode))
|
if (!S_ISREG(inode->i_mode))
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (error)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
|
@ -274,15 +274,15 @@ static long do_sys_truncate(const char __user * path, loff_t length)
|
||||||
error = locks_verify_truncate(inode, NULL, length);
|
error = locks_verify_truncate(inode, NULL, length);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
DQUOT_INIT(inode);
|
DQUOT_INIT(inode);
|
||||||
error = do_truncate(nd.path.dentry, length, 0, NULL);
|
error = do_truncate(path.dentry, length, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_write_and_out:
|
put_write_and_out:
|
||||||
put_write_access(inode);
|
put_write_access(inode);
|
||||||
mnt_drop_write_and_out:
|
mnt_drop_write_and_out:
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
dput_and_out:
|
dput_and_out:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ out:
|
||||||
*/
|
*/
|
||||||
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
int old_fsuid, old_fsgid;
|
int old_fsuid, old_fsgid;
|
||||||
kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
|
kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
|
||||||
|
@ -449,7 +449,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
||||||
* FIXME: There is a race here against sys_capset. The
|
* FIXME: There is a race here against sys_capset. The
|
||||||
* capabilities can change yet we will restore the old
|
* capabilities can change yet we will restore the old
|
||||||
* value below. We should hold task_capabilities_lock,
|
* value below. We should hold task_capabilities_lock,
|
||||||
* but we cannot because user_path_walk can sleep.
|
* but we cannot because user_path_at can sleep.
|
||||||
*/
|
*/
|
||||||
#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
|
#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
|
||||||
if (current->uid)
|
if (current->uid)
|
||||||
|
@ -458,11 +458,11 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
||||||
old_cap = cap_set_effective(current->cap_permitted);
|
old_cap = cap_set_effective(current->cap_permitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
|
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
|
||||||
if (res)
|
if (res)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
inode = nd.path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
|
|
||||||
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||||
/*
|
/*
|
||||||
|
@ -470,7 +470,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
||||||
* with the "noexec" flag.
|
* with the "noexec" flag.
|
||||||
*/
|
*/
|
||||||
res = -EACCES;
|
res = -EACCES;
|
||||||
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
|
if (path.mnt->mnt_flags & MNT_NOEXEC)
|
||||||
goto out_path_release;
|
goto out_path_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,11 +488,11 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
||||||
* inherently racy and know that the fs may change
|
* inherently racy and know that the fs may change
|
||||||
* state before we even see this result.
|
* state before we even see this result.
|
||||||
*/
|
*/
|
||||||
if (__mnt_is_readonly(nd.path.mnt))
|
if (__mnt_is_readonly(path.mnt))
|
||||||
res = -EROFS;
|
res = -EROFS;
|
||||||
|
|
||||||
out_path_release:
|
out_path_release:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
current->fsuid = old_fsuid;
|
current->fsuid = old_fsuid;
|
||||||
current->fsgid = old_fsgid;
|
current->fsgid = old_fsgid;
|
||||||
|
@ -510,21 +510,21 @@ asmlinkage long sys_access(const char __user *filename, int mode)
|
||||||
|
|
||||||
asmlinkage long sys_chdir(const char __user * filename)
|
asmlinkage long sys_chdir(const char __user * filename)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
|
error = user_path_dir(filename, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||||
if (error)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
set_fs_pwd(current->fs, &nd.path);
|
set_fs_pwd(current->fs, &path);
|
||||||
|
|
||||||
dput_and_out:
|
dput_and_out:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -557,14 +557,14 @@ out:
|
||||||
|
|
||||||
asmlinkage long sys_chroot(const char __user * filename)
|
asmlinkage long sys_chroot(const char __user * filename)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
|
error = user_path_dir(filename, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||||
if (error)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
|
@ -572,10 +572,10 @@ asmlinkage long sys_chroot(const char __user * filename)
|
||||||
if (!capable(CAP_SYS_CHROOT))
|
if (!capable(CAP_SYS_CHROOT))
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
set_fs_root(current->fs, &nd.path);
|
set_fs_root(current->fs, &path);
|
||||||
error = 0;
|
error = 0;
|
||||||
dput_and_out:
|
dput_and_out:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -617,17 +617,17 @@ out:
|
||||||
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
|
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
|
||||||
mode_t mode)
|
mode_t mode)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
struct inode * inode;
|
struct inode *inode;
|
||||||
int error;
|
int error;
|
||||||
struct iattr newattrs;
|
struct iattr newattrs;
|
||||||
|
|
||||||
error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
|
error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
inode = nd.path.dentry->d_inode;
|
inode = path.dentry->d_inode;
|
||||||
|
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (error)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
|
@ -635,11 +635,11 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
|
||||||
mode = inode->i_mode;
|
mode = inode->i_mode;
|
||||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||||
error = notify_change(nd.path.dentry, &newattrs);
|
error = notify_change(path.dentry, &newattrs);
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
dput_and_out:
|
dput_and_out:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -676,19 +676,19 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
|
||||||
|
|
||||||
asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
|
asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk(filename, &nd);
|
error = user_path(filename, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_release;
|
goto out_release;
|
||||||
error = chown_common(nd.path.dentry, user, group);
|
error = chown_common(path.dentry, user, group);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
out_release:
|
out_release:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -696,7 +696,7 @@ out:
|
||||||
asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
|
asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
|
||||||
gid_t group, int flag)
|
gid_t group, int flag)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error = -EINVAL;
|
int error = -EINVAL;
|
||||||
int follow;
|
int follow;
|
||||||
|
|
||||||
|
@ -704,35 +704,35 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
||||||
error = __user_walk_fd(dfd, filename, follow, &nd);
|
error = user_path_at(dfd, filename, follow, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_release;
|
goto out_release;
|
||||||
error = chown_common(nd.path.dentry, user, group);
|
error = chown_common(path.dentry, user, group);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
out_release:
|
out_release:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group)
|
asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk_link(filename, &nd);
|
error = user_lpath(filename, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_release;
|
goto out_release;
|
||||||
error = chown_common(nd.path.dentry, user, group);
|
error = chown_common(path.dentry, user, group);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
out_release:
|
out_release:
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
32
fs/stat.c
32
fs/stat.c
|
@ -57,13 +57,13 @@ EXPORT_SYMBOL(vfs_getattr);
|
||||||
|
|
||||||
int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
|
int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
|
error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat);
|
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -77,13 +77,13 @@ EXPORT_SYMBOL(vfs_stat);
|
||||||
|
|
||||||
int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
|
int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = __user_walk_fd(dfd, name, 0, &nd);
|
error = user_path_at(dfd, name, 0, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat);
|
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -291,29 +291,29 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys_readlinkat(int dfd, const char __user *path,
|
asmlinkage long sys_readlinkat(int dfd, const char __user *pathname,
|
||||||
char __user *buf, int bufsiz)
|
char __user *buf, int bufsiz)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (bufsiz <= 0)
|
if (bufsiz <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
error = __user_walk_fd(dfd, path, 0, &nd);
|
error = user_path_at(dfd, pathname, 0, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct inode *inode = nd.path.dentry->d_inode;
|
struct inode *inode = path.dentry->d_inode;
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (inode->i_op && inode->i_op->readlink) {
|
if (inode->i_op && inode->i_op->readlink) {
|
||||||
error = security_inode_readlink(nd.path.dentry);
|
error = security_inode_readlink(path.dentry);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
touch_atime(nd.path.mnt, nd.path.dentry);
|
touch_atime(path.mnt, path.dentry);
|
||||||
error = inode->i_op->readlink(nd.path.dentry,
|
error = inode->i_op->readlink(path.dentry,
|
||||||
buf, bufsiz);
|
buf, bufsiz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,18 +152,18 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
|
||||||
error = utimes_common(&file->f_path, times);
|
error = utimes_common(&file->f_path, times);
|
||||||
fput(file);
|
fput(file);
|
||||||
} else {
|
} else {
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int lookup_flags = 0;
|
int lookup_flags = 0;
|
||||||
|
|
||||||
if (!(flags & AT_SYMLINK_NOFOLLOW))
|
if (!(flags & AT_SYMLINK_NOFOLLOW))
|
||||||
lookup_flags |= LOOKUP_FOLLOW;
|
lookup_flags |= LOOKUP_FOLLOW;
|
||||||
|
|
||||||
error = __user_walk_fd(dfd, filename, lookup_flags, &nd);
|
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = utimes_common(&nd.path, times);
|
error = utimes_common(&path, times);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
96
fs/xattr.c
96
fs/xattr.c
|
@ -252,40 +252,40 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long
|
asmlinkage long
|
||||||
sys_setxattr(const char __user *path, const char __user *name,
|
sys_setxattr(const char __user *pathname, const char __user *name,
|
||||||
const void __user *value, size_t size, int flags)
|
const void __user *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = setxattr(nd.path.dentry, name, value, size, flags);
|
error = setxattr(path.dentry, name, value, size, flags);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
}
|
}
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long
|
asmlinkage long
|
||||||
sys_lsetxattr(const char __user *path, const char __user *name,
|
sys_lsetxattr(const char __user *pathname, const char __user *name,
|
||||||
const void __user *value, size_t size, int flags)
|
const void __user *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk_link(path, &nd);
|
error = user_lpath(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = setxattr(nd.path.dentry, name, value, size, flags);
|
error = setxattr(path.dentry, name, value, size, flags);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
}
|
}
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,32 +350,32 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage ssize_t
|
asmlinkage ssize_t
|
||||||
sys_getxattr(const char __user *path, const char __user *name,
|
sys_getxattr(const char __user *pathname, const char __user *name,
|
||||||
void __user *value, size_t size)
|
void __user *value, size_t size)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
ssize_t error;
|
ssize_t error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = getxattr(nd.path.dentry, name, value, size);
|
error = getxattr(path.dentry, name, value, size);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage ssize_t
|
asmlinkage ssize_t
|
||||||
sys_lgetxattr(const char __user *path, const char __user *name, void __user *value,
|
sys_lgetxattr(const char __user *pathname, const char __user *name, void __user *value,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
ssize_t error;
|
ssize_t error;
|
||||||
|
|
||||||
error = user_path_walk_link(path, &nd);
|
error = user_lpath(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = getxattr(nd.path.dentry, name, value, size);
|
error = getxattr(path.dentry, name, value, size);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,30 +425,30 @@ listxattr(struct dentry *d, char __user *list, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage ssize_t
|
asmlinkage ssize_t
|
||||||
sys_listxattr(const char __user *path, char __user *list, size_t size)
|
sys_listxattr(const char __user *pathname, char __user *list, size_t size)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
ssize_t error;
|
ssize_t error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = listxattr(nd.path.dentry, list, size);
|
error = listxattr(path.dentry, list, size);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage ssize_t
|
asmlinkage ssize_t
|
||||||
sys_llistxattr(const char __user *path, char __user *list, size_t size)
|
sys_llistxattr(const char __user *pathname, char __user *list, size_t size)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
ssize_t error;
|
ssize_t error;
|
||||||
|
|
||||||
error = user_path_walk_link(path, &nd);
|
error = user_lpath(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = listxattr(nd.path.dentry, list, size);
|
error = listxattr(path.dentry, list, size);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,38 +486,38 @@ removexattr(struct dentry *d, const char __user *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long
|
asmlinkage long
|
||||||
sys_removexattr(const char __user *path, const char __user *name)
|
sys_removexattr(const char __user *pathname, const char __user *name)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk(path, &nd);
|
error = user_path(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = removexattr(nd.path.dentry, name);
|
error = removexattr(path.dentry, name);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
}
|
}
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long
|
asmlinkage long
|
||||||
sys_lremovexattr(const char __user *path, const char __user *name)
|
sys_lremovexattr(const char __user *pathname, const char __user *name)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = user_path_walk_link(path, &nd);
|
error = user_lpath(pathname, &path);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = mnt_want_write(nd.path.mnt);
|
error = mnt_want_write(path.mnt);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = removexattr(nd.path.dentry, name);
|
error = removexattr(path.dentry, name);
|
||||||
mnt_drop_write(nd.path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
}
|
}
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,17 +84,15 @@ xfs_find_handle(
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case XFS_IOC_PATH_TO_FSHANDLE:
|
case XFS_IOC_PATH_TO_FSHANDLE:
|
||||||
case XFS_IOC_PATH_TO_HANDLE: {
|
case XFS_IOC_PATH_TO_HANDLE: {
|
||||||
struct nameidata nd;
|
struct path path;
|
||||||
int error;
|
int error = user_lpath((const char __user *)hreq.path, &path);
|
||||||
|
|
||||||
error = user_path_walk_link((const char __user *)hreq.path, &nd);
|
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
ASSERT(nd.path.dentry);
|
ASSERT(path.dentry);
|
||||||
ASSERT(nd.path.dentry->d_inode);
|
ASSERT(path.dentry->d_inode);
|
||||||
inode = igrab(nd.path.dentry->d_inode);
|
inode = igrab(path.dentry->d_inode);
|
||||||
path_put(&nd.path);
|
path_put(&path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,12 +54,13 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||||
#define LOOKUP_OPEN (0x0100)
|
#define LOOKUP_OPEN (0x0100)
|
||||||
#define LOOKUP_CREATE (0x0200)
|
#define LOOKUP_CREATE (0x0200)
|
||||||
|
|
||||||
extern int __user_walk(const char __user *, unsigned, struct nameidata *);
|
extern int user_path_at(int, const char __user *, unsigned, struct path *);
|
||||||
extern int __user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *);
|
|
||||||
#define user_path_walk(name,nd) \
|
#define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
|
||||||
__user_walk_fd(AT_FDCWD, name, LOOKUP_FOLLOW, nd)
|
#define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
|
||||||
#define user_path_walk_link(name,nd) \
|
#define user_path_dir(name, path) \
|
||||||
__user_walk_fd(AT_FDCWD, name, 0, nd)
|
user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path)
|
||||||
|
|
||||||
extern int path_lookup(const char *, unsigned, struct nameidata *);
|
extern int path_lookup(const char *, unsigned, struct nameidata *);
|
||||||
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
||||||
const char *, unsigned int, struct nameidata *);
|
const char *, unsigned int, struct nameidata *);
|
||||||
|
|
Loading…
Reference in a new issue