vfs: define struct filename and have getname() return it
getname() is intended to copy pathname strings from userspace into a
kernel buffer. The result is just a string in kernel space. It would
however be quite helpful to be able to attach some ancillary info to
the string.
For instance, we could attach some audit-related info to reduce the
amount of audit-related processing needed. When auditing is enabled,
we could also call getname() on the string more than once and not
need to recopy it from userspace.
This patchset converts the getname()/putname() interfaces to return
a struct instead of a string. For now, the struct just tracks the
string in kernel space and the original userland pointer for it.
Later, we'll add other information to the struct as it becomes
convenient.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 63e77e3..9eb0905 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -449,7 +449,7 @@
{
int retval;
struct cdfs_args tmp;
- char *devname;
+ struct filename *devname;
retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
@@ -458,7 +458,7 @@
retval = PTR_ERR(devname);
if (IS_ERR(devname))
goto out;
- retval = do_mount(devname, dirname, "ext2", flags, NULL);
+ retval = do_mount(devname->name, dirname, "ext2", flags, NULL);
putname(devname);
out:
return retval;
@@ -469,7 +469,7 @@
{
int retval;
struct cdfs_args tmp;
- char *devname;
+ struct filename *devname;
retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
@@ -478,7 +478,7 @@
retval = PTR_ERR(devname);
if (IS_ERR(devname))
goto out;
- retval = do_mount(devname, dirname, "iso9660", flags, NULL);
+ retval = do_mount(devname->name, dirname, "iso9660", flags, NULL);
putname(devname);
out:
return retval;
@@ -499,7 +499,7 @@
int, flag, void __user *, data)
{
int retval;
- char *name;
+ struct filename *name;
name = getname(path);
retval = PTR_ERR(name);
@@ -507,13 +507,13 @@
goto out;
switch (typenr) {
case 1:
- retval = osf_ufs_mount(name, data, flag);
+ retval = osf_ufs_mount(name->name, data, flag);
break;
case 6:
- retval = osf_cdfs_mount(name, data, flag);
+ retval = osf_cdfs_mount(name->name, data, flag);
break;
case 9:
- retval = osf_procfs_mount(name, data, flag);
+ retval = osf_procfs_mount(name->name, data, flag);
break;
default:
retval = -EINVAL;
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index 905fcfb..b120df3 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -50,13 +50,13 @@
struct pt_regs *regs)
{
long error;
- char * filename;
+ struct filename *filename;
filename = getname(filenamei);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index 93f10e2..e521087 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -56,14 +56,14 @@
struct pt_regs *regs)
{
int error;
- char * filename;
+ struct filename *filename;
filename = getname(filenamei);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, compat_ptr(argv), compat_ptr(envp),
- regs);
+ error = compat_do_execve(filename->name, compat_ptr(argv),
+ compat_ptr(envp), regs);
putname(filename);
out:
return error;
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 92c5af9..1bb0a8a 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -388,14 +388,14 @@
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, uargv, uenvp, regs);
+ error = do_execve(filename->name, uargv, uenvp, regs);
putname(filename);
out:
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 62bcea7..bb1cc72 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -213,14 +213,14 @@
const char __user *const __user *envp)
{
int error;
- char *filename;
+ struct filename *filename;
struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
return error;
}
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index bee8df4..15ac715 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -212,14 +212,14 @@
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname(fname);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c
index 0570e8c..4e99922 100644
--- a/arch/cris/arch-v32/kernel/process.c
+++ b/arch/cris/arch-v32/kernel/process.c
@@ -224,7 +224,7 @@
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname(fname);
error = PTR_ERR(filename);
@@ -232,7 +232,7 @@
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index f153ed1..e8dc139 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -217,14 +217,14 @@
int dummy, ...)
{
int error;
- char * filename;
+ struct filename *filename;
struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
return error;
}
diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c
index 553cd60..25a9bfe 100644
--- a/arch/hexagon/kernel/syscall.c
+++ b/arch/hexagon/kernel/syscall.c
@@ -40,7 +40,7 @@
const char __user *const __user *envp)
{
struct pt_regs *pregs = current_thread_info()->regs;
- char *filename;
+ struct filename *filename;
int retval;
filename = getname(ufilename);
@@ -48,7 +48,7 @@
if (IS_ERR(filename))
return retval;
- retval = do_execve(filename, argv, envp, pregs);
+ retval = do_execve(filename->name, argv, envp, pregs);
putname(filename);
return retval;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index ee31fe9..35e106f 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -614,14 +614,14 @@
const char __user *const __user *envp,
struct pt_regs *regs)
{
- char *fname;
+ struct filename *fname;
int error;
fname = getname(filename);
error = PTR_ERR(fname);
if (IS_ERR(fname))
goto out;
- error = do_execve(fname, argv, envp, regs);
+ error = do_execve(fname->name, argv, envp, regs);
putname(fname);
out:
return error;
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 384e63f..e736627 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -296,14 +296,14 @@
unsigned long r6, struct pt_regs regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, uargv, uenvp, ®s);
+ error = do_execve(filename->name, uargv, uenvp, ®s);
putname(filename);
out:
return error;
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c
index e5b154f..404c0f2 100644
--- a/arch/microblaze/kernel/sys_microblaze.c
+++ b/arch/microblaze/kernel/sys_microblaze.c
@@ -54,13 +54,13 @@
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname(filenamei);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 922a554..3a21ace 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -83,13 +83,13 @@
asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
{
int error;
- char * filename;
+ struct filename *filename;
filename = getname(compat_ptr(regs.regs[4]));
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
+ error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]),
compat_ptr(regs.regs[6]), ®s);
putname(filename);
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index b08220c..2bd561b 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -133,13 +133,13 @@
asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
{
int error;
- char * filename;
+ struct filename *filename;
filename = getname((const char __user *) (long)regs.regs[4]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *) (long)regs.regs[5],
(const char __user *const __user *) (long)regs.regs[6],
®s);
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
index 55210f3..c35f3ab 100644
--- a/arch/openrisc/kernel/process.c
+++ b/arch/openrisc/kernel/process.c
@@ -271,7 +271,7 @@
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname(name);
error = PTR_ERR(filename);
@@ -279,7 +279,7 @@
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index 6785de7..a0760b8 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -34,14 +34,14 @@
int hpux_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *) regs->gr[25],
(const char __user *const __user *) regs->gr[24],
regs);
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 8c6b6b6..cbc3721 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -342,13 +342,13 @@
asmlinkage int sys_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *) regs->gr[25],
(const char __user *const __user *) regs->gr[24],
regs);
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index dc9a624..bf5b93a 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -60,14 +60,14 @@
asmlinkage int sys32_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, compat_ptr(regs->gr[25]),
+ error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]),
compat_ptr(regs->gr[24]), regs);
putname(filename);
out:
diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c
index 21e8679..d45cf00 100644
--- a/arch/score/kernel/sys_score.c
+++ b/arch/score/kernel/sys_score.c
@@ -92,14 +92,14 @@
score_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname((char __user*)regs->regs[4]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *)regs->regs[5],
(const char __user *const __user *)regs->regs[6],
regs);
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 59521e8..ba7345f 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -298,14 +298,14 @@
{
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int error;
- char *filename;
+ struct filename *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, uargv, uenvp, regs);
+ error = do_execve(filename->name, uargv, uenvp, regs);
putname(filename);
out:
return error;
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index 602545b..98a709f 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -491,14 +491,14 @@
struct pt_regs *pregs)
{
int error;
- char *filename;
+ struct filename *filename;
filename = getname((char __user *)ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *)uargv,
(const char __user *const __user *)uenvp,
pregs);
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 14006d8..487bffb 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -482,7 +482,7 @@
asmlinkage int sparc_execve(struct pt_regs *regs)
{
int error, base = 0;
- char *filename;
+ struct filename *filename;
/* Check for indirect call. */
if(regs->u_regs[UREG_G1] == 0)
@@ -492,7 +492,7 @@
error = PTR_ERR(filename);
if(IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *)
regs->u_regs[base + UREG_I1],
(const char __user *const __user *)
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index aff0c72..fcaa594 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -722,7 +722,7 @@
asmlinkage int sparc_execve(struct pt_regs *regs)
{
int error, base = 0;
- char *filename;
+ struct filename *filename;
/* User register window flush is done by entry.S */
@@ -734,7 +734,7 @@
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *)
regs->u_regs[base + UREG_I1],
(const char __user *const __user *)
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index d862499..c323981 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -403,7 +403,7 @@
asmlinkage long sparc32_execve(struct pt_regs *regs)
{
int error, base = 0;
- char *filename;
+ struct filename *filename;
/* User register window flush is done by entry.S */
@@ -416,7 +416,7 @@
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename,
+ error = compat_do_execve(filename->name,
compat_ptr(regs->u_regs[base + UREG_I1]),
compat_ptr(regs->u_regs[base + UREG_I2]), regs);
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 6be7991..6225600 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -594,13 +594,13 @@
struct pt_regs *, regs)
{
long error;
- char *filename;
+ struct filename *filename;
filename = getname(path);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
if (error == 0)
single_step_execve();
@@ -615,13 +615,13 @@
struct pt_regs *regs)
{
long error;
- char *filename;
+ struct filename *filename;
filename = getname(path);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, argv, envp, regs);
+ error = compat_do_execve(filename->name, argv, envp, regs);
putname(filename);
if (error == 0)
single_step_execve();
diff --git a/arch/unicore32/kernel/sys.c b/arch/unicore32/kernel/sys.c
index 5fd9af7..fabdee9 100644
--- a/arch/unicore32/kernel/sys.c
+++ b/arch/unicore32/kernel/sys.c
@@ -51,13 +51,13 @@
struct pt_regs *regs)
{
int error;
- char *fn;
+ struct filename *fn;
fn = getname(filename);
error = PTR_ERR(fn);
if (IS_ERR(fn))
goto out;
- error = do_execve(fn, argv, envp, regs);
+ error = do_execve(fn->name, argv, envp, regs);
putname(fn);
out:
return error;
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index bc44311..bc02082 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -328,13 +328,13 @@
struct pt_regs *regs)
{
long error;
- char * filename;
+ struct filename *filename;
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/fs/compat.c b/fs/compat.c
index b7a24d0..015e1e1 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -776,16 +776,16 @@
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 @@
}
}
- 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 @@
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 ca43453..4e591e2 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -105,7 +105,7 @@
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 @@
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 @@
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 @@
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 96f2428..da165f6 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -124,7 +124,7 @@
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 @@
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 9cc0fce..ec638d2 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
int, newdfd, const char __user *, newname)
{
int error;
- char *from;
+ struct filename *from;
struct dentry *dentry;
struct path path;
@@ -3447,9 +3469,9 @@
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 @@
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 fc33207..2496062 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2408,7 +2408,7 @@
{
int ret;
char *kernel_type;
- char *kernel_dir;
+ struct filename *kernel_dir;
char *kernel_dev;
unsigned long data_page;
@@ -2430,7 +2430,7 @@
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 a015437..81dd92a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -895,13 +895,13 @@
{
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 ff0135d..af1661f 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -331,11 +331,11 @@
#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);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 3df643d..94d2916 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -460,6 +460,8 @@
#define AUDIT_TYPE_CHILD_DELETE 3 /* a child being deleted */
#define AUDIT_TYPE_CHILD_CREATE 4 /* a child being created */
+struct filename;
+
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
/* Public API */
@@ -469,8 +471,8 @@
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
-extern void __audit_getname(const char *name);
-extern void audit_putname(const char *name);
+extern void __audit_getname(struct filename *name);
+extern void audit_putname(struct filename *name);
extern void __audit_inode(const char *name, const struct dentry *dentry,
unsigned int parent);
extern void __audit_inode_child(const struct inode *parent,
@@ -505,7 +507,7 @@
__audit_syscall_exit(success, return_code);
}
}
-static inline void audit_getname(const char *name)
+static inline void audit_getname(struct filename *name)
{
if (unlikely(!audit_dummy_context()))
__audit_getname(name);
@@ -663,9 +665,9 @@
{
return 1;
}
-static inline void audit_getname(const char *name)
+static inline void audit_getname(struct filename *name)
{ }
-static inline void audit_putname(const char *name)
+static inline void audit_putname(struct filename *name)
{ }
static inline void __audit_inode(const char *name, const struct dentry *dentry,
unsigned int parent)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b44b4ca..6c93b46 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2196,6 +2196,10 @@
#endif /* CONFIG_FILE_LOCKING */
/* fs/open.c */
+struct filename {
+ const char *name; /* pointer to actual string */
+ const __user char *uptr; /* original userland pointer */
+};
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp);
@@ -2208,7 +2212,9 @@
const char *, int);
extern struct file * dentry_open(const struct path *, int, const struct cred *);
extern int filp_close(struct file *, fl_owner_t id);
-extern char * getname(const char __user *);
+
+extern struct filename *getname(const char __user *);
+
enum {
FILE_CREATED = 1,
FILE_OPENED = 2
@@ -2228,12 +2234,14 @@
extern struct kmem_cache *names_cachep;
+extern void final_putname(struct filename *name);
+
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
#ifndef CONFIG_AUDITSYSCALL
-#define putname(name) __putname(name)
+#define putname(name) final_putname(name)
#else
-extern void putname(const char *name);
+extern void putname(struct filename *name);
#endif
#ifdef CONFIG_BLOCK
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 9553ed0..6c5d9dc 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -772,7 +772,7 @@
{
struct path path;
struct file *filp;
- char *name;
+ struct filename *name;
struct mq_attr attr;
int fd, error;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
@@ -795,7 +795,7 @@
ro = mnt_want_write(mnt); /* we'll drop it in any case */
error = 0;
mutex_lock(&root->d_inode->i_mutex);
- path.dentry = lookup_one_len(name, root, strlen(name));
+ path.dentry = lookup_one_len(name->name, root, strlen(name->name));
if (IS_ERR(path.dentry)) {
error = PTR_ERR(path.dentry);
goto out_putfd;
@@ -804,7 +804,7 @@
if (oflag & O_CREAT) {
if (path.dentry->d_inode) { /* entry already exists */
- audit_inode(name, path.dentry, 0);
+ audit_inode(name->name, path.dentry, 0);
if (oflag & O_EXCL) {
error = -EEXIST;
goto out;
@@ -824,7 +824,7 @@
error = -ENOENT;
goto out;
}
- audit_inode(name, path.dentry, 0);
+ audit_inode(name->name, path.dentry, 0);
filp = do_open(&path, oflag);
}
@@ -849,7 +849,7 @@
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{
int err;
- char *name;
+ struct filename *name;
struct dentry *dentry;
struct inode *inode = NULL;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
@@ -863,7 +863,8 @@
if (err)
goto out_name;
mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT);
- dentry = lookup_one_len(name, mnt->mnt_root, strlen(name));
+ dentry = lookup_one_len(name->name, mnt->mnt_root,
+ strlen(name->name));
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out_unlock;
diff --git a/kernel/acct.c b/kernel/acct.c
index 5be0101..0835419 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -260,10 +260,10 @@
return -EPERM;
if (name) {
- char *tmp = getname(name);
+ struct filename *tmp = getname(name);
if (IS_ERR(tmp))
return (PTR_ERR(tmp));
- error = acct_on(tmp);
+ error = acct_on(tmp->name);
putname(tmp);
} else {
struct bsd_acct_struct *acct;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d147585..d4d8231 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -103,28 +103,29 @@
* we don't let putname() free it (instead we free all of the saved
* pointers at syscall exit time).
*
- * Further, in fs/namei.c:path_lookup() we store the inode and device. */
+ * Further, in fs/namei.c:path_lookup() we store the inode and device.
+ */
struct audit_names {
- struct list_head list; /* audit_context->names_list */
- const char *name;
- unsigned long ino;
- dev_t dev;
- umode_t mode;
- kuid_t uid;
- kgid_t gid;
- dev_t rdev;
- u32 osid;
- struct audit_cap_data fcap;
- unsigned int fcap_ver;
- int name_len; /* number of name's characters to log */
- unsigned char type; /* record type */
- bool name_put; /* call __putname() for this name */
+ struct list_head list; /* audit_context->names_list */
+ struct filename *name;
+ unsigned long ino;
+ dev_t dev;
+ umode_t mode;
+ kuid_t uid;
+ kgid_t gid;
+ dev_t rdev;
+ u32 osid;
+ struct audit_cap_data fcap;
+ unsigned int fcap_ver;
+ int name_len; /* number of name's characters to log */
+ unsigned char type; /* record type */
+ bool name_put; /* call __putname() for this name */
/*
* This was an allocated audit_names and not from the array of
* names allocated in the task audit context. Thus this name
* should be freed on syscall exit
*/
- bool should_free;
+ bool should_free;
};
struct audit_aux_data {
@@ -996,7 +997,7 @@
context->ino_count);
list_for_each_entry(n, &context->names_list, list) {
printk(KERN_ERR "names[%d] = %p = %s\n", i,
- n->name, n->name ?: "(null)");
+ n->name, n->name->name ?: "(null)");
}
dump_stack();
return;
@@ -1553,7 +1554,7 @@
case AUDIT_NAME_FULL:
/* log the full path */
audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, n->name);
+ audit_log_untrustedstring(ab, n->name->name);
break;
case 0:
/* name was specified as a relative path and the
@@ -1563,7 +1564,7 @@
default:
/* log the name's directory component */
audit_log_format(ab, " name=");
- audit_log_n_untrustedstring(ab, n->name,
+ audit_log_n_untrustedstring(ab, n->name->name,
n->name_len);
}
} else
@@ -2026,7 +2027,7 @@
* Add a name to the list of audit names for this context.
* Called from fs/namei.c:getname().
*/
-void __audit_getname(const char *name)
+void __audit_getname(struct filename *name)
{
struct audit_context *context = current->audit_context;
struct audit_names *n;
@@ -2040,6 +2041,11 @@
return;
}
+#if AUDIT_DEBUG
+ /* The filename _must_ have a populated ->name */
+ BUG_ON(!name->name);
+#endif
+
n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
if (!n)
return;
@@ -2059,7 +2065,7 @@
* then we delay the putname until syscall exit.
* Called from include/linux/fs.h:putname().
*/
-void audit_putname(const char *name)
+void audit_putname(struct filename *name)
{
struct audit_context *context = current->audit_context;
@@ -2074,7 +2080,7 @@
list_for_each_entry(n, &context->names_list, list)
printk(KERN_ERR "name[%d] = %p = %s\n", i,
- n->name, n->name ?: "(null)");
+ n->name, n->name->name ?: "(null)");
}
#endif
__putname(name);
@@ -2088,8 +2094,8 @@
" put_count=%d\n",
__FILE__, __LINE__,
context->serial, context->major,
- context->in_syscall, name, context->name_count,
- context->put_count);
+ context->in_syscall, name->name,
+ context->name_count, context->put_count);
dump_stack();
}
}
@@ -2152,7 +2158,7 @@
list_for_each_entry_reverse(n, &context->names_list, list) {
/* does the name pointer match? */
- if (n->name != name)
+ if (!n->name || n->name->name != name)
continue;
/* match the correct record type */
@@ -2175,7 +2181,7 @@
return;
out:
if (parent) {
- n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL;
+ n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
n->type = AUDIT_TYPE_PARENT;
} else {
n->name_len = AUDIT_NAME_FULL;
@@ -2220,7 +2226,7 @@
continue;
if (n->ino == parent->i_ino &&
- !audit_compare_dname_path(dname, n->name, n->name_len)) {
+ !audit_compare_dname_path(dname, n->name->name, n->name_len)) {
found_parent = n;
break;
}
@@ -2236,8 +2242,8 @@
if (found_parent && (n->name != found_parent->name))
continue;
- if (!strcmp(dname, n->name) ||
- !audit_compare_dname_path(dname, n->name,
+ if (!strcmp(dname, n->name->name) ||
+ !audit_compare_dname_path(dname, n->name->name,
found_parent ?
found_parent->name_len :
AUDIT_NAME_FULL)) {
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 14e254c..90d2ed5 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1483,7 +1483,7 @@
struct file *swap_file, *victim;
struct address_space *mapping;
struct inode *inode;
- char *pathname;
+ struct filename *pathname;
int oom_score_adj;
int i, type, prev;
int err;
@@ -1498,8 +1498,7 @@
if (IS_ERR(pathname))
goto out;
- victim = filp_open(pathname, O_RDWR|O_LARGEFILE, 0);
- putname(pathname);
+ victim = filp_open(pathname->name, O_RDWR|O_LARGEFILE, 0);
err = PTR_ERR(victim);
if (IS_ERR(victim))
goto out;
@@ -1936,7 +1935,7 @@
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
{
struct swap_info_struct *p;
- char *name;
+ struct filename *name;
struct file *swap_file = NULL;
struct address_space *mapping;
int i;
@@ -1967,7 +1966,7 @@
name = NULL;
goto bad_swap;
}
- swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0);
+ swap_file = filp_open(name->name, O_RDWR|O_LARGEFILE, 0);
if (IS_ERR(swap_file)) {
error = PTR_ERR(swap_file);
swap_file = NULL;
@@ -2053,7 +2052,7 @@
printk(KERN_INFO "Adding %uk swap on %s. "
"Priority:%d extents:%d across:%lluk %s%s%s\n",
- p->pages<<(PAGE_SHIFT-10), name, p->prio,
+ p->pages<<(PAGE_SHIFT-10), name->name, p->prio,
nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
(p->flags & SWP_SOLIDSTATE) ? "SS" : "",
(p->flags & SWP_DISCARDABLE) ? "D" : "",