Commit 96840aa00a031069a136ec4c55d0bdd09ac6d3a7

Authored by Davi Arnaut
Committed by Linus Torvalds
1 parent 6687a97d40

[PATCH] strndup_user()

This patch series creates a strndup_user() function to easy copying C strings
from userspace.  Also we avoid common pitfalls like userspace modifying the
final \0 after the strlen_user().

Signed-off-by: Davi Arnaut <davi.arnaut@gmail.com>
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 2 changed files with 39 additions and 0 deletions Side-by-side Diff

include/linux/string.h
... ... @@ -18,6 +18,8 @@
18 18 extern __kernel_size_t strspn(const char *,const char *);
19 19 extern __kernel_size_t strcspn(const char *,const char *);
20 20  
  21 +extern char *strndup_user(const char __user *, long);
  22 +
21 23 /*
22 24 * Include machine specific inline routines
23 25 */
1 1 #include <linux/slab.h>
2 2 #include <linux/string.h>
3 3 #include <linux/module.h>
  4 +#include <linux/err.h>
  5 +#include <asm/uaccess.h>
4 6  
5 7 /**
6 8 * kzalloc - allocate memory. The memory is set to zero.
... ... @@ -37,4 +39,39 @@
37 39 return buf;
38 40 }
39 41 EXPORT_SYMBOL(kstrdup);
  42 +
  43 +/*
  44 + * strndup_user - duplicate an existing string from user space
  45 + *
  46 + * @s: The string to duplicate
  47 + * @n: Maximum number of bytes to copy, including the trailing NUL.
  48 + */
  49 +char *strndup_user(const char __user *s, long n)
  50 +{
  51 + char *p;
  52 + long length;
  53 +
  54 + length = strnlen_user(s, n);
  55 +
  56 + if (!length)
  57 + return ERR_PTR(-EFAULT);
  58 +
  59 + if (length > n)
  60 + return ERR_PTR(-EINVAL);
  61 +
  62 + p = kmalloc(length, GFP_KERNEL);
  63 +
  64 + if (!p)
  65 + return ERR_PTR(-ENOMEM);
  66 +
  67 + if (copy_from_user(p, s, length)) {
  68 + kfree(p);
  69 + return ERR_PTR(-EFAULT);
  70 + }
  71 +
  72 + p[length - 1] = '\0';
  73 +
  74 + return p;
  75 +}
  76 +EXPORT_SYMBOL(strndup_user);