1 #include <stdarg.h>
2 #ifdef __unix__
3 #include <sys/types.h>
4 #endif
5 
6 extern void abort (void);
7 
8 extern int inside_main;
9 void *chk_fail_buf[256] __attribute__((aligned (16)));
10 volatile int chk_fail_allowed, chk_calls;
11 volatile int memcpy_disallowed, mempcpy_disallowed, memmove_disallowed;
12 volatile int memset_disallowed, strcpy_disallowed, stpcpy_disallowed;
13 volatile int strncpy_disallowed, stpncpy_disallowed, strcat_disallowed;
14 volatile int strncat_disallowed, sprintf_disallowed, vsprintf_disallowed;
15 volatile int snprintf_disallowed, vsnprintf_disallowed;
16 extern __SIZE_TYPE__ strlen (const char *);
17 extern int vsprintf (char *, const char *, va_list);
18 
19 void __attribute__((noreturn))
__chk_fail(void)20 __chk_fail (void)
21 {
22   if (chk_fail_allowed)
23     __builtin_longjmp (chk_fail_buf, 1);
24   abort ();
25 }
26 
27 void *
memcpy(void * dst,const void * src,__SIZE_TYPE__ n)28 memcpy (void *dst, const void *src, __SIZE_TYPE__ n)
29 {
30   const char *srcp;
31   char *dstp;
32 
33 #ifdef __OPTIMIZE__
34   if (memcpy_disallowed && inside_main)
35     abort ();
36 #endif
37 
38   srcp = src;
39   dstp = dst;
40   while (n-- != 0)
41     *dstp++ = *srcp++;
42 
43   return dst;
44 }
45 
46 void *
__memcpy_chk(void * dst,const void * src,__SIZE_TYPE__ n,__SIZE_TYPE__ size)47 __memcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
48 {
49   /* If size is -1, GCC should always optimize the call into memcpy.  */
50   if (size == (__SIZE_TYPE__) -1)
51     abort ();
52   ++chk_calls;
53   if (n > size)
54     __chk_fail ();
55   return memcpy (dst, src, n);
56 }
57 
58 void *
mempcpy(void * dst,const void * src,__SIZE_TYPE__ n)59 mempcpy (void *dst, const void *src, __SIZE_TYPE__ n)
60 {
61   const char *srcp;
62   char *dstp;
63 
64 #ifdef __OPTIMIZE__
65   if (mempcpy_disallowed && inside_main)
66     abort ();
67 #endif
68 
69   srcp = src;
70   dstp = dst;
71   while (n-- != 0)
72     *dstp++ = *srcp++;
73 
74   return dstp;
75 }
76 
77 void *
__mempcpy_chk(void * dst,const void * src,__SIZE_TYPE__ n,__SIZE_TYPE__ size)78 __mempcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
79 {
80   /* If size is -1, GCC should always optimize the call into mempcpy.  */
81   if (size == (__SIZE_TYPE__) -1)
82     abort ();
83   ++chk_calls;
84   if (n > size)
85     __chk_fail ();
86   return mempcpy (dst, src, n);
87 }
88 
89 void *
memmove(void * dst,const void * src,__SIZE_TYPE__ n)90 memmove (void *dst, const void *src, __SIZE_TYPE__ n)
91 {
92   const char *srcp;
93   char *dstp;
94 
95 #ifdef __OPTIMIZE__
96   if (memmove_disallowed && inside_main)
97     abort ();
98 #endif
99 
100   srcp = src;
101   dstp = dst;
102   if (srcp < dstp)
103     while (n-- != 0)
104       dstp[n] = srcp[n];
105   else
106     while (n-- != 0)
107       *dstp++ = *srcp++;
108 
109   return dst;
110 }
111 
112 void *
__memmove_chk(void * dst,const void * src,__SIZE_TYPE__ n,__SIZE_TYPE__ size)113 __memmove_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
114 {
115   /* If size is -1, GCC should always optimize the call into memmove.  */
116   if (size == (__SIZE_TYPE__) -1)
117     abort ();
118   ++chk_calls;
119   if (n > size)
120     __chk_fail ();
121   return memmove (dst, src, n);
122 }
123 
124 void *
memset(void * dst,int c,__SIZE_TYPE__ n)125 memset (void *dst, int c, __SIZE_TYPE__ n)
126 {
127   while (n-- != 0)
128     n[(char *) dst] = c;
129 
130   /* Single-byte memsets should be done inline when optimisation
131      is enabled.  Do this after the copy in case we're being called to
132      initialize bss.  */
133 #ifdef __OPTIMIZE__
134   if (memset_disallowed && inside_main && n < 2)
135     abort ();
136 #endif
137 
138   return dst;
139 }
140 
141 void *
__memset_chk(void * dst,int c,__SIZE_TYPE__ n,__SIZE_TYPE__ size)142 __memset_chk (void *dst, int c, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
143 {
144   /* If size is -1, GCC should always optimize the call into memset.  */
145   if (size == (__SIZE_TYPE__) -1)
146     abort ();
147   ++chk_calls;
148   if (n > size)
149     __chk_fail ();
150   return memset (dst, c, n);
151 }
152 
153 char *
strcpy(char * d,const char * s)154 strcpy (char *d, const char *s)
155 {
156   char *r = d;
157 #ifdef __OPTIMIZE__
158   if (strcpy_disallowed && inside_main)
159     abort ();
160 #endif
161   while ((*d++ = *s++));
162   return r;
163 }
164 
165 char *
__strcpy_chk(char * d,const char * s,__SIZE_TYPE__ size)166 __strcpy_chk (char *d, const char *s, __SIZE_TYPE__ size)
167 {
168   /* If size is -1, GCC should always optimize the call into strcpy.  */
169   if (size == (__SIZE_TYPE__) -1)
170     abort ();
171   ++chk_calls;
172   if (strlen (s) >= size)
173     __chk_fail ();
174   return strcpy (d, s);
175 }
176 
177 char *
stpcpy(char * dst,const char * src)178 stpcpy (char *dst, const char *src)
179 {
180 #ifdef __OPTIMIZE__
181   if (stpcpy_disallowed && inside_main)
182     abort ();
183 #endif
184 
185   while (*src != 0)
186     *dst++ = *src++;
187 
188   *dst = 0;
189   return dst;
190 }
191 
192 char *
__stpcpy_chk(char * d,const char * s,__SIZE_TYPE__ size)193 __stpcpy_chk (char *d, const char *s, __SIZE_TYPE__ size)
194 {
195   /* If size is -1, GCC should always optimize the call into stpcpy.  */
196   if (size == (__SIZE_TYPE__) -1)
197     abort ();
198   ++chk_calls;
199   if (strlen (s) >= size)
200     __chk_fail ();
201   return stpcpy (d, s);
202 }
203 
204 char *
stpncpy(char * dst,const char * src,__SIZE_TYPE__ n)205 stpncpy (char *dst, const char *src, __SIZE_TYPE__ n)
206 {
207 #ifdef __OPTIMIZE__
208   if (stpncpy_disallowed && inside_main)
209     abort ();
210 #endif
211 
212   for (; *src && n; n--)
213     *dst++ = *src++;
214 
215   char *ret = dst;
216 
217   while (n--)
218     *dst++ = 0;
219 
220   return ret;
221 }
222 
223 
224 char *
__stpncpy_chk(char * s1,const char * s2,__SIZE_TYPE__ n,__SIZE_TYPE__ size)225 __stpncpy_chk (char *s1, const char *s2, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
226 {
227   /* If size is -1, GCC should always optimize the call into stpncpy.  */
228   if (size == (__SIZE_TYPE__) -1)
229     abort ();
230   ++chk_calls;
231   if (n > size)
232     __chk_fail ();
233   return stpncpy (s1, s2, n);
234 }
235 
236 char *
strncpy(char * s1,const char * s2,__SIZE_TYPE__ n)237 strncpy (char *s1, const char *s2, __SIZE_TYPE__ n)
238 {
239   char *dest = s1;
240 #ifdef __OPTIMIZE__
241   if (strncpy_disallowed && inside_main)
242     abort();
243 #endif
244   for (; *s2 && n; n--)
245     *s1++ = *s2++;
246   while (n--)
247     *s1++ = 0;
248   return dest;
249 }
250 
251 char *
__strncpy_chk(char * s1,const char * s2,__SIZE_TYPE__ n,__SIZE_TYPE__ size)252 __strncpy_chk (char *s1, const char *s2, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
253 {
254   /* If size is -1, GCC should always optimize the call into strncpy.  */
255   if (size == (__SIZE_TYPE__) -1)
256     abort ();
257   ++chk_calls;
258   if (n > size)
259     __chk_fail ();
260   return strncpy (s1, s2, n);
261 }
262 
263 char *
strcat(char * dst,const char * src)264 strcat (char *dst, const char *src)
265 {
266   char *p = dst;
267 
268 #ifdef __OPTIMIZE__
269   if (strcat_disallowed && inside_main)
270     abort ();
271 #endif
272 
273   while (*p)
274     p++;
275   while ((*p++ = *src++))
276     ;
277   return dst;
278 }
279 
280 char *
__strcat_chk(char * d,const char * s,__SIZE_TYPE__ size)281 __strcat_chk (char *d, const char *s, __SIZE_TYPE__ size)
282 {
283   /* If size is -1, GCC should always optimize the call into strcat.  */
284   if (size == (__SIZE_TYPE__) -1)
285     abort ();
286   ++chk_calls;
287   if (strlen (d) + strlen (s) >= size)
288     __chk_fail ();
289   return strcat (d, s);
290 }
291 
292 char *
strncat(char * s1,const char * s2,__SIZE_TYPE__ n)293 strncat (char *s1, const char *s2, __SIZE_TYPE__ n)
294 {
295   char *dest = s1;
296   char c;
297 #ifdef __OPTIMIZE__
298   if (strncat_disallowed && inside_main)
299     abort();
300 #endif
301   while (*s1) s1++;
302   c = '\0';
303   while (n > 0)
304     {
305       c = *s2++;
306       *s1++ = c;
307       if (c == '\0')
308 	return dest;
309       n--;
310     }
311   if (c != '\0')
312     *s1 = '\0';
313   return dest;
314 }
315 
316 char *
__strncat_chk(char * d,const char * s,__SIZE_TYPE__ n,__SIZE_TYPE__ size)317 __strncat_chk (char *d, const char *s, __SIZE_TYPE__ n, __SIZE_TYPE__ size)
318 {
319   __SIZE_TYPE__ len = strlen (d), n1 = n;
320   const char *s1 = s;
321 
322   /* If size is -1, GCC should always optimize the call into strncat.  */
323   if (size == (__SIZE_TYPE__) -1)
324     abort ();
325   ++chk_calls;
326   while (len < size && n1 > 0)
327     {
328       if (*s1++ == '\0')
329 	break;
330       ++len;
331       --n1;
332     }
333 
334   if (len >= size)
335     __chk_fail ();
336   return strncat (d, s, n);
337 }
338 
339 /* No chk test in GCC testsuite needs more bytes than this.
340    As we can't expect vsnprintf to be available on the target,
341    assume 4096 bytes is enough.  */
342 static char chk_sprintf_buf[4096];
343 
344 int
__sprintf_chk(char * str,int flag,__SIZE_TYPE__ size,const char * fmt,...)345 __sprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt, ...)
346 {
347   int ret;
348   va_list ap;
349 
350   /* If size is -1 and flag 0, GCC should always optimize the call into
351      sprintf.  */
352   if (size == (__SIZE_TYPE__) -1 && flag == 0)
353     abort ();
354   ++chk_calls;
355 #ifdef __OPTIMIZE__
356   if (sprintf_disallowed && inside_main)
357     abort();
358 #endif
359   va_start (ap, fmt);
360   ret = vsprintf (chk_sprintf_buf, fmt, ap);
361   va_end (ap);
362   if (ret >= 0)
363     {
364       if (ret >= size)
365 	__chk_fail ();
366       memcpy (str, chk_sprintf_buf, ret + 1);
367     }
368   return ret;
369 }
370 
371 int
__vsprintf_chk(char * str,int flag,__SIZE_TYPE__ size,const char * fmt,va_list ap)372 __vsprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt,
373 		va_list ap)
374 {
375   int ret;
376 
377   /* If size is -1 and flag 0, GCC should always optimize the call into
378      vsprintf.  */
379   if (size == (__SIZE_TYPE__) -1 && flag == 0)
380     abort ();
381   ++chk_calls;
382 #ifdef __OPTIMIZE__
383   if (vsprintf_disallowed && inside_main)
384     abort();
385 #endif
386   ret = vsprintf (chk_sprintf_buf, fmt, ap);
387   if (ret >= 0)
388     {
389       if (ret >= size)
390 	__chk_fail ();
391       memcpy (str, chk_sprintf_buf, ret + 1);
392     }
393   return ret;
394 }
395 
396 int
__snprintf_chk(char * str,__SIZE_TYPE__ len,int flag,__SIZE_TYPE__ size,const char * fmt,...)397 __snprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size,
398 		const char *fmt, ...)
399 {
400   int ret;
401   va_list ap;
402 
403   /* If size is -1 and flag 0, GCC should always optimize the call into
404      snprintf.  */
405   if (size == (__SIZE_TYPE__) -1 && flag == 0)
406     abort ();
407   ++chk_calls;
408   if (size < len)
409     __chk_fail ();
410 #ifdef __OPTIMIZE__
411   if (snprintf_disallowed && inside_main)
412     abort();
413 #endif
414   va_start (ap, fmt);
415   ret = vsprintf (chk_sprintf_buf, fmt, ap);
416   va_end (ap);
417   if (ret >= 0)
418     {
419       if (ret < len)
420 	memcpy (str, chk_sprintf_buf, ret + 1);
421       else
422 	{
423 	  memcpy (str, chk_sprintf_buf, len - 1);
424 	  str[len - 1] = '\0';
425 	}
426     }
427   return ret;
428 }
429 
430 int
__vsnprintf_chk(char * str,__SIZE_TYPE__ len,int flag,__SIZE_TYPE__ size,const char * fmt,va_list ap)431 __vsnprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size,
432 		 const char *fmt, va_list ap)
433 {
434   int ret;
435 
436   /* If size is -1 and flag 0, GCC should always optimize the call into
437      vsnprintf.  */
438   if (size == (__SIZE_TYPE__) -1 && flag == 0)
439     abort ();
440   ++chk_calls;
441   if (size < len)
442     __chk_fail ();
443 #ifdef __OPTIMIZE__
444   if (vsnprintf_disallowed && inside_main)
445     abort();
446 #endif
447   ret = vsprintf (chk_sprintf_buf, fmt, ap);
448   if (ret >= 0)
449     {
450       if (ret < len)
451 	memcpy (str, chk_sprintf_buf, ret + 1);
452       else
453 	{
454 	  memcpy (str, chk_sprintf_buf, len - 1);
455 	  str[len - 1] = '\0';
456 	}
457     }
458   return ret;
459 }
460 
461 int
snprintf(char * str,__SIZE_TYPE__ len,const char * fmt,...)462 snprintf (char *str, __SIZE_TYPE__ len, const char *fmt, ...)
463 {
464   int ret;
465   va_list ap;
466 
467 #ifdef __OPTIMIZE__
468   if (snprintf_disallowed && inside_main)
469     abort();
470 #endif
471   va_start (ap, fmt);
472   ret = vsprintf (chk_sprintf_buf, fmt, ap);
473   va_end (ap);
474   if (ret >= 0)
475     {
476       if (ret < len)
477 	memcpy (str, chk_sprintf_buf, ret + 1);
478       else if (len)
479 	{
480 	  memcpy (str, chk_sprintf_buf, len - 1);
481 	  str[len - 1] = '\0';
482 	}
483     }
484   return ret;
485 }
486 
487 /* uClibc's vsprintf calls vsnprintf.  */
488 #ifndef __UCLIBC__
489 int
vsnprintf(char * str,__SIZE_TYPE__ len,const char * fmt,va_list ap)490 vsnprintf (char *str, __SIZE_TYPE__ len, const char *fmt, va_list ap)
491 {
492   int ret;
493 
494 #ifdef __OPTIMIZE__
495   if (vsnprintf_disallowed && inside_main)
496     abort();
497 #endif
498   ret = vsprintf (chk_sprintf_buf, fmt, ap);
499   if (ret >= 0)
500     {
501       if (ret < len)
502 	memcpy (str, chk_sprintf_buf, ret + 1);
503       else if (len)
504 	{
505 	  memcpy (str, chk_sprintf_buf, len - 1);
506 	  str[len - 1] = '\0';
507 	}
508     }
509   return ret;
510 }
511 #endif
512