提交 8418263e 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull third pile of VFS updates from Al Viro:
 "Stuff from Jeff Layton, mostly.  Sanitizing interplay between audit
  and namei, removing a lot of insanity from audit_inode() mess and
  getting things ready for his ESTALE patchset."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  procfs: don't need a PATH_MAX allocation to hold a string representation of an int
  vfs: embed struct filename inside of names_cache allocation if possible
  audit: make audit_inode take struct filename
  vfs: make path_openat take a struct filename pointer
  vfs: turn do_path_lookup into wrapper around struct filename variant
  audit: allow audit code to satisfy getname requests from its names_list
  vfs: define struct filename and have getname() return it
  vfs: unexport getname and putname symbols
  acct: constify the name arg to acct_on
  vfs: allocate page instead of names_cache buffer in mount_block_root
  audit: overhaul __audit_inode_child to accomodate retrying
  audit: optimize audit_compare_dname_path
  audit: make audit_compare_dname_path use parent_len helper
  audit: remove dirlen argument to audit_compare_dname_path
  audit: set the name_len in audit_inode for parent lookups
  audit: add a new "type" field to audit_names struct
  audit: reverse arguments to audit_inode_child
  audit: no need to walk list in audit_inode if name is NULL
  audit: pass in dentry to audit_copy_inode wherever possible
  audit: remove unnecessary NULL ptr checks from do_path_lookup
...@@ -449,7 +449,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) ...@@ -449,7 +449,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
{ {
int retval; int retval;
struct cdfs_args tmp; struct cdfs_args tmp;
char *devname; struct filename *devname;
retval = -EFAULT; retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp))) if (copy_from_user(&tmp, args, sizeof(tmp)))
...@@ -458,7 +458,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) ...@@ -458,7 +458,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
retval = PTR_ERR(devname); retval = PTR_ERR(devname);
if (IS_ERR(devname)) if (IS_ERR(devname))
goto out; goto out;
retval = do_mount(devname, dirname, "ext2", flags, NULL); retval = do_mount(devname->name, dirname, "ext2", flags, NULL);
putname(devname); putname(devname);
out: out:
return retval; return retval;
...@@ -469,7 +469,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) ...@@ -469,7 +469,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
{ {
int retval; int retval;
struct cdfs_args tmp; struct cdfs_args tmp;
char *devname; struct filename *devname;
retval = -EFAULT; retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp))) if (copy_from_user(&tmp, args, sizeof(tmp)))
...@@ -478,7 +478,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) ...@@ -478,7 +478,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
retval = PTR_ERR(devname); retval = PTR_ERR(devname);
if (IS_ERR(devname)) if (IS_ERR(devname))
goto out; goto out;
retval = do_mount(devname, dirname, "iso9660", flags, NULL); retval = do_mount(devname->name, dirname, "iso9660", flags, NULL);
putname(devname); putname(devname);
out: out:
return retval; return retval;
...@@ -499,7 +499,7 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, ...@@ -499,7 +499,7 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,
int, flag, void __user *, data) int, flag, void __user *, data)
{ {
int retval; int retval;
char *name; struct filename *name;
name = getname(path); name = getname(path);
retval = PTR_ERR(name); retval = PTR_ERR(name);
...@@ -507,13 +507,13 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, ...@@ -507,13 +507,13 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,
goto out; goto out;
switch (typenr) { switch (typenr) {
case 1: case 1:
retval = osf_ufs_mount(name, data, flag); retval = osf_ufs_mount(name->name, data, flag);
break; break;
case 6: case 6:
retval = osf_cdfs_mount(name, data, flag); retval = osf_cdfs_mount(name->name, data, flag);
break; break;
case 9: case 9:
retval = osf_procfs_mount(name, data, flag); retval = osf_procfs_mount(name->name, data, flag);
break; break;
default: default:
retval = -EINVAL; retval = -EINVAL;
......
...@@ -50,13 +50,13 @@ asmlinkage long sys_execve(const char __user *filenamei, ...@@ -50,13 +50,13 @@ asmlinkage long sys_execve(const char __user *filenamei,
struct pt_regs *regs) struct pt_regs *regs)
{ {
long error; long error;
char * filename; struct filename *filename;
filename = getname(filenamei); filename = getname(filenamei);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -56,14 +56,14 @@ asmlinkage int compat_sys_execve(const char __user *filenamei, ...@@ -56,14 +56,14 @@ asmlinkage int compat_sys_execve(const char __user *filenamei,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char * filename; struct filename *filename;
filename = getname(filenamei); filename = getname(filenamei);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = compat_do_execve(filename, compat_ptr(argv), compat_ptr(envp), error = compat_do_execve(filename->name, compat_ptr(argv),
regs); compat_ptr(envp), regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -388,14 +388,14 @@ asmlinkage int sys_execve(const char __user *ufilename, ...@@ -388,14 +388,14 @@ asmlinkage int sys_execve(const char __user *ufilename,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname(ufilename); filename = getname(ufilename);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, uargv, uenvp, regs); error = do_execve(filename->name, uargv, uenvp, regs);
putname(filename); putname(filename);
out: out:
......
...@@ -213,14 +213,14 @@ asmlinkage int sys_execve(const char __user *name, ...@@ -213,14 +213,14 @@ asmlinkage int sys_execve(const char __user *name,
const char __user *const __user *envp) const char __user *const __user *envp)
{ {
int error; int error;
char *filename; struct filename *filename;
struct pt_regs *regs = (struct pt_regs *)((&name) + 6); struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
filename = getname(name); filename = getname(name);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
return error; return error;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
return error; return error;
} }
......
...@@ -212,14 +212,14 @@ asmlinkage int sys_execve(const char *fname, ...@@ -212,14 +212,14 @@ asmlinkage int sys_execve(const char *fname,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname(fname); filename = getname(fname);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -224,7 +224,7 @@ sys_execve(const char *fname, ...@@ -224,7 +224,7 @@ sys_execve(const char *fname,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname(fname); filename = getname(fname);
error = PTR_ERR(filename); error = PTR_ERR(filename);
...@@ -232,7 +232,7 @@ sys_execve(const char *fname, ...@@ -232,7 +232,7 @@ sys_execve(const char *fname,
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -217,14 +217,14 @@ asmlinkage int sys_execve(const char *name, ...@@ -217,14 +217,14 @@ asmlinkage int sys_execve(const char *name,
int dummy, ...) int dummy, ...)
{ {
int error; int error;
char * filename; struct filename *filename;
struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4); struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);
filename = getname(name); filename = getname(name);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
return error; return error;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
return error; return error;
} }
......
...@@ -40,7 +40,7 @@ asmlinkage int sys_execve(char __user *ufilename, ...@@ -40,7 +40,7 @@ asmlinkage int sys_execve(char __user *ufilename,
const char __user *const __user *envp) const char __user *const __user *envp)
{ {
struct pt_regs *pregs = current_thread_info()->regs; struct pt_regs *pregs = current_thread_info()->regs;
char *filename; struct filename *filename;
int retval; int retval;
filename = getname(ufilename); filename = getname(ufilename);
...@@ -48,7 +48,7 @@ asmlinkage int sys_execve(char __user *ufilename, ...@@ -48,7 +48,7 @@ asmlinkage int sys_execve(char __user *ufilename,
if (IS_ERR(filename)) if (IS_ERR(filename))
return retval; return retval;
retval = do_execve(filename, argv, envp, pregs); retval = do_execve(filename->name, argv, envp, pregs);
putname(filename); putname(filename);
return retval; return retval;
......
...@@ -614,14 +614,14 @@ sys_execve (const char __user *filename, ...@@ -614,14 +614,14 @@ sys_execve (const char __user *filename,
const char __user *const __user *envp, const char __user *const __user *envp,
struct pt_regs *regs) struct pt_regs *regs)
{ {
char *fname; struct filename *fname;
int error; int error;
fname = getname(filename); fname = getname(filename);
error = PTR_ERR(fname); error = PTR_ERR(fname);
if (IS_ERR(fname)) if (IS_ERR(fname))
goto out; goto out;
error = do_execve(fname, argv, envp, regs); error = do_execve(fname->name, argv, envp, regs);
putname(fname); putname(fname);
out: out:
return error; return error;
......
...@@ -296,14 +296,14 @@ asmlinkage int sys_execve(const char __user *ufilename, ...@@ -296,14 +296,14 @@ asmlinkage int sys_execve(const char __user *ufilename,
unsigned long r6, struct pt_regs regs) unsigned long r6, struct pt_regs regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname(ufilename); filename = getname(ufilename);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, uargv, uenvp, &regs); error = do_execve(filename->name, uargv, uenvp, &regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -54,13 +54,13 @@ asmlinkage long microblaze_execve(const char __user *filenamei, ...@@ -54,13 +54,13 @@ asmlinkage long microblaze_execve(const char __user *filenamei,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname(filenamei); filename = getname(filenamei);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -83,13 +83,13 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len, ...@@ -83,13 +83,13 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len,
asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs) asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
{ {
int error; int error;
char * filename; struct filename *filename;
filename = getname(compat_ptr(regs.regs[4])); filename = getname(compat_ptr(regs.regs[4]));
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; 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]), &regs); compat_ptr(regs.regs[6]), &regs);
putname(filename); putname(filename);
......
...@@ -133,13 +133,13 @@ _sys_clone(nabi_no_regargs struct pt_regs regs) ...@@ -133,13 +133,13 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs) asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
{ {
int error; int error;
char * filename; struct filename *filename;
filename = getname((const char __user *) (long)regs.regs[4]); filename = getname((const char __user *) (long)regs.regs[4]);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; 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[5],
(const char __user *const __user *) (long)regs.regs[6], (const char __user *const __user *) (long)regs.regs[6],
&regs); &regs);
......
...@@ -271,7 +271,7 @@ asmlinkage long _sys_execve(const char __user *name, ...@@ -271,7 +271,7 @@ asmlinkage long _sys_execve(const char __user *name,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname(name); filename = getname(name);
error = PTR_ERR(filename); error = PTR_ERR(filename);
...@@ -279,7 +279,7 @@ asmlinkage long _sys_execve(const char __user *name, ...@@ -279,7 +279,7 @@ asmlinkage long _sys_execve(const char __user *name,
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
out: out:
......
...@@ -34,14 +34,14 @@ ...@@ -34,14 +34,14 @@
int hpux_execve(struct pt_regs *regs) int hpux_execve(struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname((const char __user *) regs->gr[26]); filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; 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[25],
(const char __user *const __user *) regs->gr[24], (const char __user *const __user *) regs->gr[24],
regs); regs);
......
...@@ -342,13 +342,13 @@ unsigned long thread_saved_pc(struct task_struct *t) ...@@ -342,13 +342,13 @@ unsigned long thread_saved_pc(struct task_struct *t)
asmlinkage int sys_execve(struct pt_regs *regs) asmlinkage int sys_execve(struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname((const char __user *) regs->gr[26]); filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; 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[25],
(const char __user *const __user *) regs->gr[24], (const char __user *const __user *) regs->gr[24],
regs); regs);
......
...@@ -60,14 +60,14 @@ ...@@ -60,14 +60,14 @@
asmlinkage int sys32_execve(struct pt_regs *regs) asmlinkage int sys32_execve(struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26])); DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
filename = getname((const char __user *) regs->gr[26]); filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; 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); compat_ptr(regs->gr[24]), regs);
putname(filename); putname(filename);
out: out:
......
...@@ -92,14 +92,14 @@ asmlinkage long ...@@ -92,14 +92,14 @@ asmlinkage long
score_execve(struct pt_regs *regs) score_execve(struct pt_regs *regs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname((char __user*)regs->regs[4]); filename = getname((char __user*)regs->regs[4]);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
return error; 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[5],
(const char __user *const __user *)regs->regs[6], (const char __user *const __user *)regs->regs[6],
regs); regs);
......
...@@ -298,14 +298,14 @@ asmlinkage int sys_execve(const char __user *ufilename, ...@@ -298,14 +298,14 @@ asmlinkage int sys_execve(const char __user *ufilename,
{ {
struct pt_regs *regs = RELOC_HIDE(&__regs, 0); struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int error; int error;
char *filename; struct filename *filename;
filename = getname(ufilename); filename = getname(ufilename);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, uargv, uenvp, regs); error = do_execve(filename->name, uargv, uenvp, regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -491,14 +491,14 @@ asmlinkage int sys_execve(const char *ufilename, char **uargv, ...@@ -491,14 +491,14 @@ asmlinkage int sys_execve(const char *ufilename, char **uargv,
struct pt_regs *pregs) struct pt_regs *pregs)
{ {
int error; int error;
char *filename; struct filename *filename;
filename = getname((char __user *)ufilename); filename = getname((char __user *)ufilename);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, error = do_execve(filename->name,
(const char __user *const __user *)uargv, (const char __user *const __user *)uargv,
(const char __user *const __user *)uenvp, (const char __user *const __user *)uenvp,
pregs); pregs);
......
...@@ -482,7 +482,7 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) ...@@ -482,7 +482,7 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
asmlinkage int sparc_execve(struct pt_regs *regs) asmlinkage int sparc_execve(struct pt_regs *regs)
{ {
int error, base = 0; int error, base = 0;
char *filename; struct filename *filename;
/* Check for indirect call. */ /* Check for indirect call. */
if(regs->u_regs[UREG_G1] == 0) if(regs->u_regs[UREG_G1] == 0)
...@@ -492,7 +492,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs) ...@@ -492,7 +492,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
error = PTR_ERR(filename); error = PTR_ERR(filename);
if(IS_ERR(filename)) if(IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, error = do_execve(filename->name,
(const char __user *const __user *) (const char __user *const __user *)
regs->u_regs[base + UREG_I1], regs->u_regs[base + UREG_I1],
(const char __user *const __user *) (const char __user *const __user *)
......
...@@ -722,7 +722,7 @@ EXPORT_SYMBOL(dump_fpu); ...@@ -722,7 +722,7 @@ EXPORT_SYMBOL(dump_fpu);
asmlinkage int sparc_execve(struct pt_regs *regs) asmlinkage int sparc_execve(struct pt_regs *regs)
{ {
int error, base = 0; int error, base = 0;
char *filename; struct filename *filename;
/* User register window flush is done by entry.S */ /* User register window flush is done by entry.S */
...@@ -734,7 +734,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs) ...@@ -734,7 +734,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, error = do_execve(filename->name,
(const char __user *const __user *) (const char __user *const __user *)
regs->u_regs[base + UREG_I1], regs->u_regs[base + UREG_I1],
(const char __user *const __user *) (const char __user *const __user *)
......
...@@ -403,7 +403,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig, ...@@ -403,7 +403,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
asmlinkage long sparc32_execve(struct pt_regs *regs) asmlinkage long sparc32_execve(struct pt_regs *regs)
{ {
int error, base = 0; int error, base = 0;
char *filename; struct filename *filename;
/* User register window flush is done by entry.S */ /* User register window flush is done by entry.S */
...@@ -416,7 +416,7 @@ asmlinkage long sparc32_execve(struct pt_regs *regs) ...@@ -416,7 +416,7 @@ asmlinkage long sparc32_execve(struct pt_regs *regs)
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; 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_I1]),
compat_ptr(regs->u_regs[base + UREG_I2]), regs); compat_ptr(regs->u_regs[base + UREG_I2]), regs);
......
...@@ -594,13 +594,13 @@ SYSCALL_DEFINE4(execve, const char __user *, path, ...@@ -594,13 +594,13 @@ SYSCALL_DEFINE4(execve, const char __user *, path,
struct pt_regs *, regs) struct pt_regs *, regs)
{ {
long error; long error;
char *filename; struct filename *filename;
filename = getname(path); filename = getname(path);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
if (error == 0) if (error == 0)
single_step_execve(); single_step_execve();
...@@ -615,13 +615,13 @@ long compat_sys_execve(const char __user *path, ...@@ -615,13 +615,13 @@ long compat_sys_execve(const char __user *path,
struct pt_regs *regs) struct pt_regs *regs)
{ {
long error; long error;
char *filename; struct filename *filename;
filename = getname(path); filename = getname(path);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = compat_do_execve(filename, argv, envp, regs); error = compat_do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
if (error == 0) if (error == 0)
single_step_execve(); single_step_execve();
......
...@@ -51,13 +51,13 @@ asmlinkage long __sys_execve(const char __user *filename, ...@@ -51,13 +51,13 @@ asmlinkage long __sys_execve(const char __user *filename,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int error; int error;
char *fn; struct filename *fn;
fn = getname(filename); fn = getname(filename);
error = PTR_ERR(fn); error = PTR_ERR(fn);
if (IS_ERR(fn)) if (IS_ERR(fn))
goto out; goto out;
error = do_execve(fn, argv, envp, regs); error = do_execve(fn->name, argv, envp, regs);
putname(fn); putname(fn);
out: out:
return error; return error;
......
...@@ -328,13 +328,13 @@ long xtensa_execve(const char __user *name, ...@@ -328,13 +328,13 @@ long xtensa_execve(const char __user *name,
struct pt_regs *regs) struct pt_regs *regs)
{ {
long error; long error;
char * filename; struct filename *filename;
filename = getname(name); filename = getname(name);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, argv, envp, regs); error = do_execve(filename->name, argv, envp, regs);
putname(filename); putname(filename);
out: out:
return error; return error;
......
...@@ -638,7 +638,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir) ...@@ -638,7 +638,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT; return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir); BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(victim, dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC); error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error) if (error)
......
...@@ -776,16 +776,16 @@ asmlinkage long compat_sys_mount(const char __user * dev_name, ...@@ -776,16 +776,16 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
char *kernel_type; char *kernel_type;
unsigned long data_page; unsigned long data_page;
char *kernel_dev; char *kernel_dev;
char *dir_page; struct filename *dir;
int retval; int retval;
retval = copy_mount_string(type, &kernel_type); retval = copy_mount_string(type, &kernel_type);
if (retval < 0) if (retval < 0)
goto out; goto out;
dir_page = getname(dir_name); dir = getname(dir_name);
retval = PTR_ERR(dir_page); retval = PTR_ERR(dir);
if (IS_ERR(dir_page)) if (IS_ERR(dir))
goto out1; goto out1;
retval = copy_mount_string(dev_name, &kernel_dev); retval = copy_mount_string(dev_name, &kernel_dev);
...@@ -807,7 +807,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name, ...@@ -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); flags, (void*)data_page);
out4: out4:
...@@ -815,7 +815,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name, ...@@ -815,7 +815,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
out3: out3:
kfree(kernel_dev); kfree(kernel_dev);
out2: out2:
putname(dir_page); putname(dir);
out1: out1:
kfree(kernel_type); kfree(kernel_type);
out: out:
......
...@@ -105,7 +105,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt) ...@@ -105,7 +105,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
SYSCALL_DEFINE1(uselib, const char __user *, library) SYSCALL_DEFINE1(uselib, const char __user *, library)
{ {
struct file *file; struct file *file;
char *tmp = getname(library); struct filename *tmp = getname(library);
int error = PTR_ERR(tmp); int error = PTR_ERR(tmp);
static const struct open_flags uselib_flags = { static const struct open_flags uselib_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
...@@ -751,13 +751,14 @@ struct file *open_exec(const char *name) ...@@ -751,13 +751,14 @@ struct file *open_exec(const char *name)
{ {
struct file *file; struct file *file;
int err; int err;
struct filename tmp = { .name = name };
static const struct open_flags open_exec_flags = { static const struct open_flags open_exec_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
.acc_mode = MAY_EXEC | MAY_OPEN, .acc_mode = MAY_EXEC | MAY_OPEN,
.intent = LOOKUP_OPEN .intent = LOOKUP_OPEN
}; };
file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW); file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW);
if (IS_ERR(file)) if (IS_ERR(file))
goto out; goto out;
...@@ -1664,10 +1665,10 @@ SYSCALL_DEFINE3(execve, ...@@ -1664,10 +1665,10 @@ SYSCALL_DEFINE3(execve,
const char __user *const __user *, argv, const char __user *const __user *, argv,
const char __user *const __user *, envp) const char __user *const __user *, envp)
{ {
const char *path = getname(filename); struct filename *path = getname(filename);
int error = PTR_ERR(path); int error = PTR_ERR(path);
if (!IS_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); putname(path);
} }
return error; return error;
...@@ -1677,10 +1678,11 @@ asmlinkage long compat_sys_execve(const char __user * filename, ...@@ -1677,10 +1678,11 @@ asmlinkage long compat_sys_execve(const char __user * filename,
const compat_uptr_t __user * argv, const compat_uptr_t __user * argv,
const compat_uptr_t __user * envp) const compat_uptr_t __user * envp)
{ {
const char *path = getname(filename); struct filename *path = getname(filename);
int error = PTR_ERR(path); int error = PTR_ERR(path);
if (!IS_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); putname(path);
} }
return error; return error;
......
...@@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_filesystem); ...@@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_filesystem);
static int fs_index(const char __user * __name) static int fs_index(const char __user * __name)
{ {
struct file_system_type * tmp; struct file_system_type * tmp;
char * name; struct filename *name;
int err, index; int err, index;
name = getname(__name); name = getname(__name);
...@@ -135,7 +135,7 @@ static int fs_index(const char __user * __name) ...@@ -135,7 +135,7 @@ static int fs_index(const char __user * __name)
err = -EINVAL; err = -EINVAL;
read_lock(&file_systems_lock); read_lock(&file_systems_lock);
for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { 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; err = index;
break; break;
} }
......
...@@ -97,8 +97,8 @@ struct open_flags { ...@@ -97,8 +97,8 @@ struct open_flags {
int acc_mode; int acc_mode;
int intent; int intent;
}; };
extern struct file *do_filp_open(int dfd, const char *pathname, extern struct file *do_filp_open(int dfd, struct filename *pathname,
const struct open_flags *op, int lookup_flags); const struct open_flags *op, int flags);
extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
const char *, const struct open_flags *, int lookup_flags); const char *, const struct open_flags *, int lookup_flags);
......
...@@ -117,18 +117,70 @@ ...@@ -117,18 +117,70 @@
* POSIX.1 2.4: an empty pathname is invalid (ENOENT). * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
* PATH_MAX includes the nul terminator --RR. * 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; if (name->separate) {
__putname(name->name);
kfree(name);
} else {
__putname(name);
}
}
#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename))
static struct filename *
getname_flags(const char __user *filename, int flags, int *empty)
{
struct filename *result, *err;
int len; int len;
long max;
char *kname;
result = audit_reusename(filename);
if (result)
return result;
result = __getname();
if (unlikely(!result)) if (unlikely(!result))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
len = strncpy_from_user(result, filename, PATH_MAX); /*
err = ERR_PTR(len); * First, try to embed the struct filename inside the names_cache
if (unlikely(len < 0)) * allocation
*/
kname = (char *)result + sizeof(*result);
result->name = kname;
result->separate = false;
max = EMBEDDED_NAME_MAX;
recopy:
len = strncpy_from_user(kname, filename, max);
if (unlikely(len < 0)) {
err = ERR_PTR(len);
goto error; goto error;
}
/*
* Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
* separate struct filename so we can dedicate the entire
* names_cache allocation for the pathname, and re-do the copy from
* userland.
*/
if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) {
kname = (char *)result;
result = kzalloc(sizeof(*result), GFP_KERNEL);
if (!result) {
err = ERR_PTR(-ENOMEM);
result = (struct filename *)kname;
goto error;
}
result->name = kname;
result->separate = true;
max = PATH_MAX;
goto recopy;
}
/* The empty path is special. */ /* The empty path is special. */
if (unlikely(!len)) { if (unlikely(!len)) {
...@@ -140,30 +192,32 @@ static char *getname_flags(const char __user *filename, int flags, int *empty) ...@@ -140,30 +192,32 @@ static char *getname_flags(const char __user *filename, int flags, int *empty)
} }
err = ERR_PTR(-ENAMETOOLONG); err = ERR_PTR(-ENAMETOOLONG);
if (likely(len < PATH_MAX)) { if (unlikely(len >= PATH_MAX))
audit_getname(result); goto error;
return result;
} result->uptr = filename;
audit_getname(result);
return result;
error: error:
__putname(result); final_putname(result);
return err; return err;
} }
char *getname(const char __user * filename) struct filename *
getname(const char __user * filename)
{ {
return getname_flags(filename, 0, NULL); return getname_flags(filename, 0, NULL);
} }
EXPORT_SYMBOL(getname);
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
void putname(const char *name) void putname(struct filename *name)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
audit_putname(name); return audit_putname(name);
else final_putname(name);
__putname(name);
} }
EXPORT_SYMBOL(putname);
#endif #endif
static int check_acl(struct inode *inode, int mask) static int check_acl(struct inode *inode, int mask)
...@@ -1963,24 +2017,29 @@ static int path_lookupat(int dfd, const char *name, ...@@ -1963,24 +2017,29 @@ static int path_lookupat(int dfd, const char *name,
return err; return err;
} }
static int do_path_lookup(int dfd, const char *name, static int filename_lookup(int dfd, struct filename *name,
unsigned int flags, struct nameidata *nd) unsigned int flags, struct nameidata *nd)
{ {
int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);
if (unlikely(retval == -ECHILD)) if (unlikely(retval == -ECHILD))
retval = path_lookupat(dfd, name, flags, nd); retval = path_lookupat(dfd, name->name, flags, nd);
if (unlikely(retval == -ESTALE)) if (unlikely(retval == -ESTALE))
retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd); retval = path_lookupat(dfd, name->name,
flags | LOOKUP_REVAL, nd);
if (likely(!retval)) { if (likely(!retval))
if (unlikely(!audit_dummy_context())) { audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
if (nd->path.dentry && nd->inode)
audit_inode(name, nd->path.dentry);
}
}
return retval; return retval;
} }
static int do_path_lookup(int dfd, const char *name,
unsigned int flags, struct nameidata *nd)
{
struct filename filename = { .name = name };
return filename_lookup(dfd, &filename, flags, nd);
}
/* does lookup, returns the object with parent locked */ /* does lookup, returns the object with parent locked */
struct dentry *kern_path_locked(const char *name, struct path *path) struct dentry *kern_path_locked(const char *name, struct path *path)
{ {
...@@ -2098,13 +2157,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags, ...@@ -2098,13 +2157,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
struct path *path, int *empty) struct path *path, int *empty)
{ {
struct nameidata nd; struct nameidata nd;
char *tmp = getname_flags(name, flags, empty); struct filename *tmp = getname_flags(name, flags, empty);
int err = PTR_ERR(tmp); int err = PTR_ERR(tmp);
if (!IS_ERR(tmp)) { if (!IS_ERR(tmp)) {
BUG_ON(flags & LOOKUP_PARENT); BUG_ON(flags & LOOKUP_PARENT);
err = do_path_lookup(dfd, tmp, flags, &nd); err = filename_lookup(dfd, tmp, flags, &nd);
putname(tmp); putname(tmp);
if (!err) if (!err)
*path = nd.path; *path = nd.path;
...@@ -2118,22 +2177,28 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, ...@@ -2118,22 +2177,28 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
return user_path_at_empty(dfd, name, flags, path, NULL); 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) * NB: most callers don't do anything directly with the reference to the
* to struct filename, but the nd->last pointer points into the name string
* allocated by getname. So we must hold the reference to it until all
* path-walking is complete.
*/
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; int error;
if (IS_ERR(s)) if (IS_ERR(s))
return PTR_ERR(s); return s;
error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd); error = filename_lookup(dfd, s, LOOKUP_PARENT, nd);
if (error) if (error) {
putname(s); putname(s);
else return ERR_PTR(error);
*name = s; }
return error; return s;
} }
/* /*
...@@ -2180,7 +2245,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) ...@@ -2180,7 +2245,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT; return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir); BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(victim, dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC); error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error) if (error)
...@@ -2625,7 +2690,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, ...@@ -2625,7 +2690,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
*/ */
static int do_last(struct nameidata *nd, struct path *path, static int do_last(struct nameidata *nd, struct path *path,
struct file *file, const struct open_flags *op, struct file *file, const struct open_flags *op,
int *opened, const char *pathname) int *opened, struct filename *name)
{ {
struct dentry *dir = nd->path.dentry; struct dentry *dir = nd->path.dentry;
int open_flag = op->open_flag; int open_flag = op->open_flag;
...@@ -2652,7 +2717,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2652,7 +2717,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = complete_walk(nd); error = complete_walk(nd);
if (error) if (error)
return error; return error;
audit_inode(pathname, nd->path.dentry); audit_inode(name, nd->path.dentry, 0);
if (open_flag & O_CREAT) { if (open_flag & O_CREAT) {
error = -EISDIR; error = -EISDIR;
goto out; goto out;
...@@ -2662,7 +2727,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2662,7 +2727,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = complete_walk(nd); error = complete_walk(nd);
if (error) if (error)
return error; return error;
audit_inode(pathname, dir); audit_inode(name, dir, 0);
goto finish_open; goto finish_open;
} }
...@@ -2691,7 +2756,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2691,7 +2756,7 @@ static int do_last(struct nameidata *nd, struct path *path,
if (error) if (error)
return error; return error;
audit_inode(pathname, dir); audit_inode(name, dir, 0);
error = -EISDIR; error = -EISDIR;
/* trailing slashes? */ /* trailing slashes? */
if (nd->last.name[nd->last.len]) if (nd->last.name[nd->last.len])
...@@ -2721,7 +2786,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2721,7 +2786,7 @@ static int do_last(struct nameidata *nd, struct path *path,
!S_ISREG(file->f_path.dentry->d_inode->i_mode)) !S_ISREG(file->f_path.dentry->d_inode->i_mode))
will_truncate = false; will_truncate = false;
audit_inode(pathname, file->f_path.dentry); audit_inode(name, file->f_path.dentry, 0);
goto opened; goto opened;
} }
...@@ -2738,7 +2803,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2738,7 +2803,7 @@ static int do_last(struct nameidata *nd, struct path *path,
* create/update audit record if it already exists. * create/update audit record if it already exists.
*/ */
if (path->dentry->d_inode) if (path->dentry->d_inode)
audit_inode(pathname, path->dentry); audit_inode(name, path->dentry, 0);
/* /*
* If atomic_open() acquired write access it is dropped now due to * If atomic_open() acquired write access it is dropped now due to
...@@ -2803,7 +2868,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2803,7 +2868,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = -ENOTDIR; error = -ENOTDIR;
if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup) if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
goto out; goto out;
audit_inode(pathname, nd->path.dentry); audit_inode(name, nd->path.dentry, 0);
finish_open: finish_open:
if (!S_ISREG(nd->inode->i_mode)) if (!S_ISREG(nd->inode->i_mode))
will_truncate = false; will_truncate = false;
...@@ -2871,7 +2936,7 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -2871,7 +2936,7 @@ static int do_last(struct nameidata *nd, struct path *path,
goto retry_lookup; goto retry_lookup;
} }
static struct file *path_openat(int dfd, const char *pathname, static struct file *path_openat(int dfd, struct filename *pathname,
struct nameidata *nd, const struct open_flags *op, int flags) struct nameidata *nd, const struct open_flags *op, int flags)
{ {
struct file *base = NULL; struct file *base = NULL;
...@@ -2886,12 +2951,12 @@ static struct file *path_openat(int dfd, const char *pathname, ...@@ -2886,12 +2951,12 @@ static struct file *path_openat(int dfd, const char *pathname,
file->f_flags = op->open_flag; file->f_flags = op->open_flag;
error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
current->total_link_count = 0; current->total_link_count = 0;
error = link_path_walk(pathname, nd); error = link_path_walk(pathname->name, nd);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
...@@ -2937,7 +3002,7 @@ static struct file *path_openat(int dfd, const char *pathname, ...@@ -2937,7 +3002,7 @@ static struct file *path_openat(int dfd, const char *pathname,
return file; return file;
} }
struct file *do_filp_open(int dfd, const char *pathname, struct file *do_filp_open(int dfd, struct filename *pathname,
const struct open_flags *op, int flags) const struct open_flags *op, int flags)
{ {
struct nameidata nd; struct nameidata nd;
...@@ -2956,6 +3021,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, ...@@ -2956,6 +3021,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
{ {
struct nameidata nd; struct nameidata nd;
struct file *file; struct file *file;
struct filename filename = { .name = name };
nd.root.mnt = mnt; nd.root.mnt = mnt;
nd.root.dentry = dentry; nd.root.dentry = dentry;
...@@ -2965,11 +3031,11 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, ...@@ -2965,11 +3031,11 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN) if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
return ERR_PTR(-ELOOP); return ERR_PTR(-ELOOP);
file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU);
if (unlikely(file == ERR_PTR(-ECHILD))) if (unlikely(file == ERR_PTR(-ECHILD)))
file = path_openat(-1, name, &nd, op, flags); file = path_openat(-1, &filename, &nd, op, flags);
if (unlikely(file == ERR_PTR(-ESTALE))) if (unlikely(file == ERR_PTR(-ESTALE)))
file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL); file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL);
return file; return file;
} }
...@@ -3044,11 +3110,11 @@ EXPORT_SYMBOL(done_path_create); ...@@ -3044,11 +3110,11 @@ EXPORT_SYMBOL(done_path_create);
struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) 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; struct dentry *res;
if (IS_ERR(tmp)) if (IS_ERR(tmp))
return ERR_CAST(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); putname(tmp);
return res; return res;
} }
...@@ -3253,13 +3319,13 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -3253,13 +3319,13 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
static long do_rmdir(int dfd, const char __user *pathname) static long do_rmdir(int dfd, const char __user *pathname)
{ {
int error = 0; int error = 0;
char * name; struct filename *name;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
error = user_path_parent(dfd, pathname, &nd, &name); name = user_path_parent(dfd, pathname, &nd);
if (error) if (IS_ERR(name))
return error; return PTR_ERR(name);
switch(nd.last_type) { switch(nd.last_type) {
case LAST_DOTDOT: case LAST_DOTDOT:
...@@ -3348,14 +3414,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -3348,14 +3414,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
static long do_unlinkat(int dfd, const char __user *pathname) static long do_unlinkat(int dfd, const char __user *pathname)
{ {
int error; int error;
char *name; struct filename *name;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct nameidata nd;
struct inode *inode = NULL; struct inode *inode = NULL;
error = user_path_parent(dfd, pathname, &nd, &name); name = user_path_parent(dfd, pathname, &nd);
if (error) if (IS_ERR(name))
return error; return PTR_ERR(name);
error = -EISDIR; error = -EISDIR;
if (nd.last_type != LAST_NORM) if (nd.last_type != LAST_NORM)
...@@ -3439,7 +3505,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, ...@@ -3439,7 +3505,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
int, newdfd, const char __user *, newname) int, newdfd, const char __user *, newname)
{ {
int error; int error;
char *from; struct filename *from;
struct dentry *dentry; struct dentry *dentry;
struct path path; struct path path;
...@@ -3452,9 +3518,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, ...@@ -3452,9 +3518,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
if (IS_ERR(dentry)) if (IS_ERR(dentry))
goto out_putname; goto out_putname;
error = security_path_symlink(&path, dentry, from); error = security_path_symlink(&path, dentry, from->name);
if (!error) 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); done_path_create(&path, dentry);
out_putname: out_putname:
putname(from); putname(from);
...@@ -3734,17 +3800,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, ...@@ -3734,17 +3800,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
struct dentry *old_dentry, *new_dentry; struct dentry *old_dentry, *new_dentry;
struct dentry *trap; struct dentry *trap;
struct nameidata oldnd, newnd; struct nameidata oldnd, newnd;
char *from; struct filename *from;
char *to; struct filename *to;
int error; int error;
error = user_path_parent(olddfd, oldname, &oldnd, &from); from = user_path_parent(olddfd, oldname, &oldnd);
if (error) if (IS_ERR(from)) {
error = PTR_ERR(from);
goto exit; goto exit;
}
error = user_path_parent(newdfd, newname, &newnd, &to); to = user_path_parent(newdfd, newname, &newnd);
if (error) if (IS_ERR(to)) {
error = PTR_ERR(to);
goto exit1; goto exit1;
}
error = -EXDEV; error = -EXDEV;
if (oldnd.path.mnt != newnd.path.mnt) if (oldnd.path.mnt != newnd.path.mnt)
...@@ -3968,7 +4038,6 @@ EXPORT_SYMBOL(follow_down_one); ...@@ -3968,7 +4038,6 @@ EXPORT_SYMBOL(follow_down_one);
EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(follow_down);
EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(follow_up);
EXPORT_SYMBOL(get_write_access); /* nfsd */ EXPORT_SYMBOL(get_write_access); /* nfsd */
EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(lock_rename); EXPORT_SYMBOL(lock_rename);
EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(lookup_one_len);
EXPORT_SYMBOL(page_follow_link_light); EXPORT_SYMBOL(page_follow_link_light);
......
...@@ -2408,7 +2408,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, ...@@ -2408,7 +2408,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
{ {
int ret; int ret;
char *kernel_type; char *kernel_type;
char *kernel_dir; struct filename *kernel_dir;
char *kernel_dev; char *kernel_dev;
unsigned long data_page; unsigned long data_page;
...@@ -2430,7 +2430,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, ...@@ -2430,7 +2430,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
if (ret < 0) if (ret < 0)
goto out_data; 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); (void *) data_page);
free_page(data_page); free_page(data_page);
......
...@@ -478,7 +478,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) ...@@ -478,7 +478,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)
file = fget(fd); file = fget(fd);
if (file) { if (file) {
audit_inode(NULL, file->f_path.dentry); audit_inode(NULL, file->f_path.dentry, 0);
err = chmod_common(&file->f_path, mode); err = chmod_common(&file->f_path, mode);
fput(file); fput(file);
} }
...@@ -588,7 +588,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) ...@@ -588,7 +588,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
error = mnt_want_write_file(f.file); error = mnt_want_write_file(f.file);
if (error) if (error)
goto out_fput; goto out_fput;
audit_inode(NULL, f.file->f_path.dentry); audit_inode(NULL, f.file->f_path.dentry, 0);
error = chown_common(&f.file->f_path, user, group); error = chown_common(&f.file->f_path, user, group);
mnt_drop_write_file(f.file); mnt_drop_write_file(f.file);
out_fput: out_fput:
...@@ -858,6 +858,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o ...@@ -858,6 +858,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
return lookup_flags; return lookup_flags;
} }
/**
* file_open_name - open file and return file pointer
*
* @name: struct filename containing path to open
* @flags: open flags as per the open(2) second argument
* @mode: mode for the new file if O_CREAT is set, else ignored
*
* This is the helper to open a file from kernelspace if you really
* have to. But in generally you should not do this, so please move
* along, nothing to see here..
*/
struct file *file_open_name(struct filename *name, int flags, umode_t mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
return do_filp_open(AT_FDCWD, name, &op, lookup);
}
/** /**
* filp_open - open file and return file pointer * filp_open - open file and return file pointer
* *
...@@ -871,9 +889,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o ...@@ -871,9 +889,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
*/ */
struct file *filp_open(const char *filename, int flags, umode_t mode) struct file *filp_open(const char *filename, int flags, umode_t mode)
{ {
struct open_flags op; struct filename name = {.name = filename};
int lookup = build_open_flags(flags, mode, &op); return file_open_name(&name, flags, mode);
return do_filp_open(AT_FDCWD, filename, &op, lookup);
} }
EXPORT_SYMBOL(filp_open); EXPORT_SYMBOL(filp_open);
...@@ -895,7 +912,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) ...@@ -895,7 +912,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{ {
struct open_flags op; struct open_flags op;
int lookup = build_open_flags(flags, mode, &op); int lookup = build_open_flags(flags, mode, &op);
char *tmp = getname(filename); struct filename *tmp = getname(filename);
int fd = PTR_ERR(tmp); int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) { if (!IS_ERR(tmp)) {
......
...@@ -2258,7 +2258,8 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) ...@@ -2258,7 +2258,8 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
pid_t tgid = task_tgid_nr_ns(current, ns); pid_t tgid = task_tgid_nr_ns(current, ns);
char *name = ERR_PTR(-ENOENT); char *name = ERR_PTR(-ENOENT);
if (tgid) { if (tgid) {
name = __getname(); /* 11 for max length of signed int in decimal + NULL term */
name = kmalloc(12, GFP_KERNEL);
if (!name) if (!name)
name = ERR_PTR(-ENOMEM); name = ERR_PTR(-ENOMEM);
else else
...@@ -2273,7 +2274,7 @@ static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, ...@@ -2273,7 +2274,7 @@ static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,
{ {
char *s = nd_get_link(nd); char *s = nd_get_link(nd);
if (!IS_ERR(s)) if (!IS_ERR(s))
__putname(s); kfree(s);
} }
static const struct inode_operations proc_self_inode_operations = { static const struct inode_operations proc_self_inode_operations = {
......
...@@ -331,11 +331,11 @@ static struct super_block *quotactl_block(const char __user *special, int cmd) ...@@ -331,11 +331,11 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
struct block_device *bdev; struct block_device *bdev;
struct super_block *sb; struct super_block *sb;
char *tmp = getname(special); struct filename *tmp = getname(special);
if (IS_ERR(tmp)) if (IS_ERR(tmp))
return ERR_CAST(tmp); return ERR_CAST(tmp);
bdev = lookup_bdev(tmp); bdev = lookup_bdev(tmp->name);
putname(tmp); putname(tmp);
if (IS_ERR(bdev)) if (IS_ERR(bdev))
return ERR_CAST(bdev); return ERR_CAST(bdev);
......
...@@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, ...@@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
if (!f.file) if (!f.file)
return error; return error;
dentry = f.file->f_path.dentry; dentry = f.file->f_path.dentry;
audit_inode(NULL, dentry); audit_inode(NULL, dentry, 0);
error = mnt_want_write_file(f.file); error = mnt_want_write_file(f.file);
if (!error) { if (!error) {
error = setxattr(dentry, name, value, size, flags); error = setxattr(dentry, name, value, size, flags);
...@@ -507,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name, ...@@ -507,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
if (!f.file) if (!f.file)
return error; return error;
audit_inode(NULL, f.file->f_path.dentry); audit_inode(NULL, f.file->f_path.dentry, 0);
error = getxattr(f.file->f_path.dentry, name, value, size); error = getxattr(f.file->f_path.dentry, name, value, size);
fdput(f); fdput(f);
return error; return error;
...@@ -586,7 +586,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size) ...@@ -586,7 +586,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
if (!f.file) if (!f.file)
return error; return error;
audit_inode(NULL, f.file->f_path.dentry); audit_inode(NULL, f.file->f_path.dentry, 0);
error = listxattr(f.file->f_path.dentry, list, size); error = listxattr(f.file->f_path.dentry, list, size);
fdput(f); fdput(f);
return error; return error;
...@@ -655,7 +655,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) ...@@ -655,7 +655,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
if (!f.file) if (!f.file)
return error; return error;
dentry = f.file->f_path.dentry; dentry = f.file->f_path.dentry;
audit_inode(NULL, dentry); audit_inode(NULL, dentry, 0);
error = mnt_want_write_file(f.file); error = mnt_want_write_file(f.file);
if (!error) { if (!error) {
error = removexattr(dentry, name); error = removexattr(dentry, name);
......
...@@ -452,6 +452,16 @@ struct audit_field { ...@@ -452,6 +452,16 @@ struct audit_field {
extern int __init audit_register_class(int class, unsigned *list); extern int __init audit_register_class(int class, unsigned *list);
extern int audit_classify_syscall(int abi, unsigned syscall); extern int audit_classify_syscall(int abi, unsigned syscall);
extern int audit_classify_arch(int arch); extern int audit_classify_arch(int arch);
/* audit_names->type values */
#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
#define AUDIT_TYPE_PARENT 2 /* a parent audit record */
#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 #ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */ /* These are defined in auditsc.c */
/* Public API */ /* Public API */
...@@ -461,11 +471,14 @@ extern void __audit_syscall_entry(int arch, ...@@ -461,11 +471,14 @@ extern void __audit_syscall_entry(int arch,
int major, unsigned long a0, unsigned long a1, int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3); unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value); extern void __audit_syscall_exit(int ret_success, long ret_value);
extern void __audit_getname(const char *name); extern struct filename *__audit_reusename(const __user char *uptr);
extern void audit_putname(const char *name); extern void __audit_getname(struct filename *name);
extern void __audit_inode(const char *name, const struct dentry *dentry); extern void audit_putname(struct filename *name);
extern void __audit_inode_child(const struct dentry *dentry, extern void __audit_inode(struct filename *name, const struct dentry *dentry,
const struct inode *parent); unsigned int parent);
extern void __audit_inode_child(const struct inode *parent,
const struct dentry *dentry,
const unsigned char type);
extern void __audit_seccomp(unsigned long syscall, long signr, int code); extern void __audit_seccomp(unsigned long syscall, long signr, int code);
extern void __audit_ptrace(struct task_struct *t); extern void __audit_ptrace(struct task_struct *t);
...@@ -495,19 +508,27 @@ static inline void audit_syscall_exit(void *pt_regs) ...@@ -495,19 +508,27 @@ static inline void audit_syscall_exit(void *pt_regs)
__audit_syscall_exit(success, return_code); __audit_syscall_exit(success, return_code);
} }
} }
static inline void audit_getname(const char *name) static inline struct filename *audit_reusename(const __user char *name)
{
if (unlikely(!audit_dummy_context()))
return __audit_reusename(name);
return NULL;
}
static inline void audit_getname(struct filename *name)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
__audit_getname(name); __audit_getname(name);
} }
static inline void audit_inode(const char *name, const struct dentry *dentry) { static inline void audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int parent) {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
__audit_inode(name, dentry); __audit_inode(name, dentry, parent);
} }
static inline void audit_inode_child(const struct dentry *dentry, static inline void audit_inode_child(const struct inode *parent,
const struct inode *parent) { const struct dentry *dentry,
const unsigned char type) {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
__audit_inode_child(dentry, parent); __audit_inode_child(parent, dentry, type);
} }
void audit_core_dumps(long signr); void audit_core_dumps(long signr);
...@@ -651,19 +672,29 @@ static inline int audit_dummy_context(void) ...@@ -651,19 +672,29 @@ static inline int audit_dummy_context(void)
{ {
return 1; return 1;
} }
static inline void audit_getname(const char *name) static inline struct filename *audit_reusename(const __user char *name)
{
return NULL;
}
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) static inline void __audit_inode(struct filename *name,
const struct dentry *dentry,
unsigned int parent)
{ } { }
static inline void __audit_inode_child(const struct dentry *dentry, static inline void __audit_inode_child(const struct inode *parent,
const struct inode *parent) const struct dentry *dentry,
const unsigned char type)
{ } { }
static inline void audit_inode(const char *name, const struct dentry *dentry) static inline void audit_inode(struct filename *name,
const struct dentry *dentry,
unsigned int parent)
{ } { }
static inline void audit_inode_child(const struct dentry *dentry, static inline void audit_inode_child(const struct inode *parent,
const struct inode *parent) const struct dentry *dentry,
const unsigned char type)
{ } { }
static inline void audit_core_dumps(long signr) static inline void audit_core_dumps(long signr)
{ } { }
......
...@@ -2196,6 +2196,13 @@ static inline int break_lease(struct inode *inode, unsigned int mode) ...@@ -2196,6 +2196,13 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
#endif /* CONFIG_FILE_LOCKING */ #endif /* CONFIG_FILE_LOCKING */
/* fs/open.c */ /* fs/open.c */
struct audit_names;
struct filename {
const char *name; /* pointer to actual string */
const __user char *uptr; /* original userland pointer */
struct audit_names *aname;
bool separate; /* should "name" be freed? */
};
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp); struct file *filp);
...@@ -2203,12 +2210,15 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, ...@@ -2203,12 +2210,15 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset,
loff_t len); loff_t len);
extern long do_sys_open(int dfd, const char __user *filename, int flags, extern long do_sys_open(int dfd, const char __user *filename, int flags,
umode_t mode); umode_t mode);
extern struct file *file_open_name(struct filename *, int, umode_t);
extern struct file *filp_open(const char *, int, umode_t); extern struct file *filp_open(const char *, int, umode_t);
extern struct file *file_open_root(struct dentry *, struct vfsmount *, extern struct file *file_open_root(struct dentry *, struct vfsmount *,
const char *, int); const char *, int);
extern struct file * dentry_open(const struct path *, int, const struct cred *); extern struct file * dentry_open(const struct path *, int, const struct cred *);
extern int filp_close(struct file *, fl_owner_t id); extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char __user *);
extern struct filename *getname(const char __user *);
enum { enum {
FILE_CREATED = 1, FILE_CREATED = 1,
FILE_OPENED = 2 FILE_OPENED = 2
...@@ -2228,13 +2238,14 @@ extern void __init vfs_caches_init(unsigned long); ...@@ -2228,13 +2238,14 @@ extern void __init vfs_caches_init(unsigned long);
extern struct kmem_cache *names_cachep; extern struct kmem_cache *names_cachep;
#define __getname_gfp(gfp) kmem_cache_alloc(names_cachep, (gfp)) extern void final_putname(struct filename *name);
#define __getname() __getname_gfp(GFP_KERNEL)
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) #define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
#ifndef CONFIG_AUDITSYSCALL #ifndef CONFIG_AUDITSYSCALL
#define putname(name) __putname(name) #define putname(name) final_putname(name)
#else #else
extern void putname(const char *name); extern void putname(struct filename *name);
#endif #endif
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
......
...@@ -109,7 +109,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, ...@@ -109,7 +109,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
if (source) if (source)
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
audit_inode_child(moved, new_dir); audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE);
} }
/* /*
...@@ -155,7 +155,7 @@ static inline void fsnotify_inoderemove(struct inode *inode) ...@@ -155,7 +155,7 @@ static inline void fsnotify_inoderemove(struct inode *inode)
*/ */
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{ {
audit_inode_child(dentry, inode); audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
} }
...@@ -168,7 +168,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) ...@@ -168,7 +168,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
{ {
fsnotify_link_count(inode); fsnotify_link_count(inode);
audit_inode_child(new_dentry, dir); audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0); fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
} }
...@@ -181,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) ...@@ -181,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
__u32 mask = (FS_CREATE | FS_ISDIR); __u32 mask = (FS_CREATE | FS_ISDIR);
struct inode *d_inode = dentry->d_inode; struct inode *d_inode = dentry->d_inode;
audit_inode_child(dentry, inode); audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
} }
......
...@@ -353,8 +353,9 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) ...@@ -353,8 +353,9 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
void __init mount_block_root(char *name, int flags) void __init mount_block_root(char *name, int flags)
{ {
char *fs_names = __getname_gfp(GFP_KERNEL struct page *page = alloc_page(GFP_KERNEL |
| __GFP_NOTRACK_FALSE_POSITIVE); __GFP_NOTRACK_FALSE_POSITIVE);
char *fs_names = page_address(page);
char *p; char *p;
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
char b[BDEVNAME_SIZE]; char b[BDEVNAME_SIZE];
...@@ -406,7 +407,7 @@ void __init mount_block_root(char *name, int flags) ...@@ -406,7 +407,7 @@ void __init mount_block_root(char *name, int flags)
#endif #endif
panic("VFS: Unable to mount root fs on %s", b); panic("VFS: Unable to mount root fs on %s", b);
out: out:
putname(fs_names); put_page(page);
} }
#ifdef CONFIG_ROOT_NFS #ifdef CONFIG_ROOT_NFS
......
...@@ -772,7 +772,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -772,7 +772,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
{ {
struct path path; struct path path;
struct file *filp; struct file *filp;
char *name; struct filename *name;
struct mq_attr attr; struct mq_attr attr;
int fd, error; int fd, error;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
...@@ -795,7 +795,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -795,7 +795,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
ro = mnt_want_write(mnt); /* we'll drop it in any case */ ro = mnt_want_write(mnt); /* we'll drop it in any case */
error = 0; error = 0;
mutex_lock(&root->d_inode->i_mutex); 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)) { if (IS_ERR(path.dentry)) {
error = PTR_ERR(path.dentry); error = PTR_ERR(path.dentry);
goto out_putfd; goto out_putfd;
...@@ -804,7 +804,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -804,7 +804,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
if (oflag & O_CREAT) { if (oflag & O_CREAT) {
if (path.dentry->d_inode) { /* entry already exists */ if (path.dentry->d_inode) { /* entry already exists */
audit_inode(name, path.dentry); audit_inode(name, path.dentry, 0);
if (oflag & O_EXCL) { if (oflag & O_EXCL) {
error = -EEXIST; error = -EEXIST;
goto out; goto out;
...@@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
error = -ENOENT; error = -ENOENT;
goto out; goto out;
} }
audit_inode(name, path.dentry); audit_inode(name, path.dentry, 0);
filp = do_open(&path, oflag); filp = do_open(&path, oflag);
} }
...@@ -849,7 +849,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -849,7 +849,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{ {
int err; int err;
char *name; struct filename *name;
struct dentry *dentry; struct dentry *dentry;
struct inode *inode = NULL; struct inode *inode = NULL;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
...@@ -863,7 +863,8 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) ...@@ -863,7 +863,8 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
if (err) if (err)
goto out_name; goto out_name;
mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT); 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)) { if (IS_ERR(dentry)) {
err = PTR_ERR(dentry); err = PTR_ERR(dentry);
goto out_unlock; goto out_unlock;
...@@ -978,7 +979,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, ...@@ -978,7 +979,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
goto out_fput; goto out_fput;
} }
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
audit_inode(NULL, f.file->f_path.dentry); audit_inode(NULL, f.file->f_path.dentry, 0);
if (unlikely(!(f.file->f_mode & FMODE_WRITE))) { if (unlikely(!(f.file->f_mode & FMODE_WRITE))) {
ret = -EBADF; ret = -EBADF;
...@@ -1094,7 +1095,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, ...@@ -1094,7 +1095,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
goto out_fput; goto out_fput;
} }
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
audit_inode(NULL, f.file->f_path.dentry); audit_inode(NULL, f.file->f_path.dentry, 0);
if (unlikely(!(f.file->f_mode & FMODE_READ))) { if (unlikely(!(f.file->f_mode & FMODE_READ))) {
ret = -EBADF; ret = -EBADF;
......
...@@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file, ...@@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
} }
} }
static int acct_on(char *name) static int acct_on(struct filename *pathname)
{ {
struct file *file; struct file *file;
struct vfsmount *mnt; struct vfsmount *mnt;
...@@ -201,7 +201,7 @@ static int acct_on(char *name) ...@@ -201,7 +201,7 @@ static int acct_on(char *name)
struct bsd_acct_struct *acct = NULL; struct bsd_acct_struct *acct = NULL;
/* Difference from BSD - they don't do O_APPEND */ /* Difference from BSD - they don't do O_APPEND */
file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); file = file_open_name(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
if (IS_ERR(file)) if (IS_ERR(file))
return PTR_ERR(file); return PTR_ERR(file);
...@@ -260,7 +260,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name) ...@@ -260,7 +260,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
return -EPERM; return -EPERM;
if (name) { if (name) {
char *tmp = getname(name); struct filename *tmp = getname(name);
if (IS_ERR(tmp)) if (IS_ERR(tmp))
return (PTR_ERR(tmp)); return (PTR_ERR(tmp));
error = acct_on(tmp); error = acct_on(tmp);
......
...@@ -74,12 +74,15 @@ static inline int audit_hash_ino(u32 ino) ...@@ -74,12 +74,15 @@ static inline int audit_hash_ino(u32 ino)
return (ino & (AUDIT_INODE_BUCKETS-1)); return (ino & (AUDIT_INODE_BUCKETS-1));
} }
/* Indicates that audit should log the full pathname. */
#define AUDIT_NAME_FULL -1
extern int audit_match_class(int class, unsigned syscall); extern int audit_match_class(int class, unsigned syscall);
extern int audit_comparator(const u32 left, const u32 op, const u32 right); extern int audit_comparator(const u32 left, const u32 op, const u32 right);
extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);
extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right);
extern int audit_compare_dname_path(const char *dname, const char *path, extern int parent_len(const char *path);
int *dirlen); extern int audit_compare_dname_path(const char *dname, const char *path, int plen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type, extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
int done, int multi, int done, int multi,
const void *payload, int size); const void *payload, int size);
......
...@@ -265,7 +265,8 @@ static void audit_update_watch(struct audit_parent *parent, ...@@ -265,7 +265,8 @@ static void audit_update_watch(struct audit_parent *parent,
/* Run all of the watches on this parent looking for the one that /* Run all of the watches on this parent looking for the one that
* matches the given dname */ * matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
if (audit_compare_dname_path(dname, owatch->path, NULL)) if (audit_compare_dname_path(dname, owatch->path,
AUDIT_NAME_FULL))
continue; continue;
/* If the update involves invalidating rules, do the inode-based /* If the update involves invalidating rules, do the inode-based
......
...@@ -1298,41 +1298,60 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right) ...@@ -1298,41 +1298,60 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)
} }
} }
/* Compare given dentry name with last component in given path, /**
* return of 0 indicates a match. */ * parent_len - find the length of the parent portion of a pathname
int audit_compare_dname_path(const char *dname, const char *path, * @path: pathname of which to determine length
int *dirlen) */
int parent_len(const char *path)
{ {
int dlen, plen; int plen;
const char *p; const char *p;
if (!dname || !path)
return 1;
dlen = strlen(dname);
plen = strlen(path); plen = strlen(path);
if (plen < dlen)
return 1; if (plen == 0)
return plen;
/* disregard trailing slashes */ /* disregard trailing slashes */
p = path + plen - 1; p = path + plen - 1;
while ((*p == '/') && (p > path)) while ((*p == '/') && (p > path))
p--; p--;
/* find last path component */ /* walk backward until we find the next slash or hit beginning */
p = p - dlen + 1; while ((*p != '/') && (p > path))
if (p < path) p--;
/* did we find a slash? Then increment to include it in path */
if (*p == '/')
p++;
return p - path;
}
/**
* audit_compare_dname_path - compare given dentry name with last component in
* given path. Return of 0 indicates a match.
* @dname: dentry name that we're comparing
* @path: full pathname that we're comparing
* @parentlen: length of the parent if known. Passing in AUDIT_NAME_FULL
* here indicates that we must compute this value.
*/
int audit_compare_dname_path(const char *dname, const char *path, int parentlen)
{
int dlen, pathlen;
const char *p;
dlen = strlen(dname);
pathlen = strlen(path);
if (pathlen < dlen)
return 1; return 1;
else if (p > path) {
if (*--p != '/')
return 1;
else
p++;
}
/* return length of path's directory component */ parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
if (dirlen) if (pathlen - parentlen != dlen)
*dirlen = p - path; return 1;
p = path + parentlen;
return strncmp(p, dname, dlen); return strncmp(p, dname, dlen);
} }
......
...@@ -81,9 +81,6 @@ ...@@ -81,9 +81,6 @@
* a name dynamically and also add those to the list anchored by names_list. */ * a name dynamically and also add those to the list anchored by names_list. */
#define AUDIT_NAMES 5 #define AUDIT_NAMES 5
/* Indicates that audit should log the full pathname. */
#define AUDIT_NAME_FULL -1
/* no execve audit message should be longer than this (userspace limits) */ /* no execve audit message should be longer than this (userspace limits) */
#define MAX_EXECVE_AUDIT_LEN 7500 #define MAX_EXECVE_AUDIT_LEN 7500
...@@ -106,27 +103,29 @@ struct audit_cap_data { ...@@ -106,27 +103,29 @@ struct audit_cap_data {
* we don't let putname() free it (instead we free all of the saved * we don't let putname() free it (instead we free all of the saved
* pointers at syscall exit time). * 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 audit_names {
struct list_head list; /* audit_context->names_list */ struct list_head list; /* audit_context->names_list */
const char *name; struct filename *name;
unsigned long ino; unsigned long ino;
dev_t dev; dev_t dev;
umode_t mode; umode_t mode;
kuid_t uid; kuid_t uid;
kgid_t gid; kgid_t gid;
dev_t rdev; dev_t rdev;
u32 osid; u32 osid;
struct audit_cap_data fcap; struct audit_cap_data fcap;
unsigned int fcap_ver; unsigned int fcap_ver;
int name_len; /* number of name's characters to log */ int name_len; /* number of name's characters to log */
bool name_put; /* call __putname() for this name */ 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 * This was an allocated audit_names and not from the array of
* names allocated in the task audit context. Thus this name * names allocated in the task audit context. Thus this name
* should be freed on syscall exit * should be freed on syscall exit
*/ */
bool should_free; bool should_free;
}; };
struct audit_aux_data { struct audit_aux_data {
...@@ -998,7 +997,7 @@ static inline void audit_free_names(struct audit_context *context) ...@@ -998,7 +997,7 @@ static inline void audit_free_names(struct audit_context *context)
context->ino_count); context->ino_count);
list_for_each_entry(n, &context->names_list, list) { list_for_each_entry(n, &context->names_list, list) {
printk(KERN_ERR "names[%d] = %p = %s\n", i, printk(KERN_ERR "names[%d] = %p = %s\n", i,
n->name, n->name ?: "(null)"); n->name, n->name->name ?: "(null)");
} }
dump_stack(); dump_stack();
return; return;
...@@ -1555,7 +1554,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, ...@@ -1555,7 +1554,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
case AUDIT_NAME_FULL: case AUDIT_NAME_FULL:
/* log the full path */ /* log the full path */
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, n->name); audit_log_untrustedstring(ab, n->name->name);
break; break;
case 0: case 0:
/* name was specified as a relative path and the /* name was specified as a relative path and the
...@@ -1565,7 +1564,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, ...@@ -1565,7 +1564,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
default: default:
/* log the name's directory component */ /* log the name's directory component */
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
audit_log_n_untrustedstring(ab, n->name, audit_log_n_untrustedstring(ab, n->name->name,
n->name_len); n->name_len);
} }
} else } else
...@@ -1995,7 +1994,8 @@ static void handle_path(const struct dentry *dentry) ...@@ -1995,7 +1994,8 @@ static void handle_path(const struct dentry *dentry)
#endif #endif
} }
static struct audit_names *audit_alloc_name(struct audit_context *context) static struct audit_names *audit_alloc_name(struct audit_context *context,
unsigned char type)
{ {
struct audit_names *aname; struct audit_names *aname;
...@@ -2010,6 +2010,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context) ...@@ -2010,6 +2010,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
} }
aname->ino = (unsigned long)-1; aname->ino = (unsigned long)-1;
aname->type = type;
list_add_tail(&aname->list, &context->names_list); list_add_tail(&aname->list, &context->names_list);
context->name_count++; context->name_count++;
...@@ -2019,6 +2020,29 @@ static struct audit_names *audit_alloc_name(struct audit_context *context) ...@@ -2019,6 +2020,29 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
return aname; return aname;
} }
/**
* audit_reusename - fill out filename with info from existing entry
* @uptr: userland ptr to pathname
*
* Search the audit_names list for the current audit context. If there is an
* existing entry with a matching "uptr" then return the filename
* associated with that audit_name. If not, return NULL.
*/
struct filename *
__audit_reusename(const __user char *uptr)
{
struct audit_context *context = current->audit_context;
struct audit_names *n;
list_for_each_entry(n, &context->names_list, list) {
if (!n->name)
continue;
if (n->name->uptr == uptr)
return n->name;
}
return NULL;
}
/** /**
* audit_getname - add a name to the list * audit_getname - add a name to the list
* @name: name to add * @name: name to add
...@@ -2026,7 +2050,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context) ...@@ -2026,7 +2050,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
* Add a name to the list of audit names for this context. * Add a name to the list of audit names for this context.
* Called from fs/namei.c:getname(). * 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_context *context = current->audit_context;
struct audit_names *n; struct audit_names *n;
...@@ -2040,13 +2064,19 @@ void __audit_getname(const char *name) ...@@ -2040,13 +2064,19 @@ void __audit_getname(const char *name)
return; return;
} }
n = audit_alloc_name(context); #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) if (!n)
return; return;
n->name = name; n->name = name;
n->name_len = AUDIT_NAME_FULL; n->name_len = AUDIT_NAME_FULL;
n->name_put = true; n->name_put = true;
name->aname = n;
if (!context->pwd.dentry) if (!context->pwd.dentry)
get_fs_pwd(current->fs, &context->pwd); get_fs_pwd(current->fs, &context->pwd);
...@@ -2059,7 +2089,7 @@ void __audit_getname(const char *name) ...@@ -2059,7 +2089,7 @@ void __audit_getname(const char *name)
* then we delay the putname until syscall exit. * then we delay the putname until syscall exit.
* Called from include/linux/fs.h:putname(). * 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; struct audit_context *context = current->audit_context;
...@@ -2074,7 +2104,7 @@ void audit_putname(const char *name) ...@@ -2074,7 +2104,7 @@ void audit_putname(const char *name)
list_for_each_entry(n, &context->names_list, list) list_for_each_entry(n, &context->names_list, list)
printk(KERN_ERR "name[%d] = %p = %s\n", i, printk(KERN_ERR "name[%d] = %p = %s\n", i,
n->name, n->name ?: "(null)"); n->name, n->name->name ?: "(null)");
} }
#endif #endif
__putname(name); __putname(name);
...@@ -2088,8 +2118,8 @@ void audit_putname(const char *name) ...@@ -2088,8 +2118,8 @@ void audit_putname(const char *name)
" put_count=%d\n", " put_count=%d\n",
__FILE__, __LINE__, __FILE__, __LINE__,
context->serial, context->major, context->serial, context->major,
context->in_syscall, name, context->name_count, context->in_syscall, name->name,
context->put_count); context->name_count, context->put_count);
dump_stack(); dump_stack();
} }
} }
...@@ -2132,13 +2162,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent ...@@ -2132,13 +2162,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
} }
/** /**
* audit_inode - store the inode and device from a lookup * __audit_inode - store the inode and device from a lookup
* @name: name being audited * @name: name being audited
* @dentry: dentry being audited * @dentry: dentry being audited
* * @parent: does this dentry represent the parent?
* Called from fs/namei.c:path_lookup().
*/ */
void __audit_inode(const char *name, const struct dentry *dentry) void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int parent)
{ {
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
const struct inode *inode = dentry->d_inode; const struct inode *inode = dentry->d_inode;
...@@ -2147,24 +2177,69 @@ void __audit_inode(const char *name, const struct dentry *dentry) ...@@ -2147,24 +2177,69 @@ void __audit_inode(const char *name, const struct dentry *dentry)
if (!context->in_syscall) if (!context->in_syscall)
return; return;
if (!name)
goto out_alloc;
#if AUDIT_DEBUG
/* The struct filename _must_ have a populated ->name */
BUG_ON(!name->name);
#endif
/*
* If we have a pointer to an audit_names entry already, then we can
* just use it directly if the type is correct.
*/
n = name->aname;
if (n) {
if (parent) {
if (n->type == AUDIT_TYPE_PARENT ||
n->type == AUDIT_TYPE_UNKNOWN)
goto out;
} else {
if (n->type != AUDIT_TYPE_PARENT)
goto out;
}
}
list_for_each_entry_reverse(n, &context->names_list, list) { list_for_each_entry_reverse(n, &context->names_list, list) {
if (n->name && (n->name == name)) /* does the name pointer match? */
goto out; if (!n->name || n->name->name != name->name)
continue;
/* match the correct record type */
if (parent) {
if (n->type == AUDIT_TYPE_PARENT ||
n->type == AUDIT_TYPE_UNKNOWN)
goto out;
} else {
if (n->type != AUDIT_TYPE_PARENT)
goto out;
}
} }
/* unable to find the name from a previous getname() */ out_alloc:
n = audit_alloc_name(context); /* unable to find the name from a previous getname(). Allocate a new
* anonymous entry.
*/
n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
if (!n) if (!n)
return; return;
out: out:
if (parent) {
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;
n->type = AUDIT_TYPE_NORMAL;
}
handle_path(dentry); handle_path(dentry);
audit_copy_inode(n, dentry, inode); audit_copy_inode(n, dentry, inode);
} }
/** /**
* audit_inode_child - collect inode info for created/removed objects * __audit_inode_child - collect inode info for created/removed objects
* @dentry: dentry being audited
* @parent: inode of dentry parent * @parent: inode of dentry parent
* @dentry: dentry being audited
* @type: AUDIT_TYPE_* value that we're looking for
* *
* For syscalls that create or remove filesystem objects, audit_inode * For syscalls that create or remove filesystem objects, audit_inode
* can only collect information for the filesystem object's parent. * can only collect information for the filesystem object's parent.
...@@ -2174,15 +2249,14 @@ void __audit_inode(const char *name, const struct dentry *dentry) ...@@ -2174,15 +2249,14 @@ void __audit_inode(const char *name, const struct dentry *dentry)
* must be hooked prior, in order to capture the target inode during * must be hooked prior, in order to capture the target inode during
* unsuccessful attempts. * unsuccessful attempts.
*/ */
void __audit_inode_child(const struct dentry *dentry, void __audit_inode_child(const struct inode *parent,
const struct inode *parent) const struct dentry *dentry,
const unsigned char type)
{ {
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
const char *found_parent = NULL, *found_child = NULL;
const struct inode *inode = dentry->d_inode; const struct inode *inode = dentry->d_inode;
const char *dname = dentry->d_name.name; const char *dname = dentry->d_name.name;
struct audit_names *n; struct audit_names *n, *found_parent = NULL, *found_child = NULL;
int dirlen = 0;
if (!context->in_syscall) if (!context->in_syscall)
return; return;
...@@ -2190,62 +2264,65 @@ void __audit_inode_child(const struct dentry *dentry, ...@@ -2190,62 +2264,65 @@ void __audit_inode_child(const struct dentry *dentry,
if (inode) if (inode)
handle_one(inode); handle_one(inode);
/* parent is more likely, look for it first */ /* look for a parent entry first */
list_for_each_entry(n, &context->names_list, list) { list_for_each_entry(n, &context->names_list, list) {
if (!n->name) if (!n->name || n->type != AUDIT_TYPE_PARENT)
continue; continue;
if (n->ino == parent->i_ino && if (n->ino == parent->i_ino &&
!audit_compare_dname_path(dname, n->name, &dirlen)) { !audit_compare_dname_path(dname, n->name->name, n->name_len)) {
n->name_len = dirlen; /* update parent data in place */ found_parent = n;
found_parent = n->name; break;
goto add_names;
} }
} }
/* no matching parent, look for matching child */ /* is there a matching child entry? */
list_for_each_entry(n, &context->names_list, list) { list_for_each_entry(n, &context->names_list, list) {
if (!n->name) /* can only match entries that have a name */
if (!n->name || n->type != type)
continue; continue;
/* strcmp() is the more likely scenario */ /* if we found a parent, make sure this one is a child of it */
if (!strcmp(dname, n->name) || if (found_parent && (n->name != found_parent->name))
!audit_compare_dname_path(dname, n->name, &dirlen)) { continue;
if (inode)
audit_copy_inode(n, NULL, inode); if (!strcmp(dname, n->name->name) ||
else !audit_compare_dname_path(dname, n->name->name,
n->ino = (unsigned long)-1; found_parent ?
found_child = n->name; found_parent->name_len :
goto add_names; AUDIT_NAME_FULL)) {
found_child = n;
break;
} }
} }
add_names:
if (!found_parent) { if (!found_parent) {
n = audit_alloc_name(context); /* create a new, "anonymous" parent record */
n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
if (!n) if (!n)
return; return;
audit_copy_inode(n, NULL, parent); audit_copy_inode(n, NULL, parent);
} }
if (!found_child) { if (!found_child) {
n = audit_alloc_name(context); found_child = audit_alloc_name(context, type);
if (!n) if (!found_child)
return; return;
/* Re-use the name belonging to the slot for a matching parent /* Re-use the name belonging to the slot for a matching parent
* directory. All names for this context are relinquished in * directory. All names for this context are relinquished in
* audit_free_names() */ * audit_free_names() */
if (found_parent) { if (found_parent) {
n->name = found_parent; found_child->name = found_parent->name;
n->name_len = AUDIT_NAME_FULL; found_child->name_len = AUDIT_NAME_FULL;
/* don't call __putname() */ /* don't call __putname() */
n->name_put = false; found_child->name_put = false;
} }
if (inode)
audit_copy_inode(n, NULL, inode);
} }
if (inode)
audit_copy_inode(found_child, dentry, inode);
else
found_child->ino = (unsigned long)-1;
} }
EXPORT_SYMBOL_GPL(__audit_inode_child); EXPORT_SYMBOL_GPL(__audit_inode_child);
......
...@@ -1483,7 +1483,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) ...@@ -1483,7 +1483,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
struct file *swap_file, *victim; struct file *swap_file, *victim;
struct address_space *mapping; struct address_space *mapping;
struct inode *inode; struct inode *inode;
char *pathname; struct filename *pathname;
int oom_score_adj; int oom_score_adj;
int i, type, prev; int i, type, prev;
int err; int err;
...@@ -1498,8 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) ...@@ -1498,8 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
if (IS_ERR(pathname)) if (IS_ERR(pathname))
goto out; goto out;
victim = filp_open(pathname, O_RDWR|O_LARGEFILE, 0); victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0);
putname(pathname);
err = PTR_ERR(victim); err = PTR_ERR(victim);
if (IS_ERR(victim)) if (IS_ERR(victim))
goto out; goto out;
...@@ -1936,7 +1935,7 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, ...@@ -1936,7 +1935,7 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
{ {
struct swap_info_struct *p; struct swap_info_struct *p;
char *name; struct filename *name;
struct file *swap_file = NULL; struct file *swap_file = NULL;
struct address_space *mapping; struct address_space *mapping;
int i; int i;
...@@ -1967,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) ...@@ -1967,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
name = NULL; name = NULL;
goto bad_swap; goto bad_swap;
} }
swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0); swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0);
if (IS_ERR(swap_file)) { if (IS_ERR(swap_file)) {
error = PTR_ERR(swap_file); error = PTR_ERR(swap_file);
swap_file = NULL; swap_file = NULL;
...@@ -2053,7 +2052,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) ...@@ -2053,7 +2052,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
printk(KERN_INFO "Adding %uk swap on %s. " printk(KERN_INFO "Adding %uk swap on %s. "
"Priority:%d extents:%d across:%lluk %s%s%s\n", "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), nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
(p->flags & SWP_SOLIDSTATE) ? "SS" : "", (p->flags & SWP_SOLIDSTATE) ? "SS" : "",
(p->flags & SWP_DISCARDABLE) ? "D" : "", (p->flags & SWP_DISCARDABLE) ? "D" : "",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册