Commit ddffeb01 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] Re: "rename" breakage?

I've found what's going on there.  Basically, we should not use
__user_walk() with LOOKUP_PARENT - nd->last.name is set to the last
component of the name and freeing that name before we are done is not a
good idea. 
parent cd266913
...@@ -525,12 +525,20 @@ int lento_create(const char *name, int mode, struct lento_vfs_context *info) ...@@ -525,12 +525,20 @@ int lento_create(const char *name, int mode, struct lento_vfs_context *info)
{ {
int error; int error;
struct nameidata nd; struct nameidata nd;
char * pathname;
struct dentry *dentry; struct dentry *dentry;
struct presto_file_set *fset; struct presto_file_set *fset;
ENTRY; ENTRY;
pathname = getname(name);
error = PTR_ERR(pathname);
if (IS_ERR(pathname)) {
EXIT;
goto exit;
}
/* this looks up the parent */ /* this looks up the parent */
error = __user_walk(name, LOOKUP_PARENT, &nd); error = path_lookup(pathname, LOOKUP_PARENT, &nd);
if (error) { if (error) {
EXIT; EXIT;
goto exit; goto exit;
...@@ -558,6 +566,7 @@ int lento_create(const char *name, int mode, struct lento_vfs_context *info) ...@@ -558,6 +566,7 @@ int lento_create(const char *name, int mode, struct lento_vfs_context *info)
path_release (&nd); path_release (&nd);
dput(dentry); dput(dentry);
up(&dentry->d_parent->d_inode->i_sem); up(&dentry->d_parent->d_inode->i_sem);
putname(pathname);
exit: exit:
return error; return error;
} }
...@@ -662,14 +671,19 @@ int lento_link(const char * oldname, const char * newname, ...@@ -662,14 +671,19 @@ int lento_link(const char * oldname, const char * newname,
struct lento_vfs_context *info) struct lento_vfs_context *info)
{ {
int error; int error;
struct presto_file_set *fset;
struct dentry *new_dentry; struct dentry *new_dentry;
struct nameidata nd, old_nd; struct nameidata nd, old_nd;
char * to;
struct presto_file_set *fset;
error = __user_walk(from, 0, &old_nd); to = getname(newname);
if(IS_ERR(to))
return PTR_ERR(to);
error = __user_walk(oldname, 0, &old_nd);
if (error) if (error)
goto exit; goto exit;
error = __user_walk(newname, LOOKUP_PARENT, &nd); error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error) if (error)
goto out; goto out;
error = -EXDEV; error = -EXDEV;
...@@ -697,6 +711,8 @@ int lento_link(const char * oldname, const char * newname, ...@@ -697,6 +711,8 @@ int lento_link(const char * oldname, const char * newname,
out: out:
path_release(&old_nd); path_release(&old_nd);
exit: exit:
putname(to);
return error; return error;
} }
...@@ -805,13 +821,18 @@ int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir, ...@@ -805,13 +821,18 @@ int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir,
int lento_unlink(const char *pathname, struct lento_vfs_context *info) int lento_unlink(const char *pathname, struct lento_vfs_context *info)
{ {
int error = 0; int error = 0;
char * name;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
struct presto_file_set *fset; struct presto_file_set *fset;
ENTRY; ENTRY;
error = __user_walk(pathname, LOOKUP_PARENT, &nd); name = getname(pathname);
if(IS_ERR(name))
return PTR_ERR(name);
error = path_lookup(name, LOOKUP_PARENT, &nd))
if (error) if (error)
goto exit; goto exit;
error = -EISDIR; error = -EISDIR;
...@@ -840,6 +861,8 @@ int lento_unlink(const char *pathname, struct lento_vfs_context *info) ...@@ -840,6 +861,8 @@ int lento_unlink(const char *pathname, struct lento_vfs_context *info)
exit1: exit1:
path_release(&nd); path_release(&nd);
exit: exit:
putname(name);
return error; return error;
slashes: slashes:
...@@ -951,6 +974,7 @@ int lento_symlink(const char *oldname, const char *newname, ...@@ -951,6 +974,7 @@ int lento_symlink(const char *oldname, const char *newname,
{ {
int error; int error;
char *from; char *from;
char *to;
struct dentry *dentry; struct dentry *dentry;
struct presto_file_set *fset; struct presto_file_set *fset;
struct nameidata nd; struct nameidata nd;
...@@ -964,7 +988,14 @@ int lento_symlink(const char *oldname, const char *newname, ...@@ -964,7 +988,14 @@ int lento_symlink(const char *oldname, const char *newname,
goto exit; goto exit;
} }
error = __user_walk(newname, LOOKUP_PARENT, &nd); to = getname(newname);
error = PTR_ERR(to);
if (IS_ERR(to)) {
EXIT;
goto exit_from;
}
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error) { if (error) {
EXIT; EXIT;
goto exit_to; goto exit_to;
...@@ -987,13 +1018,14 @@ int lento_symlink(const char *oldname, const char *newname, ...@@ -987,13 +1018,14 @@ int lento_symlink(const char *oldname, const char *newname,
goto exit_lock; goto exit_lock;
} }
error = presto_do_symlink(fset, nd.dentry, error = presto_do_symlink(fset, nd.dentry,
dentry, from, info); dentry, oldname, info);
path_release(&nd); path_release(&nd);
EXIT; EXIT;
exit_lock: exit_lock:
up(&nd.dentry->d_inode->i_sem); up(&nd.dentry->d_inode->i_sem);
dput(dentry); dput(dentry);
exit_to: exit_to:
putname(to);
exit_from: exit_from:
putname(from); putname(from);
exit: exit:
...@@ -1108,6 +1140,7 @@ int presto_do_mkdir(struct presto_file_set *fset, struct dentry *dir, ...@@ -1108,6 +1140,7 @@ int presto_do_mkdir(struct presto_file_set *fset, struct dentry *dir,
int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info) int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info)
{ {
int error; int error;
char *pathname;
struct dentry *dentry; struct dentry *dentry;
struct presto_file_set *fset; struct presto_file_set *fset;
struct nameidata nd; struct nameidata nd;
...@@ -1115,7 +1148,14 @@ int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info) ...@@ -1115,7 +1148,14 @@ int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info)
ENTRY; ENTRY;
CDEBUG(D_PIOCTL, "name: %s, mode %o, offset %d, recno %d, flags %x\n", CDEBUG(D_PIOCTL, "name: %s, mode %o, offset %d, recno %d, flags %x\n",
name, mode, info->slot_offset, info->recno, info->flags); name, mode, info->slot_offset, info->recno, info->flags);
error = __user_walk(pathname, LOOKUP_PARENT, &nd); pathname = getname(name);
error = PTR_ERR(pathname);
if (IS_ERR(pathname)) {
EXIT;
return error;
}
error = path_lookup(pathname, LOOKUP_PARENT, &nd);
if (error) if (error)
goto out_name; goto out_name;
...@@ -1139,6 +1179,7 @@ int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info) ...@@ -1139,6 +1179,7 @@ int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info)
path_release(&nd); path_release(&nd);
out_name: out_name:
EXIT; EXIT;
putname(pathname);
CDEBUG(D_PIOCTL, "error: %d\n", error); CDEBUG(D_PIOCTL, "error: %d\n", error);
return error; return error;
} }
...@@ -1243,12 +1284,17 @@ int presto_do_rmdir(struct presto_file_set *fset, struct dentry *dir, ...@@ -1243,12 +1284,17 @@ int presto_do_rmdir(struct presto_file_set *fset, struct dentry *dir,
int lento_rmdir(const char *pathname, struct lento_vfs_context *info) int lento_rmdir(const char *pathname, struct lento_vfs_context *info)
{ {
int error = 0; int error = 0;
char * name;
struct dentry *dentry; struct dentry *dentry;
struct presto_file_set *fset; struct presto_file_set *fset;
struct nameidata nd; struct nameidata nd;
ENTRY; ENTRY;
error = __user_walk(pathname, LOOKUP_PARENT, &nd)) name = getname(pathname);
if(IS_ERR(name))
return PTR_ERR(name);
error = path_lookup(name, LOOKUP_PARENT, &nd);
if (error) if (error)
goto exit; goto exit;
...@@ -1281,6 +1327,7 @@ int lento_rmdir(const char *pathname, struct lento_vfs_context *info) ...@@ -1281,6 +1327,7 @@ int lento_rmdir(const char *pathname, struct lento_vfs_context *info)
path_release(&nd); path_release(&nd);
exit: exit:
EXIT; EXIT;
putname(name);
return error; return error;
} }
...@@ -1390,6 +1437,7 @@ int lento_mknod(const char *filename, int mode, dev_t dev, ...@@ -1390,6 +1437,7 @@ int lento_mknod(const char *filename, int mode, dev_t dev,
struct lento_vfs_context *info) struct lento_vfs_context *info)
{ {
int error = 0; int error = 0;
char * tmp;
struct dentry * dentry; struct dentry * dentry;
struct nameidata nd; struct nameidata nd;
struct presto_file_set *fset; struct presto_file_set *fset;
...@@ -1398,8 +1446,11 @@ int lento_mknod(const char *filename, int mode, dev_t dev, ...@@ -1398,8 +1446,11 @@ int lento_mknod(const char *filename, int mode, dev_t dev,
if (S_ISDIR(mode)) if (S_ISDIR(mode))
return -EPERM; return -EPERM;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
error = __user_walk(filename, LOOKUP_PARENT, &nd); error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error) if (error)
goto out; goto out;
dentry = lookup_create(&nd, 0); dentry = lookup_create(&nd, 0);
...@@ -1432,6 +1483,8 @@ int lento_mknod(const char *filename, int mode, dev_t dev, ...@@ -1432,6 +1483,8 @@ int lento_mknod(const char *filename, int mode, dev_t dev,
up(&nd.dentry->d_inode->i_sem); up(&nd.dentry->d_inode->i_sem);
path_release(&nd); path_release(&nd);
out: out:
putname(tmp);
return error; return error;
} }
......
...@@ -1258,14 +1258,18 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) ...@@ -1258,14 +1258,18 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev) asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
{ {
int error = 0;
char * tmp;
struct dentry * dentry; struct dentry * dentry;
struct nameidata nd; struct nameidata nd;
int error;
if (S_ISDIR(mode)) if (S_ISDIR(mode))
return -EPERM; return -EPERM;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
error = __user_walk(filename, LOOKUP_PARENT, &nd); error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error) if (error)
goto out; goto out;
dentry = lookup_create(&nd, 0); dentry = lookup_create(&nd, 0);
...@@ -1291,6 +1295,8 @@ asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev) ...@@ -1291,6 +1295,8 @@ asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
up(&nd.dentry->d_inode->i_sem); up(&nd.dentry->d_inode->i_sem);
path_release(&nd); path_release(&nd);
out: out:
putname(tmp);
return error; return error;
} }
...@@ -1314,23 +1320,31 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -1314,23 +1320,31 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
asmlinkage long sys_mkdir(const char * pathname, int mode) asmlinkage long sys_mkdir(const char * pathname, int mode)
{ {
struct nameidata nd; int error = 0;
struct dentry *dentry; char * tmp;
int error;
error = __user_walk(pathname, LOOKUP_PARENT, &nd); tmp = getname(pathname);
if (error) error = PTR_ERR(tmp);
goto out; if (!IS_ERR(tmp)) {
dentry = lookup_create(&nd, 1); struct dentry *dentry;
error = PTR_ERR(dentry); struct nameidata nd;
if (!IS_ERR(dentry)) {
error = vfs_mkdir(nd.dentry->d_inode, dentry, error = path_lookup(tmp, LOOKUP_PARENT, &nd);
mode & ~current->fs->umask); if (error)
dput(dentry); goto out;
} dentry = lookup_create(&nd, 1);
up(&nd.dentry->d_inode->i_sem); error = PTR_ERR(dentry);
path_release(&nd); if (!IS_ERR(dentry)) {
error = vfs_mkdir(nd.dentry->d_inode, dentry,
mode & ~current->fs->umask);
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out: out:
putname(tmp);
}
return error; return error;
} }
...@@ -1397,11 +1411,16 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1397,11 +1411,16 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
asmlinkage long sys_rmdir(const char * pathname) asmlinkage long sys_rmdir(const char * pathname)
{ {
int error = 0;
char * name;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
int error;
error = __user_walk(pathname, LOOKUP_PARENT, &nd); name = getname(pathname);
if(IS_ERR(name))
return PTR_ERR(name);
error = path_lookup(name, LOOKUP_PARENT, &nd);
if (error) if (error)
goto exit; goto exit;
...@@ -1427,6 +1446,7 @@ asmlinkage long sys_rmdir(const char * pathname) ...@@ -1427,6 +1446,7 @@ asmlinkage long sys_rmdir(const char * pathname)
exit1: exit1:
path_release(&nd); path_release(&nd);
exit: exit:
putname(name);
return error; return error;
} }
...@@ -1462,11 +1482,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1462,11 +1482,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
asmlinkage long sys_unlink(const char * pathname) asmlinkage long sys_unlink(const char * pathname)
{ {
int error = 0;
char * name;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
int error;
error = __user_walk(pathname, LOOKUP_PARENT, &nd); name = getname(pathname);
if(IS_ERR(name))
return PTR_ERR(name);
error = path_lookup(name, LOOKUP_PARENT, &nd);
if (error) if (error)
goto exit; goto exit;
error = -EISDIR; error = -EISDIR;
...@@ -1487,6 +1512,8 @@ asmlinkage long sys_unlink(const char * pathname) ...@@ -1487,6 +1512,8 @@ asmlinkage long sys_unlink(const char * pathname)
exit1: exit1:
path_release(&nd); path_release(&nd);
exit: exit:
putname(name);
return error; return error;
slashes: slashes:
...@@ -1514,26 +1541,33 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) ...@@ -1514,26 +1541,33 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
asmlinkage long sys_symlink(const char * oldname, const char * newname) asmlinkage long sys_symlink(const char * oldname, const char * newname)
{ {
struct dentry *dentry; int error = 0;
char *from = getname(oldname); char * from;
struct nameidata nd; char * to;
int error;
if (IS_ERR(from)) from = getname(oldname);
if(IS_ERR(from))
return PTR_ERR(from); return PTR_ERR(from);
to = getname(newname);
error = PTR_ERR(to);
if (!IS_ERR(to)) {
struct dentry *dentry;
struct nameidata nd;
error = __user_walk(newname, LOOKUP_PARENT, &nd); error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error) if (error)
goto out; goto out;
dentry = lookup_create(&nd, 0); dentry = lookup_create(&nd, 0);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
error = vfs_symlink(nd.dentry->d_inode, dentry, from); error = vfs_symlink(nd.dentry->d_inode, dentry, from);
dput(dentry); dput(dentry);
} }
up(&nd.dentry->d_inode->i_sem); up(&nd.dentry->d_inode->i_sem);
path_release(&nd); path_release(&nd);
out: out:
putname(to);
}
putname(from); putname(from);
return error; return error;
} }
...@@ -1586,11 +1620,16 @@ asmlinkage long sys_link(const char * oldname, const char * newname) ...@@ -1586,11 +1620,16 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
struct dentry *new_dentry; struct dentry *new_dentry;
struct nameidata nd, old_nd; struct nameidata nd, old_nd;
int error; int error;
char * to;
to = getname(newname);
if (IS_ERR(to))
return PTR_ERR(to);
error = __user_walk(oldname, 0, &old_nd); error = __user_walk(oldname, 0, &old_nd);
if (error) if (error)
goto exit; goto exit;
error = __user_walk(newname, LOOKUP_PARENT, &nd); error = path_lookup(to, 0, &nd);
if (error) if (error)
goto out; goto out;
error = -EXDEV; error = -EXDEV;
...@@ -1608,6 +1647,8 @@ asmlinkage long sys_link(const char * oldname, const char * newname) ...@@ -1608,6 +1647,8 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
out: out:
path_release(&old_nd); path_release(&old_nd);
exit: exit:
putname(to);
return error; return error;
} }
...@@ -1755,7 +1796,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1755,7 +1796,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return error; return error;
} }
asmlinkage long sys_rename(const char * oldname, const char * newname) static inline int do_rename(const char * oldname, const char * newname)
{ {
int error = 0; int error = 0;
struct dentry * old_dir, * new_dir; struct dentry * old_dir, * new_dir;
...@@ -1763,11 +1804,11 @@ asmlinkage long sys_rename(const char * oldname, const char * newname) ...@@ -1763,11 +1804,11 @@ asmlinkage long sys_rename(const char * oldname, const char * newname)
struct dentry * trap; struct dentry * trap;
struct nameidata oldnd, newnd; struct nameidata oldnd, newnd;
error = __user_walk(oldname, LOOKUP_PARENT, &oldnd); error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
if (error) if (error)
goto exit; goto exit;
error = __user_walk(newname, LOOKUP_PARENT, &newnd); error = path_lookup(newname, LOOKUP_PARENT, &newnd);
if (error) if (error)
goto exit1; goto exit1;
...@@ -1831,6 +1872,25 @@ asmlinkage long sys_rename(const char * oldname, const char * newname) ...@@ -1831,6 +1872,25 @@ asmlinkage long sys_rename(const char * oldname, const char * newname)
return error; return error;
} }
asmlinkage long sys_rename(const char * oldname, const char * newname)
{
int error;
char * from;
char * to;
from = getname(oldname);
if(IS_ERR(from))
return PTR_ERR(from);
to = getname(newname);
error = PTR_ERR(to);
if (!IS_ERR(to)) {
error = do_rename(from,to);
putname(to);
}
putname(from);
return error;
}
int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, const char *link) int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, const char *link)
{ {
int len; int len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment