fortify: Prepare to improve strnlen() and strlen() warnings
[linux-block.git] / include / linux / fortify-string.h
CommitLineData
a28a6e86
FL
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _LINUX_FORTIFY_STRING_H_
3#define _LINUX_FORTIFY_STRING_H_
4
c430f600
KC
5#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))
6#define __RENAME(x) __asm__(#x)
7
8void fortify_panic(const char *name) __noreturn __cold;
9void __read_overflow(void) __compiletime_error("detected read beyond size of object (1st parameter)");
10void __read_overflow2(void) __compiletime_error("detected read beyond size of object (2nd parameter)");
11void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)");
a28a6e86
FL
12
13#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
14extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr);
15extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp);
16extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(memcpy);
17extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(memmove);
18extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(memset);
19extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat);
20extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy);
21extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen);
22extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat);
23extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy);
24#else
25#define __underlying_memchr __builtin_memchr
26#define __underlying_memcmp __builtin_memcmp
27#define __underlying_memcpy __builtin_memcpy
28#define __underlying_memmove __builtin_memmove
29#define __underlying_memset __builtin_memset
30#define __underlying_strcat __builtin_strcat
31#define __underlying_strcpy __builtin_strcpy
32#define __underlying_strlen __builtin_strlen
33#define __underlying_strncat __builtin_strncat
34#define __underlying_strncpy __builtin_strncpy
35#endif
36
37__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)
38{
39 size_t p_size = __builtin_object_size(p, 1);
40
41 if (__builtin_constant_p(size) && p_size < size)
42 __write_overflow();
43 if (p_size < size)
44 fortify_panic(__func__);
45 return __underlying_strncpy(p, q, size);
46}
47
48__FORTIFY_INLINE char *strcat(char *p, const char *q)
49{
50 size_t p_size = __builtin_object_size(p, 1);
51
52 if (p_size == (size_t)-1)
53 return __underlying_strcat(p, q);
54 if (strlcat(p, q, p_size) >= p_size)
55 fortify_panic(__func__);
56 return p;
57}
58
369cd216
KC
59extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
60__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)
61{
62 size_t p_size = __builtin_object_size(p, 1);
63 __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
64
65 if (p_size <= ret && maxlen != ret)
66 fortify_panic(__func__);
67 return ret;
68}
69
a28a6e86
FL
70__FORTIFY_INLINE __kernel_size_t strlen(const char *p)
71{
72 __kernel_size_t ret;
73 size_t p_size = __builtin_object_size(p, 1);
74
75 /* Work around gcc excess stack consumption issue */
76 if (p_size == (size_t)-1 ||
77 (__builtin_constant_p(p[p_size - 1]) && p[p_size - 1] == '\0'))
78 return __underlying_strlen(p);
79 ret = strnlen(p, p_size);
80 if (p_size <= ret)
81 fortify_panic(__func__);
82 return ret;
83}
84
a28a6e86
FL
85/* defined after fortified strlen to reuse it */
86extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);
87__FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)
88{
89 size_t ret;
90 size_t p_size = __builtin_object_size(p, 1);
91 size_t q_size = __builtin_object_size(q, 1);
92
93 if (p_size == (size_t)-1 && q_size == (size_t)-1)
94 return __real_strlcpy(p, q, size);
95 ret = strlen(q);
96 if (size) {
97 size_t len = (ret >= size) ? size - 1 : ret;
98
99 if (__builtin_constant_p(len) && len >= p_size)
100 __write_overflow();
101 if (len >= p_size)
102 fortify_panic(__func__);
103 __underlying_memcpy(p, q, len);
104 p[len] = '\0';
105 }
106 return ret;
107}
108
109/* defined after fortified strnlen to reuse it */
110extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy);
111__FORTIFY_INLINE ssize_t strscpy(char *p, const char *q, size_t size)
112{
113 size_t len;
114 /* Use string size rather than possible enclosing struct size. */
115 size_t p_size = __builtin_object_size(p, 1);
116 size_t q_size = __builtin_object_size(q, 1);
117
118 /* If we cannot get size of p and q default to call strscpy. */
119 if (p_size == (size_t) -1 && q_size == (size_t) -1)
120 return __real_strscpy(p, q, size);
121
122 /*
123 * If size can be known at compile time and is greater than
124 * p_size, generate a compile time write overflow error.
125 */
126 if (__builtin_constant_p(size) && size > p_size)
127 __write_overflow();
128
129 /*
130 * This call protects from read overflow, because len will default to q
131 * length if it smaller than size.
132 */
133 len = strnlen(q, size);
134 /*
135 * If len equals size, we will copy only size bytes which leads to
136 * -E2BIG being returned.
137 * Otherwise we will copy len + 1 because of the final '\O'.
138 */
139 len = len == size ? size : len + 1;
140
141 /*
142 * Generate a runtime write overflow error if len is greater than
143 * p_size.
144 */
145 if (len > p_size)
146 fortify_panic(__func__);
147
148 /*
149 * We can now safely call vanilla strscpy because we are protected from:
150 * 1. Read overflow thanks to call to strnlen().
151 * 2. Write overflow thanks to above ifs.
152 */
153 return __real_strscpy(p, q, len);
154}
155
156/* defined after fortified strlen and strnlen to reuse them */
157__FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count)
158{
159 size_t p_len, copy_len;
160 size_t p_size = __builtin_object_size(p, 1);
161 size_t q_size = __builtin_object_size(q, 1);
162
163 if (p_size == (size_t)-1 && q_size == (size_t)-1)
164 return __underlying_strncat(p, q, count);
165 p_len = strlen(p);
166 copy_len = strnlen(q, count);
167 if (p_size < p_len + copy_len + 1)
168 fortify_panic(__func__);
169 __underlying_memcpy(p + p_len, q, copy_len);
170 p[p_len + copy_len] = '\0';
171 return p;
172}
173
174__FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)
175{
176 size_t p_size = __builtin_object_size(p, 0);
177
178 if (__builtin_constant_p(size) && p_size < size)
179 __write_overflow();
180 if (p_size < size)
181 fortify_panic(__func__);
182 return __underlying_memset(p, c, size);
183}
184
185__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)
186{
187 size_t p_size = __builtin_object_size(p, 0);
188 size_t q_size = __builtin_object_size(q, 0);
189
190 if (__builtin_constant_p(size)) {
191 if (p_size < size)
192 __write_overflow();
193 if (q_size < size)
194 __read_overflow2();
195 }
196 if (p_size < size || q_size < size)
197 fortify_panic(__func__);
198 return __underlying_memcpy(p, q, size);
199}
200
201__FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size)
202{
203 size_t p_size = __builtin_object_size(p, 0);
204 size_t q_size = __builtin_object_size(q, 0);
205
206 if (__builtin_constant_p(size)) {
207 if (p_size < size)
208 __write_overflow();
209 if (q_size < size)
210 __read_overflow2();
211 }
212 if (p_size < size || q_size < size)
213 fortify_panic(__func__);
214 return __underlying_memmove(p, q, size);
215}
216
217extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan);
218__FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size)
219{
220 size_t p_size = __builtin_object_size(p, 0);
221
222 if (__builtin_constant_p(size) && p_size < size)
223 __read_overflow();
224 if (p_size < size)
225 fortify_panic(__func__);
226 return __real_memscan(p, c, size);
227}
228
229__FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size)
230{
231 size_t p_size = __builtin_object_size(p, 0);
232 size_t q_size = __builtin_object_size(q, 0);
233
234 if (__builtin_constant_p(size)) {
235 if (p_size < size)
236 __read_overflow();
237 if (q_size < size)
238 __read_overflow2();
239 }
240 if (p_size < size || q_size < size)
241 fortify_panic(__func__);
242 return __underlying_memcmp(p, q, size);
243}
244
245__FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size)
246{
247 size_t p_size = __builtin_object_size(p, 0);
248
249 if (__builtin_constant_p(size) && p_size < size)
250 __read_overflow();
251 if (p_size < size)
252 fortify_panic(__func__);
253 return __underlying_memchr(p, c, size);
254}
255
256void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv);
257__FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size)
258{
259 size_t p_size = __builtin_object_size(p, 0);
260
261 if (__builtin_constant_p(size) && p_size < size)
262 __read_overflow();
263 if (p_size < size)
264 fortify_panic(__func__);
265 return __real_memchr_inv(p, c, size);
266}
267
268extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kmemdup);
269__FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp)
270{
271 size_t p_size = __builtin_object_size(p, 0);
272
273 if (__builtin_constant_p(size) && p_size < size)
274 __read_overflow();
275 if (p_size < size)
276 fortify_panic(__func__);
277 return __real_kmemdup(p, size, gfp);
278}
279
280/* defined after fortified strlen and memcpy to reuse them */
281__FORTIFY_INLINE char *strcpy(char *p, const char *q)
282{
283 size_t p_size = __builtin_object_size(p, 1);
284 size_t q_size = __builtin_object_size(q, 1);
285 size_t size;
286
287 if (p_size == (size_t)-1 && q_size == (size_t)-1)
288 return __underlying_strcpy(p, q);
289 size = strlen(q) + 1;
072af0c6
KC
290 /* Compile-time check for const size overflow. */
291 if (__builtin_constant_p(size) && p_size < size)
292 __write_overflow();
293 /* Run-time check for dynamic size overflow. */
a28a6e86
FL
294 if (p_size < size)
295 fortify_panic(__func__);
296 memcpy(p, q, size);
297 return p;
298}
299
300/* Don't use these outside the FORITFY_SOURCE implementation */
301#undef __underlying_memchr
302#undef __underlying_memcmp
303#undef __underlying_memcpy
304#undef __underlying_memmove
305#undef __underlying_memset
306#undef __underlying_strcat
307#undef __underlying_strcpy
308#undef __underlying_strlen
309#undef __underlying_strncat
310#undef __underlying_strncpy
311
312#endif /* _LINUX_FORTIFY_STRING_H_ */