saner copy_mount_options()
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 21 Jan 2020 00:49:57 +0000 (19:49 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 4 Feb 2020 02:23:33 +0000 (21:23 -0500)
don't bother with the byte-by-byte loops, etc.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namespace.c

index 5e1bf61..85b5f7b 100644 (file)
@@ -2979,39 +2979,10 @@ static void shrink_submounts(struct mount *mnt)
        }
 }
 
-/*
- * Some copy_from_user() implementations do not return the exact number of
- * bytes remaining to copy on a fault.  But copy_mount_options() requires that.
- * Note that this function differs from copy_from_user() in that it will oops
- * on bad values of `to', rather than returning a short copy.
- */
-static long exact_copy_from_user(void *to, const void __user * from,
-                                unsigned long n)
-{
-       char *t = to;
-       const char __user *f = from;
-       char c;
-
-       if (!access_ok(from, n))
-               return n;
-
-       while (n) {
-               if (__get_user(c, f)) {
-                       memset(t, 0, n);
-                       break;
-               }
-               *t++ = c;
-               f++;
-               n--;
-       }
-       return n;
-}
-
 void *copy_mount_options(const void __user * data)
 {
-       int i;
-       unsigned long size;
        char *copy;
+       unsigned size;
 
        if (!data)
                return NULL;
@@ -3020,22 +2991,16 @@ void *copy_mount_options(const void __user * data)
        if (!copy)
                return ERR_PTR(-ENOMEM);
 
-       /* We only care that *some* data at the address the user
-        * gave us is valid.  Just in case, we'll zero
-        * the remainder of the page.
-        */
-       /* copy_from_user cannot cross TASK_SIZE ! */
-       size = TASK_SIZE - (unsigned long)untagged_addr(data);
-       if (size > PAGE_SIZE)
-               size = PAGE_SIZE;
+       size = PAGE_SIZE - offset_in_page(data);
 
-       i = size - exact_copy_from_user(copy, data, size);
-       if (!i) {
+       if (copy_from_user(copy, data, size)) {
                kfree(copy);
                return ERR_PTR(-EFAULT);
        }
-       if (i != PAGE_SIZE)
-               memset(copy + i, 0, PAGE_SIZE - i);
+       if (size != PAGE_SIZE) {
+               if (copy_from_user(copy + size, data + size, PAGE_SIZE - size))
+                       memset(copy + size, 0, PAGE_SIZE - size);
+       }
        return copy;
 }