Commit 96840aa00a031069a136ec4c55d0bdd09ac6d3a7
Committed by
Linus Torvalds
1 parent
6687a97d40
Exists in
master
and in
4 other branches
[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
mm/util.c
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); |