netfilter: fix double-free and use-after free
[linux-2.6.git] / mm / util.c
1 #include <linux/slab.h>
2 #include <linux/string.h>
3 #include <linux/module.h>
4 #include <linux/err.h>
5 #include <asm/uaccess.h>
6
7 /**
8  * kstrdup - allocate space for and copy an existing string
9  * @s: the string to duplicate
10  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
11  */
12 char *kstrdup(const char *s, gfp_t gfp)
13 {
14         size_t len;
15         char *buf;
16
17         if (!s)
18                 return NULL;
19
20         len = strlen(s) + 1;
21         buf = kmalloc_track_caller(len, gfp);
22         if (buf)
23                 memcpy(buf, s, len);
24         return buf;
25 }
26 EXPORT_SYMBOL(kstrdup);
27
28 /**
29  * kstrndup - allocate space for and copy an existing string
30  * @s: the string to duplicate
31  * @max: read at most @max chars from @s
32  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
33  */
34 char *kstrndup(const char *s, size_t max, gfp_t gfp)
35 {
36         size_t len;
37         char *buf;
38
39         if (!s)
40                 return NULL;
41
42         len = strnlen(s, max);
43         buf = kmalloc_track_caller(len+1, gfp);
44         if (buf) {
45                 memcpy(buf, s, len);
46                 buf[len] = '\0';
47         }
48         return buf;
49 }
50 EXPORT_SYMBOL(kstrndup);
51
52 /**
53  * kmemdup - duplicate region of memory
54  *
55  * @src: memory region to duplicate
56  * @len: memory region length
57  * @gfp: GFP mask to use
58  */
59 void *kmemdup(const void *src, size_t len, gfp_t gfp)
60 {
61         void *p;
62
63         p = kmalloc_track_caller(len, gfp);
64         if (p)
65                 memcpy(p, src, len);
66         return p;
67 }
68 EXPORT_SYMBOL(kmemdup);
69
70 /**
71  * __krealloc - like krealloc() but don't free @p.
72  * @p: object to reallocate memory for.
73  * @new_size: how many bytes of memory are required.
74  * @flags: the type of memory to allocate.
75  *
76  * This function is like krealloc() except it never frees the originally
77  * allocated buffer. Use this if you don't want to free the buffer immediately
78  * like, for example, with RCU.
79  */
80 void *__krealloc(const void *p, size_t new_size, gfp_t flags)
81 {
82         void *ret;
83         size_t ks = 0;
84
85         if (unlikely(!new_size))
86                 return ZERO_SIZE_PTR;
87
88         if (p)
89                 ks = ksize(p);
90
91         if (ks >= new_size)
92                 return (void *)p;
93
94         ret = kmalloc_track_caller(new_size, flags);
95         if (ret && p)
96                 memcpy(ret, p, ks);
97
98         return ret;
99 }
100 EXPORT_SYMBOL(__krealloc);
101
102 /**
103  * krealloc - reallocate memory. The contents will remain unchanged.
104  * @p: object to reallocate memory for.
105  * @new_size: how many bytes of memory are required.
106  * @flags: the type of memory to allocate.
107  *
108  * The contents of the object pointed to are preserved up to the
109  * lesser of the new and old sizes.  If @p is %NULL, krealloc()
110  * behaves exactly like kmalloc().  If @size is 0 and @p is not a
111  * %NULL pointer, the object pointed to is freed.
112  */
113 void *krealloc(const void *p, size_t new_size, gfp_t flags)
114 {
115         void *ret;
116
117         if (unlikely(!new_size)) {
118                 kfree(p);
119                 return ZERO_SIZE_PTR;
120         }
121
122         ret = __krealloc(p, new_size, flags);
123         if (ret && p != ret)
124                 kfree(p);
125
126         return ret;
127 }
128 EXPORT_SYMBOL(krealloc);
129
130 /*
131  * strndup_user - duplicate an existing string from user space
132  * @s: The string to duplicate
133  * @n: Maximum number of bytes to copy, including the trailing NUL.
134  */
135 char *strndup_user(const char __user *s, long n)
136 {
137         char *p;
138         long length;
139
140         length = strnlen_user(s, n);
141
142         if (!length)
143                 return ERR_PTR(-EFAULT);
144
145         if (length > n)
146                 return ERR_PTR(-EINVAL);
147
148         p = kmalloc(length, GFP_KERNEL);
149
150         if (!p)
151                 return ERR_PTR(-ENOMEM);
152
153         if (copy_from_user(p, s, length)) {
154                 kfree(p);
155                 return ERR_PTR(-EFAULT);
156         }
157
158         p[length - 1] = '\0';
159
160         return p;
161 }
162 EXPORT_SYMBOL(strndup_user);