fs: rework getname_kernel to handle up to PATH_MAX sized filenames
authorPaul Moore <pmoore@redhat.com>
Thu, 22 Jan 2015 04:59:56 +0000 (23:59 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 23 Jan 2015 05:22:20 +0000 (00:22 -0500)
In preparation for expanded use in the kernel, make getname_kernel()
more useful by allowing it to handle any legal filename length.

Thanks to Guenter Roeck for his suggestion to substitute memcpy() for
strlcpy().

CC: linux@roeck-us.net
CC: viro@zeniv.linux.org.uk
CC: linux-fsdevel@vger.kernel.org
Signed-off-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namei.c

index 73fcf42..71dc1cc 100644 (file)
@@ -212,32 +212,38 @@ getname(const char __user * filename)
        return getname_flags(filename, 0, NULL);
 }
 
-/*
- * The "getname_kernel()" interface doesn't do pathnames longer
- * than EMBEDDED_NAME_MAX. Deal with it - you're a kernel user.
- */
 struct filename *
 getname_kernel(const char * filename)
 {
        struct filename *result;
-       char *kname;
-       int len;
-
-       len = strlen(filename);
-       if (len >= EMBEDDED_NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
+       int len = strlen(filename) + 1;
 
        result = __getname();
        if (unlikely(!result))
                return ERR_PTR(-ENOMEM);
 
-       kname = (char *)result + sizeof(*result);
-       result->name = kname;
+       if (len <= EMBEDDED_NAME_MAX) {
+               result->name = (char *)(result) + sizeof(*result);
+               result->separate = false;
+       } else if (len <= PATH_MAX) {
+               struct filename *tmp;
+
+               tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+               if (unlikely(!tmp)) {
+                       __putname(result);
+                       return ERR_PTR(-ENOMEM);
+               }
+               tmp->name = (char *)result;
+               tmp->separate = true;
+               result = tmp;
+       } else {
+               __putname(result);
+               return ERR_PTR(-ENAMETOOLONG);
+       }
+       memcpy((char *)result->name, filename, len);
        result->uptr = NULL;
        result->aname = NULL;
-       result->separate = false;
 
-       strlcpy(kname, filename, EMBEDDED_NAME_MAX);
        return result;
 }