From 91a27b2a756784714e924e5e854b919273082d26 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 10 Oct 2012 15:25:28 -0400 Subject: vfs: define struct filename and have getname() return it getname() is intended to copy pathname strings from userspace into a kernel buffer. The result is just a string in kernel space. It would however be quite helpful to be able to attach some ancillary info to the string. For instance, we could attach some audit-related info to reduce the amount of audit-related processing needed. When auditing is enabled, we could also call getname() on the string more than once and not need to recopy it from userspace. This patchset converts the getname()/putname() interfaces to return a struct instead of a string. For now, the struct just tracks the string in kernel space and the original userland pointer for it. Later, we'll add other information to the struct as it becomes convenient. Signed-off-by: Jeff Layton Signed-off-by: Al Viro --- mm/swapfile.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'mm') diff --git a/mm/swapfile.c b/mm/swapfile.c index 14e254c768fc..90d2ed591de9 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1483,7 +1483,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) struct file *swap_file, *victim; struct address_space *mapping; struct inode *inode; - char *pathname; + struct filename *pathname; int oom_score_adj; int i, type, prev; int err; @@ -1498,8 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(pathname)) goto out; - victim = filp_open(pathname, O_RDWR|O_LARGEFILE, 0); - putname(pathname); + victim = filp_open(pathname->name, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); if (IS_ERR(victim)) goto out; @@ -1936,7 +1935,7 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; - char *name; + struct filename *name; struct file *swap_file = NULL; struct address_space *mapping; int i; @@ -1967,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) name = NULL; goto bad_swap; } - swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0); + swap_file = filp_open(name->name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(swap_file)) { error = PTR_ERR(swap_file); swap_file = NULL; @@ -2053,7 +2052,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) printk(KERN_INFO "Adding %uk swap on %s. " "Priority:%d extents:%d across:%lluk %s%s%s\n", - p->pages<<(PAGE_SHIFT-10), name, p->prio, + p->pages<<(PAGE_SHIFT-10), name->name, p->prio, nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), (p->flags & SWP_SOLIDSTATE) ? "SS" : "", (p->flags & SWP_DISCARDABLE) ? "D" : "", -- cgit v1.2.3 From 669abf4e5539c8aa48bf28c965be05c0a7b58a27 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 10 Oct 2012 16:43:10 -0400 Subject: vfs: make path_openat take a struct filename pointer ...and fix up the callers. For do_file_open_root, just declare a struct filename on the stack and fill out the .name field. For do_filp_open, make it also take a struct filename pointer, and fix up its callers to call it appropriately. For filp_open, add a variant that takes a struct filename pointer and turn filp_open into a wrapper around it. Signed-off-by: Jeff Layton Signed-off-by: Al Viro --- fs/exec.c | 5 +++-- fs/internal.h | 4 ++-- fs/namei.c | 18 ++++++++++-------- fs/open.c | 25 +++++++++++++++++++++---- include/linux/fs.h | 1 + kernel/acct.c | 6 +++--- mm/swapfile.c | 4 ++-- 7 files changed, 42 insertions(+), 21 deletions(-) (limited to 'mm') diff --git a/fs/exec.c b/fs/exec.c index 4e591e20e108..8b9011b67041 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -116,7 +116,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) if (IS_ERR(tmp)) goto out; - file = do_filp_open(AT_FDCWD, tmp->name, &uselib_flags, LOOKUP_FOLLOW); + file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW); putname(tmp); error = PTR_ERR(file); if (IS_ERR(file)) @@ -751,13 +751,14 @@ struct file *open_exec(const char *name) { struct file *file; int err; + struct filename tmp = { .name = name }; static const struct open_flags open_exec_flags = { .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, .acc_mode = MAY_EXEC | MAY_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)) goto out; diff --git a/fs/internal.h b/fs/internal.h index 371bcc4b1697..916b7cbf3e3e 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -97,8 +97,8 @@ struct open_flags { int acc_mode; int intent; }; -extern struct file *do_filp_open(int dfd, const char *pathname, - const struct open_flags *op, int lookup_flags); +extern struct file *do_filp_open(int dfd, struct filename *pathname, + const struct open_flags *op, int flags); extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, const char *, const struct open_flags *, int lookup_flags); diff --git a/fs/namei.c b/fs/namei.c index 8c14353fb750..6bbd8fdfb1f5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2662,7 +2662,7 @@ out_dput: */ static int do_last(struct nameidata *nd, struct path *path, struct file *file, const struct open_flags *op, - int *opened, const char *pathname) + int *opened, struct filename *name) { struct dentry *dir = nd->path.dentry; int open_flag = op->open_flag; @@ -2674,6 +2674,7 @@ static int do_last(struct nameidata *nd, struct path *path, struct path save_parent = { .dentry = NULL, .mnt = NULL }; bool retried = false; int error; + const char *pathname = name->name; nd->flags &= ~LOOKUP_PARENT; nd->flags |= op->intent; @@ -2908,7 +2909,7 @@ stale_open: 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 file *base = NULL; @@ -2923,12 +2924,12 @@ static struct file *path_openat(int dfd, const char *pathname, 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)) goto out; current->total_link_count = 0; - error = link_path_walk(pathname, nd); + error = link_path_walk(pathname->name, nd); if (unlikely(error)) goto out; @@ -2974,7 +2975,7 @@ out: 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) { struct nameidata nd; @@ -2993,6 +2994,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, { struct nameidata nd; struct file *file; + struct filename filename = { .name = name }; nd.root.mnt = mnt; nd.root.dentry = dentry; @@ -3002,11 +3004,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) 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))) - file = path_openat(-1, name, &nd, op, flags); + file = path_openat(-1, &filename, &nd, op, flags); 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; } diff --git a/fs/open.c b/fs/open.c index 81dd92ac10ff..59071f55bf7f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -858,6 +858,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o 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 * @@ -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 open_flags op; - int lookup = build_open_flags(flags, mode, &op); - return do_filp_open(AT_FDCWD, filename, &op, lookup); + struct filename name = {.name = filename}; + return file_open_name(&name, flags, mode); } EXPORT_SYMBOL(filp_open); @@ -901,7 +918,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) if (!IS_ERR(tmp)) { fd = get_unused_fd_flags(flags); if (fd >= 0) { - struct file *f = do_filp_open(dfd, tmp->name, &op, lookup); + struct file *f = do_filp_open(dfd, tmp, &op, lookup); if (IS_ERR(f)) { put_unused_fd(fd); fd = PTR_ERR(f); diff --git a/include/linux/fs.h b/include/linux/fs.h index 6c93b46f46dc..b6b10e7f0ac0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2207,6 +2207,7 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len); extern long do_sys_open(int dfd, const char __user *filename, int flags, 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 *file_open_root(struct dentry *, struct vfsmount *, const char *, int); diff --git a/kernel/acct.c b/kernel/acct.c index 08354195eecc..051e071a06e7 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file, } } -static int acct_on(const char *name) +static int acct_on(struct filename *pathname) { struct file *file; struct vfsmount *mnt; @@ -201,7 +201,7 @@ static int acct_on(const char *name) struct bsd_acct_struct *acct = NULL; /* 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)) return PTR_ERR(file); @@ -263,7 +263,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name) struct filename *tmp = getname(name); if (IS_ERR(tmp)) return (PTR_ERR(tmp)); - error = acct_on(tmp->name); + error = acct_on(tmp); putname(tmp); } else { struct bsd_acct_struct *acct; diff --git a/mm/swapfile.c b/mm/swapfile.c index 90d2ed591de9..71cd288b2001 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1498,7 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(pathname)) goto out; - victim = filp_open(pathname->name, O_RDWR|O_LARGEFILE, 0); + victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); if (IS_ERR(victim)) goto out; @@ -1966,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) name = NULL; goto bad_swap; } - swap_file = filp_open(name->name, O_RDWR|O_LARGEFILE, 0); + swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(swap_file)) { error = PTR_ERR(swap_file); swap_file = NULL; -- cgit v1.2.3