From d40ed7391670010db0df2202d770341b2ca82f32 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 6 Dec 2013 13:34:04 -0500 Subject: [PATCH] Linux: stop trying to use getname/putname The current code has afs_putname defined as kmem_cache_free (names_cachep, (void *) name); This is wrong and will cause a double -free when syscall auditing is enabled. Fix it to call putname properly. Instead of that, just create a new afs_getname function that doesn't bother with struct filename at all, and use that unconditionally. Signed-off-by:Jeff Layton Change-Id: I1cd58a7e528abfeb7473cf47ae4cff5b8c8f419c Reviewed-on: http://gerrit.openafs.org/10547 Tested-by: BuildBot Reviewed-by: Jeff Layton Reviewed-by: Derrick Brashear --- acinclude.m4 | 1 - src/afs/LINUX/osi_compat.h | 26 ----------------------- src/afs/LINUX/osi_misc.c | 52 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 12e1210..a77dd94 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -855,7 +855,6 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) AC_CHECK_LINUX_STRUCT([file_operations], [iterate], [fs.h]) AC_CHECK_LINUX_STRUCT([file_operations], [sendfile], [fs.h]) AC_CHECK_LINUX_STRUCT([file_system_type], [mount], [fs.h]) - AC_CHECK_LINUX_STRUCT([filename], [name], [fs.h]) AC_CHECK_LINUX_STRUCT([inode_operations], [truncate], [fs.h]) AC_CHECK_LINUX_STRUCT([key_type], [preparse], [key-type.h]) AC_CHECK_LINUX_STRUCT([key_type], [instantiate_prep], [key-type.h]) diff --git a/src/afs/LINUX/osi_compat.h b/src/afs/LINUX/osi_compat.h index 105a7e9..e9e5076 100644 --- a/src/afs/LINUX/osi_compat.h +++ b/src/afs/LINUX/osi_compat.h @@ -555,32 +555,6 @@ afs_dentry_open(struct dentry *dp, struct vfsmount *mnt, int flags, const struct } #endif -#if !defined(STRUCT_FILENAME_HAS_NAME) -typedef char *afs_name_t; - -static inline char * -afs_name_to_string(afs_name_t s) { - return (char *)s; -} - -static inline void -afs_putname(afs_name_t name) { - putname((char *)name); -} -#else -typedef struct filename *afs_name_t; - -static inline char * -afs_name_to_string(afs_name_t s) { - return (char *)s->name; -} - -static inline void -afs_putname(afs_name_t name) { - kmem_cache_free(names_cachep, (void *)name); -} -#endif - static inline int afs_truncate(struct inode *inode, int len) { diff --git a/src/afs/LINUX/osi_misc.c b/src/afs/LINUX/osi_misc.c index 879f7a1..32ee5a6 100644 --- a/src/afs/LINUX/osi_misc.c +++ b/src/afs/LINUX/osi_misc.c @@ -77,26 +77,53 @@ osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt, return code; } +static char * +afs_getname(char *aname) +{ + int len; + char *name = kmem_cache_alloc(names_cachep, GFP_KERNEL); + + if (!name) + return ERR_PTR(-ENOMEM); + + len = strncpy_from_user(name, aname, PATH_MAX); + if (len < 0) + goto error; + if (len >= PATH_MAX) { + len = -ENAMETOOLONG; + goto error; + } + return name; + +error: + kmem_cache_free(names_cachep, name); + return ERR_PTR(len); +} + +static void +afs_putname(char *name) +{ + kmem_cache_free(names_cachep, name); +} + int osi_lookupname(char *aname, uio_seg_t seg, int followlink, struct dentry **dpp) { int code; - afs_name_t tname = NULL; char *name; code = ENOENT; if (seg == AFS_UIOUSER) { - tname = getname(aname); - if (IS_ERR(tname)) - return PTR_ERR(tname); - name = afs_name_to_string(tname); + name = afs_getname(aname); + if (IS_ERR(name)) + return -PTR_ERR(name); } else { name = aname; } code = osi_lookupname_internal(name, followlink, NULL, dpp); if (seg == AFS_UIOUSER) { - afs_putname(tname); + afs_putname(name); } return code; } @@ -106,15 +133,14 @@ int osi_abspath(char *aname, char *buf, int buflen, { struct dentry *dp = NULL; struct vfsmount *mnt = NULL; - afs_name_t tname; - char *path; + char *name, *path; int code; code = ENOENT; - tname = getname(aname); - if (IS_ERR(tname)) - return -PTR_ERR(tname); - code = osi_lookupname_internal(afs_name_to_string(tname), followlink, &mnt, &dp); + name = afs_getname(aname); + if (IS_ERR(name)) + return -PTR_ERR(name); + code = osi_lookupname_internal(name, followlink, &mnt, &dp); if (!code) { #if defined(D_PATH_TAKES_STRUCT_PATH) afs_linux_path_t p = { mnt, dp }; @@ -133,7 +159,7 @@ int osi_abspath(char *aname, char *buf, int buflen, mntput(mnt); } - afs_putname(tname); + afs_putname(name); return code; } -- 1.9.4