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)
{
int error;
struct nameidata nd;
char * pathname;
struct dentry *dentry;
struct presto_file_set *fset;
ENTRY;
pathname = getname(name);
error = PTR_ERR(pathname);
if (IS_ERR(pathname)) {
EXIT;
goto exit;
}
/* this looks up the parent */
error = __user_walk(name, LOOKUP_PARENT, &nd);
error = path_lookup(pathname, LOOKUP_PARENT, &nd);
if (error) {
EXIT;
goto exit;
......@@ -558,6 +566,7 @@ int lento_create(const char *name, int mode, struct lento_vfs_context *info)
path_release (&nd);
dput(dentry);
up(&dentry->d_parent->d_inode->i_sem);
putname(pathname);
exit:
return error;
}
......@@ -662,14 +671,19 @@ int lento_link(const char * oldname, const char * newname,
struct lento_vfs_context *info)
{
int error;
struct presto_file_set *fset;
struct dentry *new_dentry;
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)
goto exit;
error = __user_walk(newname, LOOKUP_PARENT, &nd);
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error)
goto out;
error = -EXDEV;
......@@ -697,6 +711,8 @@ int lento_link(const char * oldname, const char * newname,
out:
path_release(&old_nd);
exit:
putname(to);
return error;
}
......@@ -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 error = 0;
char * name;
struct dentry *dentry;
struct nameidata nd;
struct presto_file_set *fset;
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)
goto exit;
error = -EISDIR;
......@@ -840,6 +861,8 @@ int lento_unlink(const char *pathname, struct lento_vfs_context *info)
exit1:
path_release(&nd);
exit:
putname(name);
return error;
slashes:
......@@ -951,6 +974,7 @@ int lento_symlink(const char *oldname, const char *newname,
{
int error;
char *from;
char *to;
struct dentry *dentry;
struct presto_file_set *fset;
struct nameidata nd;
......@@ -964,7 +988,14 @@ int lento_symlink(const char *oldname, const char *newname,
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) {
EXIT;
goto exit_to;
......@@ -987,13 +1018,14 @@ int lento_symlink(const char *oldname, const char *newname,
goto exit_lock;
}
error = presto_do_symlink(fset, nd.dentry,
dentry, from, info);
dentry, oldname, info);
path_release(&nd);
EXIT;
exit_lock:
up(&nd.dentry->d_inode->i_sem);
dput(dentry);
exit_to:
putname(to);
exit_from:
putname(from);
exit:
......@@ -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 error;
char *pathname;
struct dentry *dentry;
struct presto_file_set *fset;
struct nameidata nd;
......@@ -1115,7 +1148,14 @@ int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info)
ENTRY;
CDEBUG(D_PIOCTL, "name: %s, mode %o, offset %d, recno %d, flags %x\n",
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)
goto out_name;
......@@ -1139,6 +1179,7 @@ int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info)
path_release(&nd);
out_name:
EXIT;
putname(pathname);
CDEBUG(D_PIOCTL, "error: %d\n", error);
return error;
}
......@@ -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 error = 0;
char * name;
struct dentry *dentry;
struct presto_file_set *fset;
struct nameidata nd;
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)
goto exit;
......@@ -1281,6 +1327,7 @@ int lento_rmdir(const char *pathname, struct lento_vfs_context *info)
path_release(&nd);
exit:
EXIT;
putname(name);
return error;
}
......@@ -1390,6 +1437,7 @@ int lento_mknod(const char *filename, int mode, dev_t dev,
struct lento_vfs_context *info)
{
int error = 0;
char * tmp;
struct dentry * dentry;
struct nameidata nd;
struct presto_file_set *fset;
......@@ -1398,8 +1446,11 @@ int lento_mknod(const char *filename, int mode, dev_t dev,
if (S_ISDIR(mode))
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)
goto out;
dentry = lookup_create(&nd, 0);
......@@ -1432,6 +1483,8 @@ int lento_mknod(const char *filename, int mode, dev_t dev,
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
return error;
}
......
......@@ -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)
{
int error = 0;
char * tmp;
struct dentry * dentry;
struct nameidata nd;
int error;
if (S_ISDIR(mode))
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)
goto out;
dentry = lookup_create(&nd, 0);
......@@ -1291,6 +1295,8 @@ asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
return error;
}
......@@ -1314,11 +1320,16 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
asmlinkage long sys_mkdir(const char * pathname, int mode)
{
struct nameidata nd;
int error = 0;
char * tmp;
tmp = getname(pathname);
error = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
struct dentry *dentry;
int error;
struct nameidata nd;
error = __user_walk(pathname, LOOKUP_PARENT, &nd);
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
dentry = lookup_create(&nd, 1);
......@@ -1331,6 +1342,9 @@ asmlinkage long sys_mkdir(const char * pathname, int mode)
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
}
return error;
}
......@@ -1397,11 +1411,16 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
asmlinkage long sys_rmdir(const char * pathname)
{
int error = 0;
char * name;
struct dentry *dentry;
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)
goto exit;
......@@ -1427,6 +1446,7 @@ asmlinkage long sys_rmdir(const char * pathname)
exit1:
path_release(&nd);
exit:
putname(name);
return error;
}
......@@ -1462,11 +1482,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
asmlinkage long sys_unlink(const char * pathname)
{
int error = 0;
char * name;
struct dentry *dentry;
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)
goto exit;
error = -EISDIR;
......@@ -1487,6 +1512,8 @@ asmlinkage long sys_unlink(const char * pathname)
exit1:
path_release(&nd);
exit:
putname(name);
return error;
slashes:
......@@ -1514,15 +1541,20 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
asmlinkage long sys_symlink(const char * oldname, const char * newname)
{
struct dentry *dentry;
char *from = getname(oldname);
struct nameidata nd;
int error;
int error = 0;
char * from;
char * to;
if (IS_ERR(from))
from = getname(oldname);
if(IS_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)
goto out;
dentry = lookup_create(&nd, 0);
......@@ -1534,6 +1566,8 @@ asmlinkage long sys_symlink(const char * oldname, const char * newname)
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(to);
}
putname(from);
return error;
}
......@@ -1586,11 +1620,16 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
struct dentry *new_dentry;
struct nameidata nd, old_nd;
int error;
char * to;
to = getname(newname);
if (IS_ERR(to))
return PTR_ERR(to);
error = __user_walk(oldname, 0, &old_nd);
if (error)
goto exit;
error = __user_walk(newname, LOOKUP_PARENT, &nd);
error = path_lookup(to, 0, &nd);
if (error)
goto out;
error = -EXDEV;
......@@ -1608,6 +1647,8 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
out:
path_release(&old_nd);
exit:
putname(to);
return error;
}
......@@ -1755,7 +1796,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
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;
struct dentry * old_dir, * new_dir;
......@@ -1763,11 +1804,11 @@ asmlinkage long sys_rename(const char * oldname, const char * newname)
struct dentry * trap;
struct nameidata oldnd, newnd;
error = __user_walk(oldname, LOOKUP_PARENT, &oldnd);
error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
if (error)
goto exit;
error = __user_walk(newname, LOOKUP_PARENT, &newnd);
error = path_lookup(newname, LOOKUP_PARENT, &newnd);
if (error)
goto exit1;
......@@ -1831,6 +1872,25 @@ asmlinkage long sys_rename(const char * oldname, const char * newname)
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 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