summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/compat.c12
-rw-r--r--fs/exec.c13
-rw-r--r--fs/filesystems.c4
-rw-r--r--fs/namei.c108
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/open.c4
-rw-r--r--fs/quota/quota.c4
7 files changed, 88 insertions, 61 deletions
diff --git a/fs/compat.c b/fs/compat.c
index b7a24d0ca30d..015e1e1f87c6 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -776,16 +776,16 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
char *kernel_type;
unsigned long data_page;
char *kernel_dev;
- char *dir_page;
+ struct filename *dir;
int retval;
retval = copy_mount_string(type, &kernel_type);
if (retval < 0)
goto out;
- dir_page = getname(dir_name);
- retval = PTR_ERR(dir_page);
- if (IS_ERR(dir_page))
+ dir = getname(dir_name);
+ retval = PTR_ERR(dir);
+ if (IS_ERR(dir))
goto out1;
retval = copy_mount_string(dev_name, &kernel_dev);
@@ -807,7 +807,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
}
}
- retval = do_mount(kernel_dev, dir_page, kernel_type,
+ retval = do_mount(kernel_dev, dir->name, kernel_type,
flags, (void*)data_page);
out4:
@@ -815,7 +815,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
out3:
kfree(kernel_dev);
out2:
- putname(dir_page);
+ putname(dir);
out1:
kfree(kernel_type);
out:
diff --git a/fs/exec.c b/fs/exec.c
index ca434534ae9a..4e591e20e108 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -105,7 +105,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
SYSCALL_DEFINE1(uselib, const char __user *, library)
{
struct file *file;
- char *tmp = getname(library);
+ struct filename *tmp = getname(library);
int error = PTR_ERR(tmp);
static const struct open_flags uselib_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
@@ -116,7 +116,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
if (IS_ERR(tmp))
goto out;
- file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
+ file = do_filp_open(AT_FDCWD, tmp->name, &uselib_flags, LOOKUP_FOLLOW);
putname(tmp);
error = PTR_ERR(file);
if (IS_ERR(file))
@@ -1664,10 +1664,10 @@ SYSCALL_DEFINE3(execve,
const char __user *const __user *, argv,
const char __user *const __user *, envp)
{
- const char *path = getname(filename);
+ struct filename *path = getname(filename);
int error = PTR_ERR(path);
if (!IS_ERR(path)) {
- error = do_execve(path, argv, envp, current_pt_regs());
+ error = do_execve(path->name, argv, envp, current_pt_regs());
putname(path);
}
return error;
@@ -1677,10 +1677,11 @@ asmlinkage long compat_sys_execve(const char __user * filename,
const compat_uptr_t __user * argv,
const compat_uptr_t __user * envp)
{
- const char *path = getname(filename);
+ struct filename *path = getname(filename);
int error = PTR_ERR(path);
if (!IS_ERR(path)) {
- error = compat_do_execve(path, argv, envp, current_pt_regs());
+ error = compat_do_execve(path->name, argv, envp,
+ current_pt_regs());
putname(path);
}
return error;
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 96f24286667a..da165f6adcbf 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_filesystem);
static int fs_index(const char __user * __name)
{
struct file_system_type * tmp;
- char * name;
+ struct filename *name;
int err, index;
name = getname(__name);
@@ -135,7 +135,7 @@ static int fs_index(const char __user * __name)
err = -EINVAL;
read_lock(&file_systems_lock);
for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
- if (strcmp(tmp->name,name) == 0) {
+ if (strcmp(tmp->name, name->name) == 0) {
err = index;
break;
}
diff --git a/fs/namei.c b/fs/namei.c
index 9cc0fce7fc91..ec638d27642f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -117,18 +117,37 @@
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
* PATH_MAX includes the nul terminator --RR.
*/
-static char *getname_flags(const char __user *filename, int flags, int *empty)
+void final_putname(struct filename *name)
{
- char *result = __getname(), *err;
+ __putname(name->name);
+ kfree(name);
+}
+
+static struct filename *
+getname_flags(const char __user *filename, int flags, int *empty)
+{
+ struct filename *result, *err;
+ char *kname;
int len;
+ /* FIXME: create dedicated slabcache? */
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
- len = strncpy_from_user(result, filename, PATH_MAX);
- err = ERR_PTR(len);
- if (unlikely(len < 0))
+ kname = __getname();
+ if (unlikely(!kname)) {
+ err = ERR_PTR(-ENOMEM);
+ goto error_free_name;
+ }
+
+ result->name = kname;
+ result->uptr = filename;
+ len = strncpy_from_user(kname, filename, PATH_MAX);
+ if (unlikely(len < 0)) {
+ err = ERR_PTR(len);
goto error;
+ }
/* The empty path is special. */
if (unlikely(!len)) {
@@ -146,22 +165,25 @@ static char *getname_flags(const char __user *filename, int flags, int *empty)
}
error:
- __putname(result);
+ __putname(kname);
+error_free_name:
+ kfree(result);
return err;
}
-char *getname(const char __user * filename)
+struct filename *
+getname(const char __user * filename)
{
return getname_flags(filename, 0, NULL);
}
+EXPORT_SYMBOL(getname);
#ifdef CONFIG_AUDITSYSCALL
-void putname(const char *name)
+void putname(struct filename *name)
{
if (unlikely(!audit_dummy_context()))
- audit_putname(name);
- else
- __putname(name);
+ return audit_putname(name);
+ final_putname(name);
}
#endif
@@ -2093,13 +2115,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
struct path *path, int *empty)
{
struct nameidata nd;
- char *tmp = getname_flags(name, flags, empty);
+ struct filename *tmp = getname_flags(name, flags, empty);
int err = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
BUG_ON(flags & LOOKUP_PARENT);
- err = do_path_lookup(dfd, tmp, flags, &nd);
+ err = do_path_lookup(dfd, tmp->name, flags, &nd);
putname(tmp);
if (!err)
*path = nd.path;
@@ -2113,22 +2135,22 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
return user_path_at_empty(dfd, name, flags, path, NULL);
}
-static int user_path_parent(int dfd, const char __user *path,
- struct nameidata *nd, char **name)
+static struct filename *
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
{
- char *s = getname(path);
+ struct filename *s = getname(path);
int error;
if (IS_ERR(s))
- return PTR_ERR(s);
+ return s;
- error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
- if (error)
+ error = do_path_lookup(dfd, s->name, LOOKUP_PARENT, nd);
+ if (error) {
putname(s);
- else
- *name = s;
+ return ERR_PTR(error);
+ }
- return error;
+ return s;
}
/*
@@ -3039,11 +3061,11 @@ EXPORT_SYMBOL(done_path_create);
struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
{
- char *tmp = getname(pathname);
+ struct filename *tmp = getname(pathname);
struct dentry *res;
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- res = kern_path_create(dfd, tmp, path, is_dir);
+ res = kern_path_create(dfd, tmp->name, path, is_dir);
putname(tmp);
return res;
}
@@ -3248,13 +3270,13 @@ out:
static long do_rmdir(int dfd, const char __user *pathname)
{
int error = 0;
- char * name;
+ struct filename *name;
struct dentry *dentry;
struct nameidata nd;
- error = user_path_parent(dfd, pathname, &nd, &name);
- if (error)
- return error;
+ name = user_path_parent(dfd, pathname, &nd);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
switch(nd.last_type) {
case LAST_DOTDOT:
@@ -3343,14 +3365,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
static long do_unlinkat(int dfd, const char __user *pathname)
{
int error;
- char *name;
+ struct filename *name;
struct dentry *dentry;
struct nameidata nd;
struct inode *inode = NULL;
- error = user_path_parent(dfd, pathname, &nd, &name);
- if (error)
- return error;
+ name = user_path_parent(dfd, pathname, &nd);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
error = -EISDIR;
if (nd.last_type != LAST_NORM)
@@ -3434,7 +3456,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
int, newdfd, const char __user *, newname)
{
int error;
- char *from;
+ struct filename *from;
struct dentry *dentry;
struct path path;
@@ -3447,9 +3469,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
if (IS_ERR(dentry))
goto out_putname;
- error = security_path_symlink(&path, dentry, from);
+ error = security_path_symlink(&path, dentry, from->name);
if (!error)
- error = vfs_symlink(path.dentry->d_inode, dentry, from);
+ error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
done_path_create(&path, dentry);
out_putname:
putname(from);
@@ -3729,17 +3751,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
struct dentry *old_dentry, *new_dentry;
struct dentry *trap;
struct nameidata oldnd, newnd;
- char *from;
- char *to;
+ struct filename *from;
+ struct filename *to;
int error;
- error = user_path_parent(olddfd, oldname, &oldnd, &from);
- if (error)
+ from = user_path_parent(olddfd, oldname, &oldnd);
+ if (IS_ERR(from)) {
+ error = PTR_ERR(from);
goto exit;
+ }
- error = user_path_parent(newdfd, newname, &newnd, &to);
- if (error)
+ to = user_path_parent(newdfd, newname, &newnd);
+ if (IS_ERR(to)) {
+ error = PTR_ERR(to);
goto exit1;
+ }
error = -EXDEV;
if (oldnd.path.mnt != newnd.path.mnt)
diff --git a/fs/namespace.c b/fs/namespace.c
index fc33207e28ad..24960626bb6b 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2408,7 +2408,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
{
int ret;
char *kernel_type;
- char *kernel_dir;
+ struct filename *kernel_dir;
char *kernel_dev;
unsigned long data_page;
@@ -2430,7 +2430,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
if (ret < 0)
goto out_data;
- ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
+ ret = do_mount(kernel_dev, kernel_dir->name, kernel_type, flags,
(void *) data_page);
free_page(data_page);
diff --git a/fs/open.c b/fs/open.c
index a015437e1535..81dd92ac10ff 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -895,13 +895,13 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
- char *tmp = getname(filename);
+ struct filename *tmp = getname(filename);
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, &op, lookup);
+ struct file *f = do_filp_open(dfd, tmp->name, &op, lookup);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index ff0135d6bc51..af1661f7a54f 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -331,11 +331,11 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
#ifdef CONFIG_BLOCK
struct block_device *bdev;
struct super_block *sb;
- char *tmp = getname(special);
+ struct filename *tmp = getname(special);
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- bdev = lookup_bdev(tmp);
+ bdev = lookup_bdev(tmp->name);
putname(tmp);
if (IS_ERR(bdev))
return ERR_CAST(bdev);