xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision b4e38a41f584ad4391c04b8cfec81f46176b18b0)
1 //===-- dfsan.cpp ---------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of DataFlowSanitizer.
10 //
11 // This file defines the custom functions listed in done_abilist.txt.
12 //===----------------------------------------------------------------------===//
13 
14 #include "sanitizer_common/sanitizer_common.h"
15 #include "sanitizer_common/sanitizer_internal_defs.h"
16 #include "sanitizer_common/sanitizer_linux.h"
17 
18 #include "dfsan/dfsan.h"
19 
20 #include <arpa/inet.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <dlfcn.h>
24 #include <link.h>
25 #include <poll.h>
26 #include <pthread.h>
27 #include <pwd.h>
28 #include <sched.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/resource.h>
36 #include <sys/select.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <time.h>
41 #include <unistd.h>
42 
43 using namespace __dfsan;
44 
45 #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)                                     \
46   do {                                                                         \
47     if (f)                                                                     \
48       f(__VA_ARGS__);                                                          \
49   } while (false)
50 #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
51 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
52 
53 extern "C" {
54 SANITIZER_INTERFACE_ATTRIBUTE int
55 __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
56             dfsan_label buf_label, dfsan_label *ret_label) {
57   int ret = stat(path, buf);
58   if (ret == 0)
59     dfsan_set_label(0, buf, sizeof(struct stat));
60   *ret_label = 0;
61   return ret;
62 }
63 
64 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
65                                                dfsan_label fd_label,
66                                                dfsan_label buf_label,
67                                                dfsan_label *ret_label) {
68   int ret = fstat(fd, buf);
69   if (ret == 0)
70     dfsan_set_label(0, buf, sizeof(struct stat));
71   *ret_label = 0;
72   return ret;
73 }
74 
75 SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
76                                                   dfsan_label s_label,
77                                                   dfsan_label c_label,
78                                                   dfsan_label *ret_label) {
79   for (size_t i = 0;; ++i) {
80     if (s[i] == c || s[i] == 0) {
81       if (flags().strict_data_dependencies) {
82         *ret_label = s_label;
83       } else {
84         *ret_label = dfsan_union(dfsan_read_label(s, i + 1),
85                                  dfsan_union(s_label, c_label));
86       }
87       return s[i] == 0 ? nullptr : const_cast<char *>(s+i);
88     }
89   }
90 }
91 
92 DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
93                               const void *s1, const void *s2, size_t n,
94                               dfsan_label s1_label, dfsan_label s2_label,
95                               dfsan_label n_label)
96 
97 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
98                                                 size_t n, dfsan_label s1_label,
99                                                 dfsan_label s2_label,
100                                                 dfsan_label n_label,
101                                                 dfsan_label *ret_label) {
102   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
103                              s1_label, s2_label, n_label);
104   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
105   for (size_t i = 0; i != n; ++i) {
106     if (cs1[i] != cs2[i]) {
107       if (flags().strict_data_dependencies) {
108         *ret_label = 0;
109       } else {
110         *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
111                                  dfsan_read_label(cs2, i + 1));
112       }
113       return cs1[i] - cs2[i];
114     }
115   }
116 
117   if (flags().strict_data_dependencies) {
118     *ret_label = 0;
119   } else {
120     *ret_label = dfsan_union(dfsan_read_label(cs1, n),
121                              dfsan_read_label(cs2, n));
122   }
123   return 0;
124 }
125 
126 DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
127                               const char *s1, const char *s2,
128                               dfsan_label s1_label, dfsan_label s2_label)
129 
130 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
131                                                 dfsan_label s1_label,
132                                                 dfsan_label s2_label,
133                                                 dfsan_label *ret_label) {
134   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
135                              s1_label, s2_label);
136   for (size_t i = 0;; ++i) {
137     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
138       if (flags().strict_data_dependencies) {
139         *ret_label = 0;
140       } else {
141         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
142                                  dfsan_read_label(s2, i + 1));
143       }
144       return s1[i] - s2[i];
145     }
146   }
147   return 0;
148 }
149 
150 SANITIZER_INTERFACE_ATTRIBUTE int
151 __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
152                   dfsan_label s2_label, dfsan_label *ret_label) {
153   for (size_t i = 0;; ++i) {
154     if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) {
155       if (flags().strict_data_dependencies) {
156         *ret_label = 0;
157       } else {
158         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
159                                  dfsan_read_label(s2, i + 1));
160       }
161       return s1[i] - s2[i];
162     }
163   }
164   return 0;
165 }
166 
167 DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
168                               const char *s1, const char *s2, size_t n,
169                               dfsan_label s1_label, dfsan_label s2_label,
170                               dfsan_label n_label)
171 
172 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
173                                                  size_t n, dfsan_label s1_label,
174                                                  dfsan_label s2_label,
175                                                  dfsan_label n_label,
176                                                  dfsan_label *ret_label) {
177   if (n == 0) {
178     *ret_label = 0;
179     return 0;
180   }
181 
182   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
183                              n, s1_label, s2_label, n_label);
184 
185   for (size_t i = 0;; ++i) {
186     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
187       if (flags().strict_data_dependencies) {
188         *ret_label = 0;
189       } else {
190         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
191                                  dfsan_read_label(s2, i + 1));
192       }
193       return s1[i] - s2[i];
194     }
195   }
196   return 0;
197 }
198 
199 SANITIZER_INTERFACE_ATTRIBUTE int
200 __dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
201                    dfsan_label s1_label, dfsan_label s2_label,
202                    dfsan_label n_label, dfsan_label *ret_label) {
203   if (n == 0) {
204     *ret_label = 0;
205     return 0;
206   }
207 
208   for (size_t i = 0;; ++i) {
209     if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0 ||
210         i == n - 1) {
211       if (flags().strict_data_dependencies) {
212         *ret_label = 0;
213       } else {
214         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
215                                  dfsan_read_label(s2, i + 1));
216       }
217       return s1[i] - s2[i];
218     }
219   }
220   return 0;
221 }
222 
223 SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
224                                                   dfsan_label nmemb_label,
225                                                   dfsan_label size_label,
226                                                   dfsan_label *ret_label) {
227   void *p = calloc(nmemb, size);
228   dfsan_set_label(0, p, nmemb * size);
229   *ret_label = 0;
230   return p;
231 }
232 
233 SANITIZER_INTERFACE_ATTRIBUTE size_t
234 __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
235   size_t ret = strlen(s);
236   if (flags().strict_data_dependencies) {
237     *ret_label = 0;
238   } else {
239     *ret_label = dfsan_read_label(s, ret + 1);
240   }
241   return ret;
242 }
243 
244 
245 static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
246   dfsan_label *sdest = shadow_for(dest);
247   const dfsan_label *ssrc = shadow_for(src);
248   internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
249   return internal_memcpy(dest, src, n);
250 }
251 
252 static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
253   internal_memset(s, c, n);
254   dfsan_set_label(c_label, s, n);
255 }
256 
257 SANITIZER_INTERFACE_ATTRIBUTE
258 void *__dfsw_memcpy(void *dest, const void *src, size_t n,
259                     dfsan_label dest_label, dfsan_label src_label,
260                     dfsan_label n_label, dfsan_label *ret_label) {
261   *ret_label = dest_label;
262   return dfsan_memcpy(dest, src, n);
263 }
264 
265 SANITIZER_INTERFACE_ATTRIBUTE
266 void *__dfsw_memset(void *s, int c, size_t n,
267                     dfsan_label s_label, dfsan_label c_label,
268                     dfsan_label n_label, dfsan_label *ret_label) {
269   dfsan_memset(s, c, c_label, n);
270   *ret_label = s_label;
271   return s;
272 }
273 
274 SANITIZER_INTERFACE_ATTRIBUTE char *
275 __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
276   size_t len = strlen(s);
277   void *p = malloc(len+1);
278   dfsan_memcpy(p, s, len+1);
279   *ret_label = 0;
280   return static_cast<char *>(p);
281 }
282 
283 SANITIZER_INTERFACE_ATTRIBUTE char *
284 __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
285                dfsan_label s2_label, dfsan_label n_label,
286                dfsan_label *ret_label) {
287   size_t len = strlen(s2);
288   if (len < n) {
289     dfsan_memcpy(s1, s2, len+1);
290     dfsan_memset(s1+len+1, 0, 0, n-len-1);
291   } else {
292     dfsan_memcpy(s1, s2, n);
293   }
294 
295   *ret_label = s1_label;
296   return s1;
297 }
298 
299 SANITIZER_INTERFACE_ATTRIBUTE ssize_t
300 __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
301              dfsan_label fd_label, dfsan_label buf_label,
302              dfsan_label count_label, dfsan_label offset_label,
303              dfsan_label *ret_label) {
304   ssize_t ret = pread(fd, buf, count, offset);
305   if (ret > 0)
306     dfsan_set_label(0, buf, ret);
307   *ret_label = 0;
308   return ret;
309 }
310 
311 SANITIZER_INTERFACE_ATTRIBUTE ssize_t
312 __dfsw_read(int fd, void *buf, size_t count,
313              dfsan_label fd_label, dfsan_label buf_label,
314              dfsan_label count_label,
315              dfsan_label *ret_label) {
316   ssize_t ret = read(fd, buf, count);
317   if (ret > 0)
318     dfsan_set_label(0, buf, ret);
319   *ret_label = 0;
320   return ret;
321 }
322 
323 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
324                                                        struct timespec *tp,
325                                                        dfsan_label clk_id_label,
326                                                        dfsan_label tp_label,
327                                                        dfsan_label *ret_label) {
328   int ret = clock_gettime(clk_id, tp);
329   if (ret == 0)
330     dfsan_set_label(0, tp, sizeof(struct timespec));
331   *ret_label = 0;
332   return ret;
333 }
334 
335 static void unpoison(const void *ptr, uptr size) {
336   dfsan_set_label(0, const_cast<void *>(ptr), size);
337 }
338 
339 // dlopen() ultimately calls mmap() down inside the loader, which generally
340 // doesn't participate in dynamic symbol resolution.  Therefore we won't
341 // intercept its calls to mmap, and we have to hook it here.
342 SANITIZER_INTERFACE_ATTRIBUTE void *
343 __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
344               dfsan_label flag_label, dfsan_label *ret_label) {
345   void *handle = dlopen(filename, flag);
346   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
347   if (map)
348     ForEachMappedRegion(map, unpoison);
349   *ret_label = 0;
350   return handle;
351 }
352 
353 struct pthread_create_info {
354   void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
355   void *start_routine;
356   void *arg;
357 };
358 
359 static void *pthread_create_cb(void *p) {
360   pthread_create_info pci(*(pthread_create_info *)p);
361   free(p);
362   dfsan_label ret_label;
363   return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
364                                       &ret_label);
365 }
366 
367 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
368     pthread_t *thread, const pthread_attr_t *attr,
369     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
370                                       dfsan_label *),
371     void *start_routine, void *arg, dfsan_label thread_label,
372     dfsan_label attr_label, dfsan_label start_routine_label,
373     dfsan_label arg_label, dfsan_label *ret_label) {
374   pthread_create_info *pci =
375       (pthread_create_info *)malloc(sizeof(pthread_create_info));
376   pci->start_routine_trampoline = start_routine_trampoline;
377   pci->start_routine = start_routine;
378   pci->arg = arg;
379   int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
380   if (rv != 0)
381     free(pci);
382   *ret_label = 0;
383   return rv;
384 }
385 
386 struct dl_iterate_phdr_info {
387   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
388                              size_t size, void *data, dfsan_label info_label,
389                              dfsan_label size_label, dfsan_label data_label,
390                              dfsan_label *ret_label);
391   void *callback;
392   void *data;
393 };
394 
395 int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
396   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
397   dfsan_set_label(0, *info);
398   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
399                   strlen(info->dlpi_name) + 1);
400   dfsan_set_label(
401       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
402       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
403   dfsan_label ret_label;
404   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
405                                    0, &ret_label);
406 }
407 
408 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
409     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
410                                size_t size, void *data, dfsan_label info_label,
411                                dfsan_label size_label, dfsan_label data_label,
412                                dfsan_label *ret_label),
413     void *callback, void *data, dfsan_label callback_label,
414     dfsan_label data_label, dfsan_label *ret_label) {
415   dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
416   *ret_label = 0;
417   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
418 }
419 
420 SANITIZER_INTERFACE_ATTRIBUTE
421 char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
422                      dfsan_label buf_label, dfsan_label *ret_label) {
423   char *ret = ctime_r(timep, buf);
424   if (ret) {
425     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
426                     strlen(buf) + 1);
427     *ret_label = buf_label;
428   } else {
429     *ret_label = 0;
430   }
431   return ret;
432 }
433 
434 SANITIZER_INTERFACE_ATTRIBUTE
435 char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
436                    dfsan_label size_label, dfsan_label stream_label,
437                    dfsan_label *ret_label) {
438   char *ret = fgets(s, size, stream);
439   if (ret) {
440     dfsan_set_label(0, ret, strlen(ret) + 1);
441     *ret_label = s_label;
442   } else {
443     *ret_label = 0;
444   }
445   return ret;
446 }
447 
448 SANITIZER_INTERFACE_ATTRIBUTE
449 char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
450                     dfsan_label size_label, dfsan_label *ret_label) {
451   char *ret = getcwd(buf, size);
452   if (ret) {
453     dfsan_set_label(0, ret, strlen(ret) + 1);
454     *ret_label = buf_label;
455   } else {
456     *ret_label = 0;
457   }
458   return ret;
459 }
460 
461 SANITIZER_INTERFACE_ATTRIBUTE
462 char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
463   char *ret = get_current_dir_name();
464   if (ret) {
465     dfsan_set_label(0, ret, strlen(ret) + 1);
466   }
467   *ret_label = 0;
468   return ret;
469 }
470 
471 SANITIZER_INTERFACE_ATTRIBUTE
472 int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
473                        dfsan_label len_label, dfsan_label *ret_label) {
474   int ret = gethostname(name, len);
475   if (ret == 0) {
476     dfsan_set_label(0, name, strlen(name) + 1);
477   }
478   *ret_label = 0;
479   return ret;
480 }
481 
482 SANITIZER_INTERFACE_ATTRIBUTE
483 int __dfsw_getrlimit(int resource, struct rlimit *rlim,
484                      dfsan_label resource_label, dfsan_label rlim_label,
485                      dfsan_label *ret_label) {
486   int ret = getrlimit(resource, rlim);
487   if (ret == 0) {
488     dfsan_set_label(0, rlim, sizeof(struct rlimit));
489   }
490   *ret_label = 0;
491   return ret;
492 }
493 
494 SANITIZER_INTERFACE_ATTRIBUTE
495 int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
496                      dfsan_label usage_label, dfsan_label *ret_label) {
497   int ret = getrusage(who, usage);
498   if (ret == 0) {
499     dfsan_set_label(0, usage, sizeof(struct rusage));
500   }
501   *ret_label = 0;
502   return ret;
503 }
504 
505 SANITIZER_INTERFACE_ATTRIBUTE
506 char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
507                     dfsan_label src_label, dfsan_label *ret_label) {
508   char *ret = strcpy(dest, src);  // NOLINT
509   if (ret) {
510     internal_memcpy(shadow_for(dest), shadow_for(src),
511                     sizeof(dfsan_label) * (strlen(src) + 1));
512   }
513   *ret_label = dst_label;
514   return ret;
515 }
516 
517 SANITIZER_INTERFACE_ATTRIBUTE
518 long int __dfsw_strtol(const char *nptr, char **endptr, int base,
519                        dfsan_label nptr_label, dfsan_label endptr_label,
520                        dfsan_label base_label, dfsan_label *ret_label) {
521   char *tmp_endptr;
522   long int ret = strtol(nptr, &tmp_endptr, base);
523   if (endptr) {
524     *endptr = tmp_endptr;
525   }
526   if (tmp_endptr > nptr) {
527     // If *tmp_endptr is '\0' include its label as well.
528     *ret_label = dfsan_union(
529         base_label,
530         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
531   } else {
532     *ret_label = 0;
533   }
534   return ret;
535 }
536 
537 SANITIZER_INTERFACE_ATTRIBUTE
538 double __dfsw_strtod(const char *nptr, char **endptr,
539                        dfsan_label nptr_label, dfsan_label endptr_label,
540                        dfsan_label *ret_label) {
541   char *tmp_endptr;
542   double ret = strtod(nptr, &tmp_endptr);
543   if (endptr) {
544     *endptr = tmp_endptr;
545   }
546   if (tmp_endptr > nptr) {
547     // If *tmp_endptr is '\0' include its label as well.
548     *ret_label = dfsan_read_label(
549         nptr,
550         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
551   } else {
552     *ret_label = 0;
553   }
554   return ret;
555 }
556 
557 SANITIZER_INTERFACE_ATTRIBUTE
558 long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
559                        dfsan_label nptr_label, dfsan_label endptr_label,
560                        dfsan_label base_label, dfsan_label *ret_label) {
561   char *tmp_endptr;
562   long long int ret = strtoll(nptr, &tmp_endptr, base);
563   if (endptr) {
564     *endptr = tmp_endptr;
565   }
566   if (tmp_endptr > nptr) {
567     // If *tmp_endptr is '\0' include its label as well.
568     *ret_label = dfsan_union(
569         base_label,
570         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
571   } else {
572     *ret_label = 0;
573   }
574   return ret;
575 }
576 
577 SANITIZER_INTERFACE_ATTRIBUTE
578 unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
579                        dfsan_label nptr_label, dfsan_label endptr_label,
580                        dfsan_label base_label, dfsan_label *ret_label) {
581   char *tmp_endptr;
582   unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
583   if (endptr) {
584     *endptr = tmp_endptr;
585   }
586   if (tmp_endptr > nptr) {
587     // If *tmp_endptr is '\0' include its label as well.
588     *ret_label = dfsan_union(
589         base_label,
590         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
591   } else {
592     *ret_label = 0;
593   }
594   return ret;
595 }
596 
597 SANITIZER_INTERFACE_ATTRIBUTE
598 long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
599                                        dfsan_label nptr_label,
600                                        int base, dfsan_label endptr_label,
601                                        dfsan_label base_label,
602                                        dfsan_label *ret_label) {
603   char *tmp_endptr;
604   long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
605   if (endptr) {
606     *endptr = tmp_endptr;
607   }
608   if (tmp_endptr > nptr) {
609     // If *tmp_endptr is '\0' include its label as well.
610     *ret_label = dfsan_union(
611         base_label,
612         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
613   } else {
614     *ret_label = 0;
615   }
616   return ret;
617 }
618 
619 SANITIZER_INTERFACE_ATTRIBUTE
620 time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
621   time_t ret = time(t);
622   if (ret != (time_t) -1 && t) {
623     dfsan_set_label(0, t, sizeof(time_t));
624   }
625   *ret_label = 0;
626   return ret;
627 }
628 
629 SANITIZER_INTERFACE_ATTRIBUTE
630 int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
631                      dfsan_label src_label, dfsan_label dst_label,
632                      dfsan_label *ret_label) {
633   int ret = inet_pton(af, src, dst);
634   if (ret == 1) {
635     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
636                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
637   }
638   *ret_label = 0;
639   return ret;
640 }
641 
642 SANITIZER_INTERFACE_ATTRIBUTE
643 struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
644                               dfsan_label timep_label, dfsan_label result_label,
645                               dfsan_label *ret_label) {
646   struct tm *ret = localtime_r(timep, result);
647   if (ret) {
648     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
649                     sizeof(struct tm));
650     *ret_label = result_label;
651   } else {
652     *ret_label = 0;
653   }
654   return ret;
655 }
656 
657 SANITIZER_INTERFACE_ATTRIBUTE
658 int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
659                       char *buf, size_t buflen, struct passwd **result,
660                       dfsan_label uid_label, dfsan_label pwd_label,
661                       dfsan_label buf_label, dfsan_label buflen_label,
662                       dfsan_label result_label, dfsan_label *ret_label) {
663   // Store the data in pwd, the strings referenced from pwd in buf, and the
664   // address of pwd in *result.  On failure, NULL is stored in *result.
665   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
666   if (ret == 0) {
667     dfsan_set_label(0, pwd, sizeof(struct passwd));
668     dfsan_set_label(0, buf, strlen(buf) + 1);
669   }
670   *ret_label = 0;
671   dfsan_set_label(0, result, sizeof(struct passwd*));
672   return ret;
673 }
674 
675 SANITIZER_INTERFACE_ATTRIBUTE
676 int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
677                 dfsan_label dfs_label, dfsan_label nfds_label,
678                 dfsan_label timeout_label, dfsan_label *ret_label) {
679   int ret = poll(fds, nfds, timeout);
680   if (ret >= 0) {
681     for (; nfds > 0; --nfds) {
682       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
683     }
684   }
685   *ret_label = 0;
686   return ret;
687 }
688 
689 SANITIZER_INTERFACE_ATTRIBUTE
690 int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
691                   fd_set *exceptfds, struct timeval *timeout,
692                   dfsan_label nfds_label, dfsan_label readfds_label,
693                   dfsan_label writefds_label, dfsan_label exceptfds_label,
694                   dfsan_label timeout_label, dfsan_label *ret_label) {
695   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
696   // Clear everything (also on error) since their content is either set or
697   // undefined.
698   if (readfds) {
699     dfsan_set_label(0, readfds, sizeof(fd_set));
700   }
701   if (writefds) {
702     dfsan_set_label(0, writefds, sizeof(fd_set));
703   }
704   if (exceptfds) {
705     dfsan_set_label(0, exceptfds, sizeof(fd_set));
706   }
707   dfsan_set_label(0, timeout, sizeof(struct timeval));
708   *ret_label = 0;
709   return ret;
710 }
711 
712 SANITIZER_INTERFACE_ATTRIBUTE
713 int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
714                              dfsan_label pid_label,
715                              dfsan_label cpusetsize_label,
716                              dfsan_label mask_label, dfsan_label *ret_label) {
717   int ret = sched_getaffinity(pid, cpusetsize, mask);
718   if (ret == 0) {
719     dfsan_set_label(0, mask, cpusetsize);
720   }
721   *ret_label = 0;
722   return ret;
723 }
724 
725 SANITIZER_INTERFACE_ATTRIBUTE
726 int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
727                        dfsan_label *ret_label) {
728   int ret = sigemptyset(set);
729   dfsan_set_label(0, set, sizeof(sigset_t));
730   return ret;
731 }
732 
733 SANITIZER_INTERFACE_ATTRIBUTE
734 int __dfsw_sigaction(int signum, const struct sigaction *act,
735                      struct sigaction *oldact, dfsan_label signum_label,
736                      dfsan_label act_label, dfsan_label oldact_label,
737                      dfsan_label *ret_label) {
738   int ret = sigaction(signum, act, oldact);
739   if (oldact) {
740     dfsan_set_label(0, oldact, sizeof(struct sigaction));
741   }
742   *ret_label = 0;
743   return ret;
744 }
745 
746 SANITIZER_INTERFACE_ATTRIBUTE
747 int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
748                         dfsan_label tv_label, dfsan_label tz_label,
749                         dfsan_label *ret_label) {
750   int ret = gettimeofday(tv, tz);
751   if (tv) {
752     dfsan_set_label(0, tv, sizeof(struct timeval));
753   }
754   if (tz) {
755     dfsan_set_label(0, tz, sizeof(struct timezone));
756   }
757   *ret_label = 0;
758   return ret;
759 }
760 
761 SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
762                                                   dfsan_label s_label,
763                                                   dfsan_label c_label,
764                                                   dfsan_label n_label,
765                                                   dfsan_label *ret_label) {
766   void *ret = memchr(s, c, n);
767   if (flags().strict_data_dependencies) {
768     *ret_label = ret ? s_label : 0;
769   } else {
770     size_t len =
771         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
772             : n;
773     *ret_label =
774         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
775   }
776   return ret;
777 }
778 
779 SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
780                                                    dfsan_label s_label,
781                                                    dfsan_label c_label,
782                                                    dfsan_label *ret_label) {
783   char *ret = strrchr(s, c);
784   if (flags().strict_data_dependencies) {
785     *ret_label = ret ? s_label : 0;
786   } else {
787     *ret_label =
788         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
789                     dfsan_union(s_label, c_label));
790   }
791 
792   return ret;
793 }
794 
795 SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
796                                                   dfsan_label haystack_label,
797                                                   dfsan_label needle_label,
798                                                   dfsan_label *ret_label) {
799   char *ret = strstr(haystack, needle);
800   if (flags().strict_data_dependencies) {
801     *ret_label = ret ? haystack_label : 0;
802   } else {
803     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
804     *ret_label =
805         dfsan_union(dfsan_read_label(haystack, len),
806                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
807                                 dfsan_union(haystack_label, needle_label)));
808   }
809 
810   return ret;
811 }
812 
813 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
814                                                    struct timespec *rem,
815                                                    dfsan_label req_label,
816                                                    dfsan_label rem_label,
817                                                    dfsan_label *ret_label) {
818   int ret = nanosleep(req, rem);
819   *ret_label = 0;
820   if (ret == -1) {
821     // Interrupted by a signal, rem is filled with the remaining time.
822     dfsan_set_label(0, rem, sizeof(struct timespec));
823   }
824   return ret;
825 }
826 
827 SANITIZER_INTERFACE_ATTRIBUTE int
828 __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
829                   dfsan_label domain_label, dfsan_label type_label,
830                   dfsan_label protocol_label, dfsan_label sv_label,
831                   dfsan_label *ret_label) {
832   int ret = socketpair(domain, type, protocol, sv);
833   *ret_label = 0;
834   if (ret == 0) {
835     dfsan_set_label(0, sv, sizeof(*sv) * 2);
836   }
837   return ret;
838 }
839 
840 // Type of the trampoline function passed to the custom version of
841 // dfsan_set_write_callback.
842 typedef void (*write_trampoline_t)(
843     void *callback,
844     int fd, const void *buf, ssize_t count,
845     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
846 
847 // Calls to dfsan_set_write_callback() set the values in this struct.
848 // Calls to the custom version of write() read (and invoke) them.
849 static struct {
850   write_trampoline_t write_callback_trampoline = nullptr;
851   void *write_callback = nullptr;
852 } write_callback_info;
853 
854 SANITIZER_INTERFACE_ATTRIBUTE void
855 __dfsw_dfsan_set_write_callback(
856     write_trampoline_t write_callback_trampoline,
857     void *write_callback,
858     dfsan_label write_callback_label,
859     dfsan_label *ret_label) {
860   write_callback_info.write_callback_trampoline = write_callback_trampoline;
861   write_callback_info.write_callback = write_callback;
862 }
863 
864 SANITIZER_INTERFACE_ATTRIBUTE int
865 __dfsw_write(int fd, const void *buf, size_t count,
866              dfsan_label fd_label, dfsan_label buf_label,
867              dfsan_label count_label, dfsan_label *ret_label) {
868   if (write_callback_info.write_callback) {
869     write_callback_info.write_callback_trampoline(
870         write_callback_info.write_callback,
871         fd, buf, count,
872         fd_label, buf_label, count_label);
873   }
874 
875   *ret_label = 0;
876   return write(fd, buf, count);
877 }
878 } // namespace __dfsan
879 
880 // Type used to extract a dfsan_label with va_arg()
881 typedef int dfsan_label_va;
882 
883 // Formats a chunk either a constant string or a single format directive (e.g.,
884 // '%.3f').
885 struct Formatter {
886   Formatter(char *str_, const char *fmt_, size_t size_)
887       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
888         width(-1) {}
889 
890   int format() {
891     char *tmp_fmt = build_format_string();
892     int retval =
893         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
894                  0 /* used only to avoid warnings */);
895     free(tmp_fmt);
896     return retval;
897   }
898 
899   template <typename T> int format(T arg) {
900     char *tmp_fmt = build_format_string();
901     int retval;
902     if (width >= 0) {
903       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
904                         tmp_fmt, width, arg);
905     } else {
906       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
907                         tmp_fmt, arg);
908     }
909     free(tmp_fmt);
910     return retval;
911   }
912 
913   char *build_format_string() {
914     size_t fmt_size = fmt_cur - fmt_start + 1;
915     char *new_fmt = (char *)malloc(fmt_size + 1);
916     assert(new_fmt);
917     internal_memcpy(new_fmt, fmt_start, fmt_size);
918     new_fmt[fmt_size] = '\0';
919     return new_fmt;
920   }
921 
922   char *str_cur() { return str + str_off; }
923 
924   size_t num_written_bytes(int retval) {
925     if (retval < 0) {
926       return 0;
927     }
928 
929     size_t num_avail = str_off < size ? size - str_off : 0;
930     if (num_avail == 0) {
931       return 0;
932     }
933 
934     size_t num_written = retval;
935     // A return value of {v,}snprintf of size or more means that the output was
936     // truncated.
937     if (num_written >= num_avail) {
938       num_written -= num_avail;
939     }
940 
941     return num_written;
942   }
943 
944   char *str;
945   size_t str_off;
946   size_t size;
947   const char *fmt_start;
948   const char *fmt_cur;
949   int width;
950 };
951 
952 // Formats the input and propagates the input labels to the output. The output
953 // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
954 // 'ap' are the format string and the list of arguments for formatting. Returns
955 // the return value vsnprintf would return.
956 //
957 // The function tokenizes the format string in chunks representing either a
958 // constant string or a single format directive (e.g., '%.3f') and formats each
959 // chunk independently into the output string. This approach allows to figure
960 // out which bytes of the output string depends on which argument and thus to
961 // propagate labels more precisely.
962 //
963 // WARNING: This implementation does not support conversion specifiers with
964 // positional arguments.
965 static int format_buffer(char *str, size_t size, const char *fmt,
966                          dfsan_label *va_labels, dfsan_label *ret_label,
967                          va_list ap) {
968   Formatter formatter(str, fmt, size);
969 
970   while (*formatter.fmt_cur) {
971     formatter.fmt_start = formatter.fmt_cur;
972     formatter.width = -1;
973     int retval = 0;
974 
975     if (*formatter.fmt_cur != '%') {
976       // Ordinary character. Consume all the characters until a '%' or the end
977       // of the string.
978       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
979            ++formatter.fmt_cur) {}
980       retval = formatter.format();
981       dfsan_set_label(0, formatter.str_cur(),
982                       formatter.num_written_bytes(retval));
983     } else {
984       // Conversion directive. Consume all the characters until a conversion
985       // specifier or the end of the string.
986       bool end_fmt = false;
987       for (; *formatter.fmt_cur && !end_fmt; ) {
988         switch (*++formatter.fmt_cur) {
989         case 'd':
990         case 'i':
991         case 'o':
992         case 'u':
993         case 'x':
994         case 'X':
995           switch (*(formatter.fmt_cur - 1)) {
996           case 'h':
997             // Also covers the 'hh' case (since the size of the arg is still
998             // an int).
999             retval = formatter.format(va_arg(ap, int));
1000             break;
1001           case 'l':
1002             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
1003                 *(formatter.fmt_cur - 2) == 'l') {
1004               retval = formatter.format(va_arg(ap, long long int));
1005             } else {
1006               retval = formatter.format(va_arg(ap, long int));
1007             }
1008             break;
1009           case 'q':
1010             retval = formatter.format(va_arg(ap, long long int));
1011             break;
1012           case 'j':
1013             retval = formatter.format(va_arg(ap, intmax_t));
1014             break;
1015           case 'z':
1016           case 't':
1017             retval = formatter.format(va_arg(ap, size_t));
1018             break;
1019           default:
1020             retval = formatter.format(va_arg(ap, int));
1021           }
1022           dfsan_set_label(*va_labels++, formatter.str_cur(),
1023                           formatter.num_written_bytes(retval));
1024           end_fmt = true;
1025           break;
1026 
1027         case 'a':
1028         case 'A':
1029         case 'e':
1030         case 'E':
1031         case 'f':
1032         case 'F':
1033         case 'g':
1034         case 'G':
1035           if (*(formatter.fmt_cur - 1) == 'L') {
1036             retval = formatter.format(va_arg(ap, long double));
1037           } else {
1038             retval = formatter.format(va_arg(ap, double));
1039           }
1040           dfsan_set_label(*va_labels++, formatter.str_cur(),
1041                           formatter.num_written_bytes(retval));
1042           end_fmt = true;
1043           break;
1044 
1045         case 'c':
1046           retval = formatter.format(va_arg(ap, int));
1047           dfsan_set_label(*va_labels++, formatter.str_cur(),
1048                           formatter.num_written_bytes(retval));
1049           end_fmt = true;
1050           break;
1051 
1052         case 's': {
1053           char *arg = va_arg(ap, char *);
1054           retval = formatter.format(arg);
1055           va_labels++;
1056           internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
1057                           sizeof(dfsan_label) *
1058                               formatter.num_written_bytes(retval));
1059           end_fmt = true;
1060           break;
1061         }
1062 
1063         case 'p':
1064           retval = formatter.format(va_arg(ap, void *));
1065           dfsan_set_label(*va_labels++, formatter.str_cur(),
1066                           formatter.num_written_bytes(retval));
1067           end_fmt = true;
1068           break;
1069 
1070         case 'n': {
1071           int *ptr = va_arg(ap, int *);
1072           *ptr = (int)formatter.str_off;
1073           va_labels++;
1074           dfsan_set_label(0, ptr, sizeof(ptr));
1075           end_fmt = true;
1076           break;
1077         }
1078 
1079         case '%':
1080           retval = formatter.format();
1081           dfsan_set_label(0, formatter.str_cur(),
1082                           formatter.num_written_bytes(retval));
1083           end_fmt = true;
1084           break;
1085 
1086         case '*':
1087           formatter.width = va_arg(ap, int);
1088           va_labels++;
1089           break;
1090 
1091         default:
1092           break;
1093         }
1094       }
1095     }
1096 
1097     if (retval < 0) {
1098       return retval;
1099     }
1100 
1101     formatter.fmt_cur++;
1102     formatter.str_off += retval;
1103   }
1104 
1105   *ret_label = 0;
1106 
1107   // Number of bytes written in total.
1108   return formatter.str_off;
1109 }
1110 
1111 extern "C" {
1112 SANITIZER_INTERFACE_ATTRIBUTE
1113 int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
1114                    dfsan_label format_label, dfsan_label *va_labels,
1115                    dfsan_label *ret_label, ...) {
1116   va_list ap;
1117   va_start(ap, ret_label);
1118   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, ap);
1119   va_end(ap);
1120   return ret;
1121 }
1122 
1123 SANITIZER_INTERFACE_ATTRIBUTE
1124 int __dfsw_snprintf(char *str, size_t size, const char *format,
1125                     dfsan_label str_label, dfsan_label size_label,
1126                     dfsan_label format_label, dfsan_label *va_labels,
1127                     dfsan_label *ret_label, ...) {
1128   va_list ap;
1129   va_start(ap, ret_label);
1130   int ret = format_buffer(str, size, format, va_labels, ret_label, ap);
1131   va_end(ap);
1132   return ret;
1133 }
1134 
1135 // Default empty implementations (weak). Users should redefine them.
1136 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
1137 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
1138                              u32 *) {}
1139 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
1140 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
1141 
1142 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
1143 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
1144 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
1145 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
1146 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
1147 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
1148                              void) {}
1149 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
1150                              void) {}
1151 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
1152                              void) {}
1153 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
1154                              void) {}
1155 SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
1156 }  // extern "C"
1157