Commit 2d8f3038 authored by Al Viro's avatar Al Viro

[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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 256984a8
......@@ -253,15 +253,15 @@ do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
}
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;
retval = user_path_walk(path, &nd);
retval = user_path(pathname, &path);
if (!retval) {
retval = do_osf_statfs(nd.path.dentry, buffer, bufsiz);
path_put(&nd.path);
retval = do_osf_statfs(path.dentry, buffer, bufsiz);
path_put(&path);
}
return retval;
}
......
......@@ -210,19 +210,19 @@ static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
}
/* hpux statfs */
asmlinkage long hpux_statfs(const char __user *path,
asmlinkage long hpux_statfs(const char __user *pathname,
struct hpux_statfs __user *buf)
{
struct nameidata nd;
struct path path;
int error;
error = user_path_walk(path, &nd);
error = user_path(pathname, &path);
if (!error) {
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)))
error = -EFAULT;
path_put(&nd.path);
path_put(&path);
}
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,
unsigned int cmd, unsigned long user_data)
{
struct nameidata nd;
struct path path;
int error;
struct PioctlData data;
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
* user memory, and namei takes care of this
*/
if ( data.follow ) {
error = user_path_walk(data.path, &nd);
if (data.follow) {
error = user_path(data.path, &path);
} else {
error = user_path_walk_link(data.path, &nd);
error = user_lpath(data.path, &path);
}
if ( error ) {
return error;
} else {
target_inode = nd.path.dentry->d_inode;
target_inode = path.dentry->d_inode;
}
/* return if it is not a Coda inode */
if ( target_inode->i_sb != inode->i_sb ) {
path_put(&nd.path);
path_put(&path);
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);
path_put(&nd.path);
path_put(&path);
return error;
}
......@@ -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
* 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;
error = user_path_walk(path, &nd);
error = user_path(pathname, &path);
if (!error) {
struct kstatfs tmp;
error = vfs_statfs(nd.path.dentry, &tmp);
error = vfs_statfs(path.dentry, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
path_put(&nd.path);
path_put(&path);
}
return error;
}
......@@ -299,21 +299,21 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
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;
if (sz != sizeof(*buf))
return -EINVAL;
error = user_path_walk(path, &nd);
error = user_path(pathname, &path);
if (!error) {
struct kstatfs tmp;
error = vfs_statfs(nd.path.dentry, &tmp);
error = vfs_statfs(path.dentry, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
path_put(&nd.path);
path_put(&path);
}
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)
{
int error;
error = __user_walk(dirname, flags, nd);
error = user_path_at(AT_FDCWD, dirname, flags, path);
if (error)
return error;
/* 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)
path_put(&nd->path);
path_put(path);
return error;
}
......@@ -650,11 +650,11 @@ asmlinkage long sys_inotify_init(void)
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 inotify_device *dev;
struct nameidata nd;
struct path path;
struct file *filp;
int ret, fput_needed;
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)
flags |= LOOKUP_DIRECTORY;
ret = find_inode(path, &nd, flags);
ret = find_inode(pathname, &path, flags);
if (unlikely(ret))
goto fput_and_out;
/* inode held in place by reference to nd; dev by fget on fd */
inode = nd.path.dentry->d_inode;
/* inode held in place by reference to path; dev by fget on fd */
inode = path.dentry->d_inode;
dev = filp->private_data;
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);
mutex_unlock(&dev->up_mutex);
path_put(&nd.path);
path_put(&path);
fput_and_out:
fput_light(filp, fput_needed);
return ret;
......
......@@ -1334,24 +1334,24 @@ struct dentry *lookup_one_noperm(const char *name, struct dentry *base)
return __lookup_hash(&this, base, NULL);
}
int __user_walk_fd(int dfd, const char __user *name, unsigned flags,
struct nameidata *nd)
int user_path_at(int dfd, const char __user *name, unsigned flags,
struct path *path)
{
struct nameidata nd;
char *tmp = getname(name);
int err = PTR_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);
if (!err)
*path = nd.path;
}
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
* minimal.
......@@ -2446,7 +2446,8 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
int flags)
{
struct dentry *new_dentry;
struct nameidata nd, old_nd;
struct nameidata nd;
struct path old_path;
int error;
char * to;
......@@ -2457,16 +2458,16 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
if (IS_ERR(to))
return PTR_ERR(to);
error = __user_walk_fd(olddfd, oldname,
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
&old_nd);
error = user_path_at(olddfd, oldname,
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
&old_path);
if (error)
goto exit;
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
if (error)
goto out;
error = -EXDEV;
if (old_nd.path.mnt != nd.path.mnt)
if (old_path.mnt != nd.path.mnt)
goto out_release;
new_dentry = lookup_create(&nd, 0);
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);
if (error)
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);
out_dput:
dput(new_dentry);
......@@ -2484,7 +2485,7 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
out_release:
path_put(&nd.path);
out:
path_put(&old_nd.path);
path_put(&old_path);
exit:
putname(to);
......@@ -2877,8 +2878,7 @@ const struct inode_operations page_symlink_inode_operations = {
.put_link = page_put_link,
};
EXPORT_SYMBOL(__user_walk);
EXPORT_SYMBOL(__user_walk_fd);
EXPORT_SYMBOL(user_path_at);
EXPORT_SYMBOL(follow_down);
EXPORT_SYMBOL(follow_up);
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)
{
struct nameidata nd;
struct path path;
int retval;
retval = __user_walk(name, LOOKUP_FOLLOW, &nd);
retval = user_path(name, &path);
if (retval)
goto out;
retval = -EINVAL;
if (nd.path.dentry != nd.path.mnt->mnt_root)
if (path.dentry != path.mnt->mnt_root)
goto dput_and_out;
if (!check_mnt(nd.path.mnt))
if (!check_mnt(path.mnt))
goto dput_and_out;
retval = -EPERM;
if (!capable(CAP_SYS_ADMIN))
goto dput_and_out;
retval = do_umount(nd.path.mnt, flags);
retval = do_umount(path.mnt, flags);
dput_and_out:
/* we mustn't call path_put() as that would clear mnt_expiry_mark */
dput(nd.path.dentry);
mntput_no_expire(nd.path.mnt);
dput(path.dentry);
mntput_no_expire(path.mnt);
out:
return retval;
}
......@@ -2179,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
const char __user * put_old)
{
struct vfsmount *tmp;
struct nameidata new_nd, old_nd;
struct path parent_path, root_parent, root;
struct path new, old, parent_path, root_parent, root;
int error;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
&new_nd);
error = user_path_dir(new_root, &new);
if (error)
goto out0;
error = -EINVAL;
if (!check_mnt(new_nd.path.mnt))
if (!check_mnt(new.mnt))
goto out1;
error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd);
error = user_path_dir(put_old, &old);
if (error)
goto out1;
error = security_sb_pivotroot(&old_nd.path, &new_nd.path);
error = security_sb_pivotroot(&old, &new);
if (error) {
path_put(&old_nd.path);
path_put(&old);
goto out1;
}
......@@ -2209,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
path_get(&current->fs->root);
read_unlock(&current->fs->lock);
down_write(&namespace_sem);
mutex_lock(&old_nd.path.dentry->d_inode->i_mutex);
mutex_lock(&old.dentry->d_inode->i_mutex);
error = -EINVAL;
if (IS_MNT_SHARED(old_nd.path.mnt) ||
IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) ||
if (IS_MNT_SHARED(old.mnt) ||
IS_MNT_SHARED(new.mnt->mnt_parent) ||
IS_MNT_SHARED(root.mnt->mnt_parent))
goto out2;
if (!check_mnt(root.mnt))
goto out2;
error = -ENOENT;
if (IS_DEADDIR(new_nd.path.dentry->d_inode))
if (IS_DEADDIR(new.dentry->d_inode))
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;
if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry))
if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry))
goto out2;
error = -EBUSY;
if (new_nd.path.mnt == root.mnt ||
old_nd.path.mnt == root.mnt)
if (new.mnt == root.mnt ||
old.mnt == root.mnt)
goto out2; /* loop, on the same file system */
error = -EINVAL;
if (root.mnt->mnt_root != root.dentry)
goto out2; /* not a mountpoint */
if (root.mnt->mnt_parent == root.mnt)
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 */
if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt)
if (new.mnt->mnt_parent == new.mnt)
goto out2; /* not attached */
/* make sure we can reach put_old from new_root */
tmp = old_nd.path.mnt;
tmp = old.mnt;
spin_lock(&vfsmount_lock);
if (tmp != new_nd.path.mnt) {
if (tmp != new.mnt) {
for (;;) {
if (tmp->mnt_parent == tmp)
goto out3; /* already mounted on put_old */
if (tmp->mnt_parent == new_nd.path.mnt)
if (tmp->mnt_parent == new.mnt)
break;
tmp = tmp->mnt_parent;
}
if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry))
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
goto out3;
} else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry))
} else if (!is_subdir(old.dentry, new.dentry))
goto out3;
detach_mnt(new_nd.path.mnt, &parent_path);
detach_mnt(new.mnt, &parent_path);
detach_mnt(root.mnt, &root_parent);
/* mount old root on put_old */
attach_mnt(root.mnt, &old_nd.path);
attach_mnt(root.mnt, &old);
/* 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);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&root, &new_nd.path);
security_sb_post_pivotroot(&root, &new_nd.path);
chroot_fs_refs(&root, &new);
security_sb_post_pivotroot(&root, &new);
error = 0;
path_put(&root_parent);
path_put(&parent_path);
out2:
mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex);
mutex_unlock(&old.dentry->d_inode->i_mutex);
up_write(&namespace_sem);
path_put(&root);
path_put(&old_nd.path);
path_put(&old);
out1:
path_put(&new_nd.path);
path_put(&new);
out0:
return error;
out3:
......
......@@ -122,37 +122,37 @@ static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
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;
error = user_path_walk(path, &nd);
error = user_path(pathname, &path);
if (!error) {
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)))
error = -EFAULT;
path_put(&nd.path);
path_put(&path);
}
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;
if (sz != sizeof(*buf))
return -EINVAL;
error = user_path_walk(path, &nd);
error = user_path(pathname, &path);
if (!error) {
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)))
error = -EFAULT;
path_put(&nd.path);
path_put(&path);
}
return error;
}
......@@ -223,20 +223,20 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
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 inode * inode;
struct path path;
struct inode *inode;
int error;
error = -EINVAL;
if (length < 0) /* sorry, but loff_t says... */
goto out;
error = user_path_walk(path, &nd);
error = user_path(pathname, &path);
if (error)
goto out;
inode = nd.path.dentry->d_inode;
inode = path.dentry->d_inode;
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
error = -EISDIR;
......@@ -247,7 +247,7 @@ static long do_sys_truncate(const char __user * path, loff_t length)
if (!S_ISREG(inode->i_mode))
goto dput_and_out;
error = mnt_want_write(nd.path.mnt);
error = mnt_want_write(path.mnt);
if (error)
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);
if (!error) {
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_access(inode);
mnt_drop_write_and_out:
mnt_drop_write(nd.path.mnt);
mnt_drop_write(path.mnt);
dput_and_out:
path_put(&nd.path);
path_put(&path);
out:
return error;
}
......@@ -425,7 +425,7 @@ asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
*/
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
struct nameidata nd;
struct path path;
struct inode *inode;
int old_fsuid, old_fsgid;
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
* capabilities can change yet we will restore the old
* 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 */
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);
}
res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
if (res)
goto out;
inode = nd.path.dentry->d_inode;
inode = path.dentry->d_inode;
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.
*/
res = -EACCES;
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
if (path.mnt->mnt_flags & MNT_NOEXEC)
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
* state before we even see this result.
*/
if (__mnt_is_readonly(nd.path.mnt))
if (__mnt_is_readonly(path.mnt))
res = -EROFS;
out_path_release:
path_put(&nd.path);
path_put(&path);
out:
current->fsuid = old_fsuid;
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)
{
struct nameidata nd;
struct path path;
int error;
error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
error = user_path_dir(filename, &path);
if (error)
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)
goto dput_and_out;
set_fs_pwd(current->fs, &nd.path);
set_fs_pwd(current->fs, &path);
dput_and_out:
path_put(&nd.path);
path_put(&path);
out:
return error;
}
......@@ -557,14 +557,14 @@ asmlinkage long sys_fchdir(unsigned int fd)
asmlinkage long sys_chroot(const char __user * filename)
{
struct nameidata nd;
struct path path;
int error;
error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
error = user_path_dir(filename, &path);
if (error)
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)
goto dput_and_out;
......@@ -572,10 +572,10 @@ asmlinkage long sys_chroot(const char __user * filename)
if (!capable(CAP_SYS_CHROOT))
goto dput_and_out;
set_fs_root(current->fs, &nd.path);
set_fs_root(current->fs, &path);
error = 0;
dput_and_out:
path_put(&nd.path);
path_put(&path);
out:
return error;
}
......@@ -617,17 +617,17 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
mode_t mode)
{
struct nameidata nd;
struct inode * inode;
struct path path;
struct inode *inode;
int error;
struct iattr newattrs;
error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
if (error)
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)
goto dput_and_out;
mutex_lock(&inode->i_mutex);
......@@ -635,11 +635,11 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
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);
mnt_drop_write(nd.path.mnt);
mnt_drop_write(path.mnt);
dput_and_out:
path_put(&nd.path);
path_put(&path);
out:
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)
{
struct nameidata nd;
struct path path;
int error;
error = user_path_walk(filename, &nd);
error = user_path(filename, &path);
if (error)
goto out;
error = mnt_want_write(nd.path.mnt);
error = mnt_want_write(path.mnt);
if (error)
goto out_release;