xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 74626c16ff489c0d64cf2843dfd522e7c544f3ce)
1fe6060f1SDimitry Andric //===-- dfsan_custom.cpp --------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of DataFlowSanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // This file defines the custom functions listed in done_abilist.txt.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include <arpa/inet.h>
1568d75effSDimitry Andric #include <assert.h>
1668d75effSDimitry Andric #include <ctype.h>
1768d75effSDimitry Andric #include <dlfcn.h>
1868d75effSDimitry Andric #include <link.h>
1968d75effSDimitry Andric #include <poll.h>
2068d75effSDimitry Andric #include <pthread.h>
2168d75effSDimitry Andric #include <pwd.h>
2268d75effSDimitry Andric #include <sched.h>
2368d75effSDimitry Andric #include <signal.h>
2468d75effSDimitry Andric #include <stdarg.h>
2568d75effSDimitry Andric #include <stdint.h>
2668d75effSDimitry Andric #include <stdio.h>
2768d75effSDimitry Andric #include <stdlib.h>
2868d75effSDimitry Andric #include <string.h>
29e8d8bef9SDimitry Andric #include <sys/epoll.h>
3068d75effSDimitry Andric #include <sys/resource.h>
3168d75effSDimitry Andric #include <sys/select.h>
32e8d8bef9SDimitry Andric #include <sys/socket.h>
3368d75effSDimitry Andric #include <sys/stat.h>
3468d75effSDimitry Andric #include <sys/time.h>
3568d75effSDimitry Andric #include <sys/types.h>
3668d75effSDimitry Andric #include <time.h>
3768d75effSDimitry Andric #include <unistd.h>
3868d75effSDimitry Andric 
39e8d8bef9SDimitry Andric #include "dfsan/dfsan.h"
40fe6060f1SDimitry Andric #include "dfsan/dfsan_chained_origin_depot.h"
41fe6060f1SDimitry Andric #include "dfsan/dfsan_flags.h"
42fe6060f1SDimitry Andric #include "dfsan/dfsan_thread.h"
43e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
44e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
45e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
46fe6060f1SDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
47e8d8bef9SDimitry Andric 
4868d75effSDimitry Andric using namespace __dfsan;
4968d75effSDimitry Andric 
5068d75effSDimitry Andric #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)                                     \
5168d75effSDimitry Andric   do {                                                                         \
5268d75effSDimitry Andric     if (f)                                                                     \
5368d75effSDimitry Andric       f(__VA_ARGS__);                                                          \
5468d75effSDimitry Andric   } while (false)
5568d75effSDimitry Andric #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
5668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
5768d75effSDimitry Andric 
58*74626c16SDimitry Andric #define WRAPPER_ALIAS(fun, real)                                          \
59*74626c16SDimitry Andric   SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_##fun() ALIAS(__dfsw_##real); \
60*74626c16SDimitry Andric   SANITIZER_INTERFACE_ATTRIBUTE void __dfso_##fun() ALIAS(__dfso_##real);
61*74626c16SDimitry Andric 
62fe6060f1SDimitry Andric // Async-safe, non-reentrant spin lock.
63fe6060f1SDimitry Andric class SignalSpinLocker {
64fe6060f1SDimitry Andric  public:
65fe6060f1SDimitry Andric   SignalSpinLocker() {
66fe6060f1SDimitry Andric     sigset_t all_set;
67fe6060f1SDimitry Andric     sigfillset(&all_set);
68fe6060f1SDimitry Andric     pthread_sigmask(SIG_SETMASK, &all_set, &saved_thread_mask_);
69fe6060f1SDimitry Andric     sigactions_mu.Lock();
70fe6060f1SDimitry Andric   }
71fe6060f1SDimitry Andric   ~SignalSpinLocker() {
72fe6060f1SDimitry Andric     sigactions_mu.Unlock();
73fe6060f1SDimitry Andric     pthread_sigmask(SIG_SETMASK, &saved_thread_mask_, nullptr);
74fe6060f1SDimitry Andric   }
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric  private:
77fe6060f1SDimitry Andric   static StaticSpinMutex sigactions_mu;
78fe6060f1SDimitry Andric   sigset_t saved_thread_mask_;
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric   SignalSpinLocker(const SignalSpinLocker &) = delete;
81fe6060f1SDimitry Andric   SignalSpinLocker &operator=(const SignalSpinLocker &) = delete;
82fe6060f1SDimitry Andric };
83fe6060f1SDimitry Andric 
84fe6060f1SDimitry Andric StaticSpinMutex SignalSpinLocker::sigactions_mu;
85fe6060f1SDimitry Andric 
8668d75effSDimitry Andric extern "C" {
8768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
8868d75effSDimitry Andric __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
8968d75effSDimitry Andric             dfsan_label buf_label, dfsan_label *ret_label) {
9068d75effSDimitry Andric   int ret = stat(path, buf);
9168d75effSDimitry Andric   if (ret == 0)
9268d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
9368d75effSDimitry Andric   *ret_label = 0;
9468d75effSDimitry Andric   return ret;
9568d75effSDimitry Andric }
9668d75effSDimitry Andric 
97fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_stat(
98fe6060f1SDimitry Andric     const char *path, struct stat *buf, dfsan_label path_label,
99fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label *ret_label, dfsan_origin path_origin,
100fe6060f1SDimitry Andric     dfsan_origin buf_origin, dfsan_origin *ret_origin) {
101fe6060f1SDimitry Andric   int ret = __dfsw_stat(path, buf, path_label, buf_label, ret_label);
102fe6060f1SDimitry Andric   return ret;
103fe6060f1SDimitry Andric }
104fe6060f1SDimitry Andric 
10568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
10668d75effSDimitry Andric                                                dfsan_label fd_label,
10768d75effSDimitry Andric                                                dfsan_label buf_label,
10868d75effSDimitry Andric                                                dfsan_label *ret_label) {
10968d75effSDimitry Andric   int ret = fstat(fd, buf);
11068d75effSDimitry Andric   if (ret == 0)
11168d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
11268d75effSDimitry Andric   *ret_label = 0;
11368d75effSDimitry Andric   return ret;
11468d75effSDimitry Andric }
11568d75effSDimitry Andric 
116fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_fstat(
117fe6060f1SDimitry Andric     int fd, struct stat *buf, dfsan_label fd_label, dfsan_label buf_label,
118fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
119fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
120fe6060f1SDimitry Andric   int ret = __dfsw_fstat(fd, buf, fd_label, buf_label, ret_label);
121fe6060f1SDimitry Andric   return ret;
122fe6060f1SDimitry Andric }
123fe6060f1SDimitry Andric 
124fe6060f1SDimitry Andric static char *dfsan_strchr_with_label(const char *s, int c, size_t *bytes_read,
125fe6060f1SDimitry Andric                                      dfsan_label s_label, dfsan_label c_label,
126fe6060f1SDimitry Andric                                      dfsan_label *ret_label) {
127fe6060f1SDimitry Andric   char *match_pos = nullptr;
128fe6060f1SDimitry Andric   for (size_t i = 0;; ++i) {
129fe6060f1SDimitry Andric     if (s[i] == c || s[i] == 0) {
130fe6060f1SDimitry Andric       // If s[i] is the \0 at the end of the string, and \0 is not the
131fe6060f1SDimitry Andric       // character we are searching for, then return null.
132fe6060f1SDimitry Andric       *bytes_read = i + 1;
133fe6060f1SDimitry Andric       match_pos = s[i] == 0 && c != 0 ? nullptr : const_cast<char *>(s + i);
134fe6060f1SDimitry Andric       break;
135fe6060f1SDimitry Andric     }
136fe6060f1SDimitry Andric   }
137fe6060f1SDimitry Andric   if (flags().strict_data_dependencies)
138fe6060f1SDimitry Andric     *ret_label = s_label;
139fe6060f1SDimitry Andric   else
140fe6060f1SDimitry Andric     *ret_label = dfsan_union(dfsan_read_label(s, *bytes_read),
141fe6060f1SDimitry Andric                              dfsan_union(s_label, c_label));
142fe6060f1SDimitry Andric   return match_pos;
143fe6060f1SDimitry Andric }
144fe6060f1SDimitry Andric 
14568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
14668d75effSDimitry Andric                                                   dfsan_label s_label,
14768d75effSDimitry Andric                                                   dfsan_label c_label,
14868d75effSDimitry Andric                                                   dfsan_label *ret_label) {
149fe6060f1SDimitry Andric   size_t bytes_read;
150fe6060f1SDimitry Andric   return dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label,
151fe6060f1SDimitry Andric                                  ret_label);
15268d75effSDimitry Andric }
1535ffd83dbSDimitry Andric 
154fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strchr(
155fe6060f1SDimitry Andric     const char *s, int c, dfsan_label s_label, dfsan_label c_label,
156fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
157fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
158fe6060f1SDimitry Andric   size_t bytes_read;
159fe6060f1SDimitry Andric   char *r =
160fe6060f1SDimitry Andric       dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label, ret_label);
161fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
162fe6060f1SDimitry Andric     *ret_origin = s_origin;
163fe6060f1SDimitry Andric   } else if (*ret_label) {
164fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, bytes_read);
165fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1665ffd83dbSDimitry Andric   }
167fe6060f1SDimitry Andric   return r;
16868d75effSDimitry Andric }
16968d75effSDimitry Andric 
170e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strpbrk(const char *s,
171e8d8bef9SDimitry Andric                                                    const char *accept,
172e8d8bef9SDimitry Andric                                                    dfsan_label s_label,
173e8d8bef9SDimitry Andric                                                    dfsan_label accept_label,
17468d75effSDimitry Andric                                                    dfsan_label *ret_label) {
175e8d8bef9SDimitry Andric   const char *ret = strpbrk(s, accept);
176e8d8bef9SDimitry Andric   if (flags().strict_data_dependencies) {
177e8d8bef9SDimitry Andric     *ret_label = ret ? s_label : 0;
178e8d8bef9SDimitry Andric   } else {
179e8d8bef9SDimitry Andric     size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
180e8d8bef9SDimitry Andric     *ret_label =
181e8d8bef9SDimitry Andric         dfsan_union(dfsan_read_label(s, s_bytes_read),
182e8d8bef9SDimitry Andric                     dfsan_union(dfsan_read_label(accept, strlen(accept) + 1),
183e8d8bef9SDimitry Andric                                 dfsan_union(s_label, accept_label)));
184e8d8bef9SDimitry Andric   }
185e8d8bef9SDimitry Andric   return const_cast<char *>(ret);
186e8d8bef9SDimitry Andric }
187e8d8bef9SDimitry Andric 
188fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strpbrk(
189fe6060f1SDimitry Andric     const char *s, const char *accept, dfsan_label s_label,
190fe6060f1SDimitry Andric     dfsan_label accept_label, dfsan_label *ret_label, dfsan_origin s_origin,
191fe6060f1SDimitry Andric     dfsan_origin accept_origin, dfsan_origin *ret_origin) {
192fe6060f1SDimitry Andric   const char *ret = __dfsw_strpbrk(s, accept, s_label, accept_label, ret_label);
193fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
194fe6060f1SDimitry Andric     if (ret)
195fe6060f1SDimitry Andric       *ret_origin = s_origin;
196fe6060f1SDimitry Andric   } else {
197fe6060f1SDimitry Andric     if (*ret_label) {
198fe6060f1SDimitry Andric       size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
199fe6060f1SDimitry Andric       dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_bytes_read);
200fe6060f1SDimitry Andric       if (o) {
201fe6060f1SDimitry Andric         *ret_origin = o;
202fe6060f1SDimitry Andric       } else {
203fe6060f1SDimitry Andric         o = dfsan_read_origin_of_first_taint(accept, strlen(accept) + 1);
204fe6060f1SDimitry Andric         *ret_origin = o ? o : (s_label ? s_origin : accept_origin);
205fe6060f1SDimitry Andric       }
206fe6060f1SDimitry Andric     }
207fe6060f1SDimitry Andric   }
208fe6060f1SDimitry Andric   return const_cast<char *>(ret);
209fe6060f1SDimitry Andric }
210fe6060f1SDimitry Andric 
21106c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strsep(char **s, const char *delim,
21206c3fb27SDimitry Andric                                                   dfsan_label s_label,
21306c3fb27SDimitry Andric                                                   dfsan_label delim_label,
21406c3fb27SDimitry Andric                                                   dfsan_label *ret_label) {
21506c3fb27SDimitry Andric   dfsan_label base_label = dfsan_read_label(s, sizeof(*s));
21606c3fb27SDimitry Andric   char *base = *s;
21706c3fb27SDimitry Andric   char *res = strsep(s, delim);
21806c3fb27SDimitry Andric   if (res != *s) {
21906c3fb27SDimitry Andric     char *token_start = res;
22006c3fb27SDimitry Andric     int token_length = strlen(res);
22106c3fb27SDimitry Andric     // the delimiter byte has been set to NULL
22206c3fb27SDimitry Andric     dfsan_set_label(0, token_start + token_length, 1);
22306c3fb27SDimitry Andric   }
22406c3fb27SDimitry Andric 
22506c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
22606c3fb27SDimitry Andric     *ret_label = res ? base_label : 0;
22706c3fb27SDimitry Andric   } else {
22806c3fb27SDimitry Andric     size_t s_bytes_read = (res ? strlen(res) : strlen(base)) + 1;
22906c3fb27SDimitry Andric     *ret_label = dfsan_union(
23006c3fb27SDimitry Andric         dfsan_union(base_label, dfsan_read_label(base, sizeof(s_bytes_read))),
23106c3fb27SDimitry Andric         dfsan_union(dfsan_read_label(delim, strlen(delim) + 1),
23206c3fb27SDimitry Andric                     dfsan_union(s_label, delim_label)));
23306c3fb27SDimitry Andric   }
23406c3fb27SDimitry Andric 
23506c3fb27SDimitry Andric   return res;
23606c3fb27SDimitry Andric }
23706c3fb27SDimitry Andric 
23806c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strsep(
23906c3fb27SDimitry Andric     char **s, const char *delim, dfsan_label s_label, dfsan_label delim_label,
24006c3fb27SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin delim_origin,
24106c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
24206c3fb27SDimitry Andric   dfsan_origin base_origin = dfsan_read_origin_of_first_taint(s, sizeof(*s));
24306c3fb27SDimitry Andric   char *res = __dfsw_strsep(s, delim, s_label, delim_label, ret_label);
24406c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
24506c3fb27SDimitry Andric     if (res)
24606c3fb27SDimitry Andric       *ret_origin = base_origin;
24706c3fb27SDimitry Andric   } else {
24806c3fb27SDimitry Andric     if (*ret_label) {
24906c3fb27SDimitry Andric       if (base_origin) {
25006c3fb27SDimitry Andric         *ret_origin = base_origin;
25106c3fb27SDimitry Andric       } else {
25206c3fb27SDimitry Andric         dfsan_origin o =
25306c3fb27SDimitry Andric             dfsan_read_origin_of_first_taint(delim, strlen(delim) + 1);
25406c3fb27SDimitry Andric         *ret_origin = o ? o : (s_label ? s_origin : delim_origin);
25506c3fb27SDimitry Andric       }
25606c3fb27SDimitry Andric     }
25706c3fb27SDimitry Andric   }
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric   return res;
26006c3fb27SDimitry Andric }
26106c3fb27SDimitry Andric 
262e8d8bef9SDimitry Andric static int dfsan_memcmp_bcmp(const void *s1, const void *s2, size_t n,
263fe6060f1SDimitry Andric                              size_t *bytes_read) {
26468d75effSDimitry Andric   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
26568d75effSDimitry Andric   for (size_t i = 0; i != n; ++i) {
26668d75effSDimitry Andric     if (cs1[i] != cs2[i]) {
267fe6060f1SDimitry Andric       *bytes_read = i + 1;
26868d75effSDimitry Andric       return cs1[i] - cs2[i];
26968d75effSDimitry Andric     }
27068d75effSDimitry Andric   }
271fe6060f1SDimitry Andric   *bytes_read = n;
27268d75effSDimitry Andric   return 0;
27368d75effSDimitry Andric }
27468d75effSDimitry Andric 
275fe6060f1SDimitry Andric static dfsan_label dfsan_get_memcmp_label(const void *s1, const void *s2,
276fe6060f1SDimitry Andric                                           size_t pos) {
277fe6060f1SDimitry Andric   if (flags().strict_data_dependencies)
278fe6060f1SDimitry Andric     return 0;
279fe6060f1SDimitry Andric   return dfsan_union(dfsan_read_label(s1, pos), dfsan_read_label(s2, pos));
280fe6060f1SDimitry Andric }
281fe6060f1SDimitry Andric 
282fe6060f1SDimitry Andric static void dfsan_get_memcmp_origin(const void *s1, const void *s2, size_t pos,
283fe6060f1SDimitry Andric                                     dfsan_label *ret_label,
284fe6060f1SDimitry Andric                                     dfsan_origin *ret_origin) {
285fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, pos);
286fe6060f1SDimitry Andric   if (*ret_label == 0)
287fe6060f1SDimitry Andric     return;
288fe6060f1SDimitry Andric   dfsan_origin o = dfsan_read_origin_of_first_taint(s1, pos);
289fe6060f1SDimitry Andric   *ret_origin = o ? o : dfsan_read_origin_of_first_taint(s2, pos);
290fe6060f1SDimitry Andric }
291fe6060f1SDimitry Andric 
292fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_label(const void *s1, const void *s2, size_t n,
293fe6060f1SDimitry Andric                                    dfsan_label *ret_label) {
294fe6060f1SDimitry Andric   size_t bytes_read;
295fe6060f1SDimitry Andric   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
296fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
297fe6060f1SDimitry Andric   return r;
298fe6060f1SDimitry Andric }
299fe6060f1SDimitry Andric 
300fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_origin(const void *s1, const void *s2, size_t n,
301fe6060f1SDimitry Andric                                     dfsan_label *ret_label,
302fe6060f1SDimitry Andric                                     dfsan_origin *ret_origin) {
303fe6060f1SDimitry Andric   size_t bytes_read;
304fe6060f1SDimitry Andric   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
305fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
306fe6060f1SDimitry Andric   return r;
307fe6060f1SDimitry Andric }
308fe6060f1SDimitry Andric 
309e8d8bef9SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
310e8d8bef9SDimitry Andric                               const void *s1, const void *s2, size_t n,
311e8d8bef9SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
312e8d8bef9SDimitry Andric                               dfsan_label n_label)
313e8d8bef9SDimitry Andric 
314fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, uptr caller_pc,
315fe6060f1SDimitry Andric                               const void *s1, const void *s2, size_t n,
316fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
317fe6060f1SDimitry Andric                               dfsan_label n_label, dfsan_origin s1_origin,
318fe6060f1SDimitry Andric                               dfsan_origin s2_origin, dfsan_origin n_origin)
319fe6060f1SDimitry Andric 
320e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
321e8d8bef9SDimitry Andric                                                 size_t n, dfsan_label s1_label,
322e8d8bef9SDimitry Andric                                                 dfsan_label s2_label,
323e8d8bef9SDimitry Andric                                                 dfsan_label n_label,
324e8d8bef9SDimitry Andric                                                 dfsan_label *ret_label) {
325e8d8bef9SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
326e8d8bef9SDimitry Andric                              s1_label, s2_label, n_label);
327fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
328fe6060f1SDimitry Andric }
329fe6060f1SDimitry Andric 
330fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_memcmp(
331fe6060f1SDimitry Andric     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
332fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
333fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
334fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
335fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, GET_CALLER_PC(), s1,
336fe6060f1SDimitry Andric                              s2, n, s1_label, s2_label, n_label, s1_origin,
337fe6060f1SDimitry Andric                              s2_origin, n_origin);
338fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
339e8d8bef9SDimitry Andric }
340e8d8bef9SDimitry Andric 
341e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_bcmp(const void *s1, const void *s2,
342e8d8bef9SDimitry Andric                                               size_t n, dfsan_label s1_label,
343e8d8bef9SDimitry Andric                                               dfsan_label s2_label,
344e8d8bef9SDimitry Andric                                               dfsan_label n_label,
345e8d8bef9SDimitry Andric                                               dfsan_label *ret_label) {
346fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
347fe6060f1SDimitry Andric }
348fe6060f1SDimitry Andric 
349fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_bcmp(
350fe6060f1SDimitry Andric     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
351fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
352fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
353fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
354fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
355fe6060f1SDimitry Andric }
356fe6060f1SDimitry Andric 
357fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit.
358fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2.
359fe6060f1SDimitry Andric static int dfsan_strncmp(const char *s1, const char *s2, size_t n,
360fe6060f1SDimitry Andric                          size_t *bytes_read) {
361fe6060f1SDimitry Andric   for (size_t i = 0;; ++i) {
362fe6060f1SDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || (n > 0 && i == n - 1)) {
363fe6060f1SDimitry Andric       *bytes_read = i + 1;
364fe6060f1SDimitry Andric       return s1[i] - s2[i];
365fe6060f1SDimitry Andric     }
366fe6060f1SDimitry Andric   }
367e8d8bef9SDimitry Andric }
368e8d8bef9SDimitry Andric 
36968d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
37068d75effSDimitry Andric                               const char *s1, const char *s2,
37168d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label)
37268d75effSDimitry Andric 
373fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, uptr caller_pc,
374fe6060f1SDimitry Andric                               const char *s1, const char *s2,
375fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
376fe6060f1SDimitry Andric                               dfsan_origin s1_origin, dfsan_origin s2_origin)
377fe6060f1SDimitry Andric 
37868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
37968d75effSDimitry Andric                                                 dfsan_label s1_label,
38068d75effSDimitry Andric                                                 dfsan_label s2_label,
38168d75effSDimitry Andric                                                 dfsan_label *ret_label) {
38268d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
38368d75effSDimitry Andric                              s1_label, s2_label);
384fe6060f1SDimitry Andric   size_t bytes_read;
385fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
386fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
387fe6060f1SDimitry Andric   return r;
38868d75effSDimitry Andric }
38968d75effSDimitry Andric 
390fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcmp(
391fe6060f1SDimitry Andric     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
392fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
393fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
394fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, GET_CALLER_PC(), s1,
395fe6060f1SDimitry Andric                              s2, s1_label, s2_label, s1_origin, s2_origin);
396fe6060f1SDimitry Andric   size_t bytes_read;
397fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
398fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
399fe6060f1SDimitry Andric   return r;
400fe6060f1SDimitry Andric }
401fe6060f1SDimitry Andric 
402fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit.
403fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2.
404fe6060f1SDimitry Andric static int dfsan_strncasecmp(const char *s1, const char *s2, size_t n,
405fe6060f1SDimitry Andric                              size_t *bytes_read) {
40668d75effSDimitry Andric   for (size_t i = 0;; ++i) {
4075ffd83dbSDimitry Andric     char s1_lower = tolower(s1[i]);
4085ffd83dbSDimitry Andric     char s2_lower = tolower(s2[i]);
4095ffd83dbSDimitry Andric 
410fe6060f1SDimitry Andric     if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0 ||
411fe6060f1SDimitry Andric         (n > 0 && i == n - 1)) {
412fe6060f1SDimitry Andric       *bytes_read = i + 1;
4135ffd83dbSDimitry Andric       return s1_lower - s2_lower;
41468d75effSDimitry Andric     }
41568d75effSDimitry Andric   }
416fe6060f1SDimitry Andric }
417fe6060f1SDimitry Andric 
418fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcasecmp(const char *s1,
419fe6060f1SDimitry Andric                                                     const char *s2,
420fe6060f1SDimitry Andric                                                     dfsan_label s1_label,
421fe6060f1SDimitry Andric                                                     dfsan_label s2_label,
422fe6060f1SDimitry Andric                                                     dfsan_label *ret_label) {
423fe6060f1SDimitry Andric   size_t bytes_read;
424fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
425fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
426fe6060f1SDimitry Andric   return r;
427fe6060f1SDimitry Andric }
428fe6060f1SDimitry Andric 
429fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcasecmp(
430fe6060f1SDimitry Andric     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
431fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
432fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
433fe6060f1SDimitry Andric   size_t bytes_read;
434fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
435fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
436fe6060f1SDimitry Andric   return r;
43768d75effSDimitry Andric }
43868d75effSDimitry Andric 
43968d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
44068d75effSDimitry Andric                               const char *s1, const char *s2, size_t n,
44168d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
44268d75effSDimitry Andric                               dfsan_label n_label)
44368d75effSDimitry Andric 
444fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, uptr caller_pc,
445fe6060f1SDimitry Andric                               const char *s1, const char *s2, size_t n,
446fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
447fe6060f1SDimitry Andric                               dfsan_label n_label, dfsan_origin s1_origin,
448fe6060f1SDimitry Andric                               dfsan_origin s2_origin, dfsan_origin n_origin)
449fe6060f1SDimitry Andric 
45068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
45168d75effSDimitry Andric                                                  size_t n, dfsan_label s1_label,
45268d75effSDimitry Andric                                                  dfsan_label s2_label,
45368d75effSDimitry Andric                                                  dfsan_label n_label,
45468d75effSDimitry Andric                                                  dfsan_label *ret_label) {
45568d75effSDimitry Andric   if (n == 0) {
45668d75effSDimitry Andric     *ret_label = 0;
45768d75effSDimitry Andric     return 0;
45868d75effSDimitry Andric   }
45968d75effSDimitry Andric 
46068d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
46168d75effSDimitry Andric                              n, s1_label, s2_label, n_label);
46268d75effSDimitry Andric 
463fe6060f1SDimitry Andric   size_t bytes_read;
464fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
465fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
466fe6060f1SDimitry Andric   return r;
46768d75effSDimitry Andric }
46868d75effSDimitry Andric 
469fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncmp(
470fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
471fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
472fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
473fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
47468d75effSDimitry Andric   if (n == 0) {
47568d75effSDimitry Andric     *ret_label = 0;
47668d75effSDimitry Andric     return 0;
47768d75effSDimitry Andric   }
47868d75effSDimitry Andric 
479fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, GET_CALLER_PC(),
480fe6060f1SDimitry Andric                              s1, s2, n, s1_label, s2_label, n_label, s1_origin,
481fe6060f1SDimitry Andric                              s2_origin, n_origin);
4825ffd83dbSDimitry Andric 
483fe6060f1SDimitry Andric   size_t bytes_read;
484fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
485fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
486fe6060f1SDimitry Andric   return r;
487fe6060f1SDimitry Andric }
488fe6060f1SDimitry Andric 
489fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncasecmp(
490fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
491fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) {
492fe6060f1SDimitry Andric   if (n == 0) {
49368d75effSDimitry Andric     *ret_label = 0;
49468d75effSDimitry Andric     return 0;
49568d75effSDimitry Andric   }
49668d75effSDimitry Andric 
497fe6060f1SDimitry Andric   size_t bytes_read;
498fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
499fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
500fe6060f1SDimitry Andric   return r;
50168d75effSDimitry Andric }
50268d75effSDimitry Andric 
503fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncasecmp(
504fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
505fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
506fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
507fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
508fe6060f1SDimitry Andric   if (n == 0) {
509fe6060f1SDimitry Andric     *ret_label = 0;
510fe6060f1SDimitry Andric     return 0;
511fe6060f1SDimitry Andric   }
512fe6060f1SDimitry Andric 
513fe6060f1SDimitry Andric   size_t bytes_read;
514fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
515fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
516fe6060f1SDimitry Andric   return r;
517fe6060f1SDimitry Andric }
518fe6060f1SDimitry Andric 
519fe6060f1SDimitry Andric 
52068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t
52168d75effSDimitry Andric __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
52268d75effSDimitry Andric   size_t ret = strlen(s);
52368d75effSDimitry Andric   if (flags().strict_data_dependencies) {
52468d75effSDimitry Andric     *ret_label = 0;
52568d75effSDimitry Andric   } else {
52668d75effSDimitry Andric     *ret_label = dfsan_read_label(s, ret + 1);
52768d75effSDimitry Andric   }
52868d75effSDimitry Andric   return ret;
52968d75effSDimitry Andric }
53068d75effSDimitry Andric 
531fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s,
532fe6060f1SDimitry Andric                                                    dfsan_label s_label,
533fe6060f1SDimitry Andric                                                    dfsan_label *ret_label,
534fe6060f1SDimitry Andric                                                    dfsan_origin s_origin,
535fe6060f1SDimitry Andric                                                    dfsan_origin *ret_origin) {
536fe6060f1SDimitry Andric   size_t ret = __dfsw_strlen(s, s_label, ret_label);
537fe6060f1SDimitry Andric   if (!flags().strict_data_dependencies)
538fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1);
539fe6060f1SDimitry Andric   return ret;
540fe6060f1SDimitry Andric }
541fe6060f1SDimitry Andric 
54206c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strnlen(const char *s,
54306c3fb27SDimitry Andric                                                     size_t maxlen,
54406c3fb27SDimitry Andric                                                     dfsan_label s_label,
54506c3fb27SDimitry Andric                                                     dfsan_label maxlen_label,
54606c3fb27SDimitry Andric                                                     dfsan_label *ret_label) {
54706c3fb27SDimitry Andric   size_t ret = strnlen(s, maxlen);
54806c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
54906c3fb27SDimitry Andric     *ret_label = 0;
55006c3fb27SDimitry Andric   } else {
55106c3fb27SDimitry Andric     size_t full_len = strlen(s);
55206c3fb27SDimitry Andric     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
55306c3fb27SDimitry Andric     *ret_label = dfsan_union(maxlen_label, dfsan_read_label(s, covered_len));
55406c3fb27SDimitry Andric   }
55506c3fb27SDimitry Andric   return ret;
55606c3fb27SDimitry Andric }
55706c3fb27SDimitry Andric 
55806c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strnlen(
55906c3fb27SDimitry Andric     const char *s, size_t maxlen, dfsan_label s_label, dfsan_label maxlen_label,
56006c3fb27SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin maxlen_origin,
56106c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
56206c3fb27SDimitry Andric   size_t ret = __dfsw_strnlen(s, maxlen, s_label, maxlen_label, ret_label);
56306c3fb27SDimitry Andric   if (!flags().strict_data_dependencies) {
56406c3fb27SDimitry Andric     size_t full_len = strlen(s);
56506c3fb27SDimitry Andric     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
56606c3fb27SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, covered_len);
56706c3fb27SDimitry Andric     *ret_origin = o ? o : maxlen_origin;
56806c3fb27SDimitry Andric   }
56906c3fb27SDimitry Andric   return ret;
57006c3fb27SDimitry Andric }
57106c3fb27SDimitry Andric 
572fe6060f1SDimitry Andric static void *dfsan_memmove(void *dest, const void *src, size_t n) {
573fe6060f1SDimitry Andric   dfsan_label *sdest = shadow_for(dest);
574fe6060f1SDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
575fe6060f1SDimitry Andric   internal_memmove((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
576fe6060f1SDimitry Andric   return internal_memmove(dest, src, n);
577fe6060f1SDimitry Andric }
578fe6060f1SDimitry Andric 
579fe6060f1SDimitry Andric static void *dfsan_memmove_with_origin(void *dest, const void *src, size_t n) {
580fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
581fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
582fe6060f1SDimitry Andric }
58368d75effSDimitry Andric 
58468d75effSDimitry Andric static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
58504eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest, src, n);
58668d75effSDimitry Andric   return internal_memcpy(dest, src, n);
58768d75effSDimitry Andric }
58868d75effSDimitry Andric 
589fe6060f1SDimitry Andric static void *dfsan_memcpy_with_origin(void *dest, const void *src, size_t n) {
590fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
591fe6060f1SDimitry Andric   return dfsan_memcpy(dest, src, n);
592fe6060f1SDimitry Andric }
593fe6060f1SDimitry Andric 
59468d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
59568d75effSDimitry Andric   internal_memset(s, c, n);
59668d75effSDimitry Andric   dfsan_set_label(c_label, s, n);
59768d75effSDimitry Andric }
59868d75effSDimitry Andric 
599fe6060f1SDimitry Andric static void dfsan_memset_with_origin(void *s, int c, dfsan_label c_label,
600fe6060f1SDimitry Andric                                      dfsan_origin c_origin, size_t n) {
601fe6060f1SDimitry Andric   internal_memset(s, c, n);
602fe6060f1SDimitry Andric   dfsan_set_label_origin(c_label, c_origin, s, n);
603fe6060f1SDimitry Andric }
604fe6060f1SDimitry Andric 
60568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
60668d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n,
60768d75effSDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
60868d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
60968d75effSDimitry Andric   *ret_label = dest_label;
61068d75effSDimitry Andric   return dfsan_memcpy(dest, src, n);
61168d75effSDimitry Andric }
61268d75effSDimitry Andric 
61368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
614fe6060f1SDimitry Andric void *__dfso_memcpy(void *dest, const void *src, size_t n,
615fe6060f1SDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
616fe6060f1SDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label,
617fe6060f1SDimitry Andric                     dfsan_origin dest_origin, dfsan_origin src_origin,
618fe6060f1SDimitry Andric                     dfsan_origin n_origin, dfsan_origin *ret_origin) {
619fe6060f1SDimitry Andric   *ret_label = dest_label;
620fe6060f1SDimitry Andric   *ret_origin = dest_origin;
621fe6060f1SDimitry Andric   return dfsan_memcpy_with_origin(dest, src, n);
622fe6060f1SDimitry Andric }
623fe6060f1SDimitry Andric 
624fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
625fe6060f1SDimitry Andric void *__dfsw_memmove(void *dest, const void *src, size_t n,
626fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
627fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label) {
628fe6060f1SDimitry Andric   *ret_label = dest_label;
629fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
630fe6060f1SDimitry Andric }
631fe6060f1SDimitry Andric 
632fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
633fe6060f1SDimitry Andric void *__dfso_memmove(void *dest, const void *src, size_t n,
634fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
635fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label,
636fe6060f1SDimitry Andric                      dfsan_origin dest_origin, dfsan_origin src_origin,
637fe6060f1SDimitry Andric                      dfsan_origin n_origin, dfsan_origin *ret_origin) {
638fe6060f1SDimitry Andric   *ret_label = dest_label;
639fe6060f1SDimitry Andric   *ret_origin = dest_origin;
640fe6060f1SDimitry Andric   return dfsan_memmove_with_origin(dest, src, n);
641fe6060f1SDimitry Andric }
642fe6060f1SDimitry Andric 
643fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
64468d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n,
64568d75effSDimitry Andric                     dfsan_label s_label, dfsan_label c_label,
64668d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
64768d75effSDimitry Andric   dfsan_memset(s, c, c_label, n);
64868d75effSDimitry Andric   *ret_label = s_label;
64968d75effSDimitry Andric   return s;
65068d75effSDimitry Andric }
65168d75effSDimitry Andric 
652fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
653fe6060f1SDimitry Andric void *__dfso_memset(void *s, int c, size_t n, dfsan_label s_label,
654fe6060f1SDimitry Andric                     dfsan_label c_label, dfsan_label n_label,
655fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin s_origin,
656fe6060f1SDimitry Andric                     dfsan_origin c_origin, dfsan_origin n_origin,
657fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
658fe6060f1SDimitry Andric   dfsan_memset_with_origin(s, c, c_label, c_origin, n);
659fe6060f1SDimitry Andric   *ret_label = s_label;
660fe6060f1SDimitry Andric   *ret_origin = s_origin;
661fe6060f1SDimitry Andric   return s;
662fe6060f1SDimitry Andric }
663fe6060f1SDimitry Andric 
664fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src,
665fe6060f1SDimitry Andric                                                   dfsan_label dest_label,
666fe6060f1SDimitry Andric                                                   dfsan_label src_label,
667fe6060f1SDimitry Andric                                                   dfsan_label *ret_label) {
668fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
669349cc55cSDimitry Andric   char *ret = strcat(dest, src);
67004eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, strlen(src));
671fe6060f1SDimitry Andric   *ret_label = dest_label;
672fe6060f1SDimitry Andric   return ret;
673fe6060f1SDimitry Andric }
674fe6060f1SDimitry Andric 
675fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat(
676fe6060f1SDimitry Andric     char *dest, const char *src, dfsan_label dest_label, dfsan_label src_label,
677fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin,
678fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
679fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
680349cc55cSDimitry Andric   char *ret = strcat(dest, src);
681fe6060f1SDimitry Andric   size_t src_len = strlen(src);
682fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
68304eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
684fe6060f1SDimitry Andric   *ret_label = dest_label;
685fe6060f1SDimitry Andric   *ret_origin = dest_origin;
686fe6060f1SDimitry Andric   return ret;
687fe6060f1SDimitry Andric }
688fe6060f1SDimitry Andric 
68906c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strncat(
69006c3fb27SDimitry Andric     char *dest, const char *src, size_t num, dfsan_label dest_label,
69106c3fb27SDimitry Andric     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label) {
69206c3fb27SDimitry Andric   size_t src_len = strlen(src);
69306c3fb27SDimitry Andric   src_len = src_len < num ? src_len : num;
69406c3fb27SDimitry Andric   size_t dest_len = strlen(dest);
69506c3fb27SDimitry Andric 
69606c3fb27SDimitry Andric   char *ret = strncat(dest, src, num);
69706c3fb27SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
69806c3fb27SDimitry Andric   *ret_label = dest_label;
69906c3fb27SDimitry Andric   return ret;
70006c3fb27SDimitry Andric }
70106c3fb27SDimitry Andric 
70206c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncat(
70306c3fb27SDimitry Andric     char *dest, const char *src, size_t num, dfsan_label dest_label,
70406c3fb27SDimitry Andric     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label,
70506c3fb27SDimitry Andric     dfsan_origin dest_origin, dfsan_origin src_origin, dfsan_origin num_origin,
70606c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
70706c3fb27SDimitry Andric   size_t src_len = strlen(src);
70806c3fb27SDimitry Andric   src_len = src_len < num ? src_len : num;
70906c3fb27SDimitry Andric   size_t dest_len = strlen(dest);
71006c3fb27SDimitry Andric 
71106c3fb27SDimitry Andric   char *ret = strncat(dest, src, num);
71206c3fb27SDimitry Andric 
71306c3fb27SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
71406c3fb27SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
71506c3fb27SDimitry Andric   *ret_label = dest_label;
71606c3fb27SDimitry Andric   *ret_origin = dest_origin;
71706c3fb27SDimitry Andric   return ret;
71806c3fb27SDimitry Andric }
71906c3fb27SDimitry Andric 
72068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
72168d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
72268d75effSDimitry Andric   size_t len = strlen(s);
72368d75effSDimitry Andric   void *p = malloc(len+1);
72468d75effSDimitry Andric   dfsan_memcpy(p, s, len+1);
72568d75effSDimitry Andric   *ret_label = 0;
72668d75effSDimitry Andric   return static_cast<char *>(p);
72768d75effSDimitry Andric }
72868d75effSDimitry Andric 
729fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strdup(const char *s,
730fe6060f1SDimitry Andric                                                   dfsan_label s_label,
731fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
732fe6060f1SDimitry Andric                                                   dfsan_origin s_origin,
733fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
734fe6060f1SDimitry Andric   size_t len = strlen(s);
735fe6060f1SDimitry Andric   void *p = malloc(len + 1);
736fe6060f1SDimitry Andric   dfsan_memcpy_with_origin(p, s, len + 1);
737fe6060f1SDimitry Andric   *ret_label = 0;
738fe6060f1SDimitry Andric   return static_cast<char *>(p);
739fe6060f1SDimitry Andric }
740fe6060f1SDimitry Andric 
74168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
74268d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
74368d75effSDimitry Andric                dfsan_label s2_label, dfsan_label n_label,
74468d75effSDimitry Andric                dfsan_label *ret_label) {
74568d75effSDimitry Andric   size_t len = strlen(s2);
74668d75effSDimitry Andric   if (len < n) {
74768d75effSDimitry Andric     dfsan_memcpy(s1, s2, len+1);
74868d75effSDimitry Andric     dfsan_memset(s1+len+1, 0, 0, n-len-1);
74968d75effSDimitry Andric   } else {
75068d75effSDimitry Andric     dfsan_memcpy(s1, s2, n);
75168d75effSDimitry Andric   }
75268d75effSDimitry Andric 
75368d75effSDimitry Andric   *ret_label = s1_label;
75468d75effSDimitry Andric   return s1;
75568d75effSDimitry Andric }
75668d75effSDimitry Andric 
757fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncpy(
758fe6060f1SDimitry Andric     char *s1, const char *s2, size_t n, dfsan_label s1_label,
759fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
760fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
761fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
762fe6060f1SDimitry Andric   size_t len = strlen(s2);
763fe6060f1SDimitry Andric   if (len < n) {
764fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, len + 1);
765fe6060f1SDimitry Andric     dfsan_memset_with_origin(s1 + len + 1, 0, 0, 0, n - len - 1);
766fe6060f1SDimitry Andric   } else {
767fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, n);
768fe6060f1SDimitry Andric   }
769fe6060f1SDimitry Andric 
770fe6060f1SDimitry Andric   *ret_label = s1_label;
771fe6060f1SDimitry Andric   *ret_origin = s1_origin;
772fe6060f1SDimitry Andric   return s1;
773fe6060f1SDimitry Andric }
774fe6060f1SDimitry Andric 
77568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
77668d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
77768d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
77868d75effSDimitry Andric              dfsan_label count_label, dfsan_label offset_label,
77968d75effSDimitry Andric              dfsan_label *ret_label) {
78068d75effSDimitry Andric   ssize_t ret = pread(fd, buf, count, offset);
78168d75effSDimitry Andric   if (ret > 0)
78268d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
78368d75effSDimitry Andric   *ret_label = 0;
78468d75effSDimitry Andric   return ret;
78568d75effSDimitry Andric }
78668d75effSDimitry Andric 
787fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_pread(
788fe6060f1SDimitry Andric     int fd, void *buf, size_t count, off_t offset, dfsan_label fd_label,
789fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label offset_label,
790fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
791fe6060f1SDimitry Andric     dfsan_origin count_origin, dfsan_label offset_origin,
792fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
793fe6060f1SDimitry Andric   return __dfsw_pread(fd, buf, count, offset, fd_label, buf_label, count_label,
794fe6060f1SDimitry Andric                       offset_label, ret_label);
795fe6060f1SDimitry Andric }
796fe6060f1SDimitry Andric 
79768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
79868d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count,
79968d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
80068d75effSDimitry Andric              dfsan_label count_label,
80168d75effSDimitry Andric              dfsan_label *ret_label) {
80268d75effSDimitry Andric   ssize_t ret = read(fd, buf, count);
80368d75effSDimitry Andric   if (ret > 0)
80468d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
80568d75effSDimitry Andric   *ret_label = 0;
80668d75effSDimitry Andric   return ret;
80768d75effSDimitry Andric }
80868d75effSDimitry Andric 
809fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_read(
810fe6060f1SDimitry Andric     int fd, void *buf, size_t count, dfsan_label fd_label,
811fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
812fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
813fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
814fe6060f1SDimitry Andric   return __dfsw_read(fd, buf, count, fd_label, buf_label, count_label,
815fe6060f1SDimitry Andric                      ret_label);
816fe6060f1SDimitry Andric }
817fe6060f1SDimitry Andric 
81868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
81968d75effSDimitry Andric                                                        struct timespec *tp,
82068d75effSDimitry Andric                                                        dfsan_label clk_id_label,
82168d75effSDimitry Andric                                                        dfsan_label tp_label,
82268d75effSDimitry Andric                                                        dfsan_label *ret_label) {
82368d75effSDimitry Andric   int ret = clock_gettime(clk_id, tp);
82468d75effSDimitry Andric   if (ret == 0)
82568d75effSDimitry Andric     dfsan_set_label(0, tp, sizeof(struct timespec));
82668d75effSDimitry Andric   *ret_label = 0;
82768d75effSDimitry Andric   return ret;
82868d75effSDimitry Andric }
82968d75effSDimitry Andric 
830fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_clock_gettime(
831fe6060f1SDimitry Andric     clockid_t clk_id, struct timespec *tp, dfsan_label clk_id_label,
832fe6060f1SDimitry Andric     dfsan_label tp_label, dfsan_label *ret_label, dfsan_origin clk_id_origin,
833fe6060f1SDimitry Andric     dfsan_origin tp_origin, dfsan_origin *ret_origin) {
834fe6060f1SDimitry Andric   return __dfsw_clock_gettime(clk_id, tp, clk_id_label, tp_label, ret_label);
835fe6060f1SDimitry Andric }
836fe6060f1SDimitry Andric 
837fe6060f1SDimitry Andric static void dfsan_set_zero_label(const void *ptr, uptr size) {
83868d75effSDimitry Andric   dfsan_set_label(0, const_cast<void *>(ptr), size);
83968d75effSDimitry Andric }
84068d75effSDimitry Andric 
84168d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally
84268d75effSDimitry Andric // doesn't participate in dynamic symbol resolution.  Therefore we won't
84368d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here.
84468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *
84568d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
84668d75effSDimitry Andric               dfsan_label flag_label, dfsan_label *ret_label) {
84768d75effSDimitry Andric   void *handle = dlopen(filename, flag);
84868d75effSDimitry Andric   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
8497a6dacacSDimitry Andric   if (filename && map)
850fe6060f1SDimitry Andric     ForEachMappedRegion(map, dfsan_set_zero_label);
85168d75effSDimitry Andric   *ret_label = 0;
85268d75effSDimitry Andric   return handle;
85368d75effSDimitry Andric }
85468d75effSDimitry Andric 
855fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen(
856fe6060f1SDimitry Andric     const char *filename, int flag, dfsan_label filename_label,
857fe6060f1SDimitry Andric     dfsan_label flag_label, dfsan_label *ret_label,
858fe6060f1SDimitry Andric     dfsan_origin filename_origin, dfsan_origin flag_origin,
859fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
860fe6060f1SDimitry Andric   return __dfsw_dlopen(filename, flag, filename_label, flag_label, ret_label);
861fe6060f1SDimitry Andric }
86268d75effSDimitry Andric 
863fe6060f1SDimitry Andric static void *DFsanThreadStartFunc(void *arg) {
864fe6060f1SDimitry Andric   DFsanThread *t = (DFsanThread *)arg;
865fe6060f1SDimitry Andric   SetCurrentThread(t);
866349cc55cSDimitry Andric   t->Init();
867349cc55cSDimitry Andric   SetSigProcMask(&t->starting_sigset_, nullptr);
868fe6060f1SDimitry Andric   return t->ThreadStart();
869fe6060f1SDimitry Andric }
870fe6060f1SDimitry Andric 
871fe6060f1SDimitry Andric static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
872fe6060f1SDimitry Andric                                 void *start_routine, void *arg,
873fe6060f1SDimitry Andric                                 dfsan_label *ret_label,
874fe6060f1SDimitry Andric                                 bool track_origins = false) {
875fe6060f1SDimitry Andric   pthread_attr_t myattr;
876fe6060f1SDimitry Andric   if (!attr) {
877fe6060f1SDimitry Andric     pthread_attr_init(&myattr);
878fe6060f1SDimitry Andric     attr = &myattr;
879fe6060f1SDimitry Andric   }
880fe6060f1SDimitry Andric 
881fe6060f1SDimitry Andric   // Ensure that the thread stack is large enough to hold all TLS data.
882fe6060f1SDimitry Andric   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
883fe6060f1SDimitry Andric 
884fe6060f1SDimitry Andric   DFsanThread *t =
88581ad6265SDimitry Andric       DFsanThread::Create((thread_callback_t)start_routine, arg, track_origins);
886349cc55cSDimitry Andric   ScopedBlockSignals block(&t->starting_sigset_);
887fe6060f1SDimitry Andric   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
888fe6060f1SDimitry Andric 
889fe6060f1SDimitry Andric   if (attr == &myattr)
890fe6060f1SDimitry Andric     pthread_attr_destroy(&myattr);
891fe6060f1SDimitry Andric   *ret_label = 0;
892fe6060f1SDimitry Andric   return res;
89368d75effSDimitry Andric }
89468d75effSDimitry Andric 
89568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
89681ad6265SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
89781ad6265SDimitry Andric     void *arg, dfsan_label thread_label, dfsan_label attr_label,
89881ad6265SDimitry Andric     dfsan_label start_routine_label, dfsan_label arg_label,
89981ad6265SDimitry Andric     dfsan_label *ret_label) {
90081ad6265SDimitry Andric   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label);
901fe6060f1SDimitry Andric }
902fe6060f1SDimitry Andric 
903fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
90481ad6265SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
90581ad6265SDimitry Andric     void *arg, dfsan_label thread_label, dfsan_label attr_label,
90681ad6265SDimitry Andric     dfsan_label start_routine_label, dfsan_label arg_label,
90781ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin thread_origin,
908fe6060f1SDimitry Andric     dfsan_origin attr_origin, dfsan_origin start_routine_origin,
909fe6060f1SDimitry Andric     dfsan_origin arg_origin, dfsan_origin *ret_origin) {
91081ad6265SDimitry Andric   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label,
91181ad6265SDimitry Andric                               true);
91268d75effSDimitry Andric }
91368d75effSDimitry Andric 
914e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
915e8d8bef9SDimitry Andric                                                       void **retval,
916e8d8bef9SDimitry Andric                                                       dfsan_label thread_label,
917e8d8bef9SDimitry Andric                                                       dfsan_label retval_label,
918e8d8bef9SDimitry Andric                                                       dfsan_label *ret_label) {
919e8d8bef9SDimitry Andric   int ret = pthread_join(thread, retval);
920e8d8bef9SDimitry Andric   if (ret == 0 && retval)
921e8d8bef9SDimitry Andric     dfsan_set_label(0, retval, sizeof(*retval));
922e8d8bef9SDimitry Andric   *ret_label = 0;
923e8d8bef9SDimitry Andric   return ret;
924e8d8bef9SDimitry Andric }
925e8d8bef9SDimitry Andric 
926fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
927fe6060f1SDimitry Andric     pthread_t thread, void **retval, dfsan_label thread_label,
928fe6060f1SDimitry Andric     dfsan_label retval_label, dfsan_label *ret_label,
929fe6060f1SDimitry Andric     dfsan_origin thread_origin, dfsan_origin retval_origin,
930fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
931fe6060f1SDimitry Andric   return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
932fe6060f1SDimitry Andric                              ret_label);
933fe6060f1SDimitry Andric }
934fe6060f1SDimitry Andric 
93568d75effSDimitry Andric struct dl_iterate_phdr_info {
93681ad6265SDimitry Andric   int (*callback)(struct dl_phdr_info *info, size_t size, void *data);
937fe6060f1SDimitry Andric   void *data;
938fe6060f1SDimitry Andric };
939fe6060f1SDimitry Andric 
94068d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
94168d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
94268d75effSDimitry Andric   dfsan_set_label(0, *info);
94368d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
94468d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
94568d75effSDimitry Andric   dfsan_set_label(
94668d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
94768d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
94868d75effSDimitry Andric 
94981ad6265SDimitry Andric   dfsan_clear_thread_local_state();
95081ad6265SDimitry Andric   return dipi->callback(info, size, dipi->data);
951fe6060f1SDimitry Andric }
952fe6060f1SDimitry Andric 
95368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
95481ad6265SDimitry Andric     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
95581ad6265SDimitry Andric     void *data, dfsan_label callback_label, dfsan_label data_label,
95681ad6265SDimitry Andric     dfsan_label *ret_label) {
95781ad6265SDimitry Andric   dl_iterate_phdr_info dipi = {callback, data};
95868d75effSDimitry Andric   *ret_label = 0;
95968d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
96068d75effSDimitry Andric }
96168d75effSDimitry Andric 
962fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr(
96381ad6265SDimitry Andric     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
96481ad6265SDimitry Andric     void *data, dfsan_label callback_label, dfsan_label data_label,
96581ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin callback_origin,
96681ad6265SDimitry Andric     dfsan_origin data_origin, dfsan_origin *ret_origin) {
96781ad6265SDimitry Andric   dl_iterate_phdr_info dipi = {callback, data};
968fe6060f1SDimitry Andric   *ret_label = 0;
96981ad6265SDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
970fe6060f1SDimitry Andric }
971fe6060f1SDimitry Andric 
972e8d8bef9SDimitry Andric // This function is only available for glibc 2.27 or newer.  Mark it weak so
973e8d8bef9SDimitry Andric // linking succeeds with older glibcs.
974e8d8bef9SDimitry Andric SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep,
975e8d8bef9SDimitry Andric                                                       size_t *alignp);
976e8d8bef9SDimitry Andric 
977e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info(
978e8d8bef9SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
979e8d8bef9SDimitry Andric     dfsan_label alignp_label) {
980e8d8bef9SDimitry Andric   assert(_dl_get_tls_static_info);
981e8d8bef9SDimitry Andric   _dl_get_tls_static_info(sizep, alignp);
982e8d8bef9SDimitry Andric   dfsan_set_label(0, sizep, sizeof(*sizep));
983e8d8bef9SDimitry Andric   dfsan_set_label(0, alignp, sizeof(*alignp));
984e8d8bef9SDimitry Andric }
985e8d8bef9SDimitry Andric 
986fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info(
987fe6060f1SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
988fe6060f1SDimitry Andric     dfsan_label alignp_label, dfsan_origin sizep_origin,
989fe6060f1SDimitry Andric     dfsan_origin alignp_origin) {
990fe6060f1SDimitry Andric   __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label);
991fe6060f1SDimitry Andric }
992fe6060f1SDimitry Andric 
99368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
99468d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
99568d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
99668d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
99768d75effSDimitry Andric   if (ret) {
99868d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
99968d75effSDimitry Andric                     strlen(buf) + 1);
100068d75effSDimitry Andric     *ret_label = buf_label;
100168d75effSDimitry Andric   } else {
100268d75effSDimitry Andric     *ret_label = 0;
100368d75effSDimitry Andric   }
100468d75effSDimitry Andric   return ret;
100568d75effSDimitry Andric }
100668d75effSDimitry Andric 
100768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1008fe6060f1SDimitry Andric char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
1009fe6060f1SDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label,
1010fe6060f1SDimitry Andric                      dfsan_origin timep_origin, dfsan_origin buf_origin,
1011fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1012fe6060f1SDimitry Andric   char *ret = ctime_r(timep, buf);
1013fe6060f1SDimitry Andric   if (ret) {
1014fe6060f1SDimitry Andric     dfsan_set_label_origin(
1015fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1016fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf,
1017fe6060f1SDimitry Andric         strlen(buf) + 1);
1018fe6060f1SDimitry Andric     *ret_label = buf_label;
1019fe6060f1SDimitry Andric     *ret_origin = buf_origin;
1020fe6060f1SDimitry Andric   } else {
1021fe6060f1SDimitry Andric     *ret_label = 0;
1022fe6060f1SDimitry Andric   }
1023fe6060f1SDimitry Andric   return ret;
1024fe6060f1SDimitry Andric }
1025fe6060f1SDimitry Andric 
1026fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
102768d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
102868d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
102968d75effSDimitry Andric                    dfsan_label *ret_label) {
103068d75effSDimitry Andric   char *ret = fgets(s, size, stream);
103168d75effSDimitry Andric   if (ret) {
103268d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
103368d75effSDimitry Andric     *ret_label = s_label;
103468d75effSDimitry Andric   } else {
103568d75effSDimitry Andric     *ret_label = 0;
103668d75effSDimitry Andric   }
103768d75effSDimitry Andric   return ret;
103868d75effSDimitry Andric }
103968d75effSDimitry Andric 
104068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1041fe6060f1SDimitry Andric char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
1042fe6060f1SDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
1043fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin s_origin,
1044fe6060f1SDimitry Andric                    dfsan_origin size_origin, dfsan_origin stream_origin,
1045fe6060f1SDimitry Andric                    dfsan_origin *ret_origin) {
1046fe6060f1SDimitry Andric   char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label,
1047fe6060f1SDimitry Andric                            ret_label);
1048fe6060f1SDimitry Andric   if (ret)
1049fe6060f1SDimitry Andric     *ret_origin = s_origin;
1050fe6060f1SDimitry Andric   return ret;
1051fe6060f1SDimitry Andric }
1052fe6060f1SDimitry Andric 
1053fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
105468d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
105568d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
105668d75effSDimitry Andric   char *ret = getcwd(buf, size);
105768d75effSDimitry Andric   if (ret) {
105868d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
105968d75effSDimitry Andric     *ret_label = buf_label;
106068d75effSDimitry Andric   } else {
106168d75effSDimitry Andric     *ret_label = 0;
106268d75effSDimitry Andric   }
106368d75effSDimitry Andric   return ret;
106468d75effSDimitry Andric }
106568d75effSDimitry Andric 
106668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1067fe6060f1SDimitry Andric char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label,
1068fe6060f1SDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label,
1069fe6060f1SDimitry Andric                     dfsan_origin buf_origin, dfsan_origin size_origin,
1070fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1071fe6060f1SDimitry Andric   char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label);
1072fe6060f1SDimitry Andric   if (ret)
1073fe6060f1SDimitry Andric     *ret_origin = buf_origin;
1074fe6060f1SDimitry Andric   return ret;
1075fe6060f1SDimitry Andric }
1076fe6060f1SDimitry Andric 
1077fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
107868d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
107968d75effSDimitry Andric   char *ret = get_current_dir_name();
1080fe6060f1SDimitry Andric   if (ret)
108168d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
108268d75effSDimitry Andric   *ret_label = 0;
108368d75effSDimitry Andric   return ret;
108468d75effSDimitry Andric }
108568d75effSDimitry Andric 
108668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1087fe6060f1SDimitry Andric char *__dfso_get_current_dir_name(dfsan_label *ret_label,
1088fe6060f1SDimitry Andric                                   dfsan_origin *ret_origin) {
1089fe6060f1SDimitry Andric   return __dfsw_get_current_dir_name(ret_label);
1090fe6060f1SDimitry Andric }
1091fe6060f1SDimitry Andric 
1092349cc55cSDimitry Andric // This function is only available for glibc 2.25 or newer.  Mark it weak so
1093349cc55cSDimitry Andric // linking succeeds with older glibcs.
1094349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length);
1095349cc55cSDimitry Andric 
1096349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length,
1097349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1098349cc55cSDimitry Andric                                                     dfsan_label length_label,
1099349cc55cSDimitry Andric                                                     dfsan_label *ret_label) {
1100349cc55cSDimitry Andric   int ret = getentropy(buffer, length);
1101349cc55cSDimitry Andric   if (ret == 0) {
1102349cc55cSDimitry Andric     dfsan_set_label(0, buffer, length);
1103349cc55cSDimitry Andric   }
1104349cc55cSDimitry Andric   *ret_label = 0;
1105349cc55cSDimitry Andric   return ret;
1106349cc55cSDimitry Andric }
1107349cc55cSDimitry Andric 
1108349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length,
1109349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1110349cc55cSDimitry Andric                                                     dfsan_label length_label,
1111349cc55cSDimitry Andric                                                     dfsan_label *ret_label,
1112349cc55cSDimitry Andric                                                     dfsan_origin buffer_origin,
1113349cc55cSDimitry Andric                                                     dfsan_origin length_origin,
1114349cc55cSDimitry Andric                                                     dfsan_origin *ret_origin) {
1115349cc55cSDimitry Andric   return __dfsw_getentropy(buffer, length, buffer_label, length_label,
1116349cc55cSDimitry Andric                            ret_label);
1117349cc55cSDimitry Andric }
1118349cc55cSDimitry Andric 
1119fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
112068d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
112168d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
112268d75effSDimitry Andric   int ret = gethostname(name, len);
112368d75effSDimitry Andric   if (ret == 0) {
112468d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
112568d75effSDimitry Andric   }
112668d75effSDimitry Andric   *ret_label = 0;
112768d75effSDimitry Andric   return ret;
112868d75effSDimitry Andric }
112968d75effSDimitry Andric 
113068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1131fe6060f1SDimitry Andric int __dfso_gethostname(char *name, size_t len, dfsan_label name_label,
1132fe6060f1SDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label,
1133fe6060f1SDimitry Andric                        dfsan_origin name_origin, dfsan_origin len_origin,
1134fe6060f1SDimitry Andric                        dfsan_label *ret_origin) {
1135fe6060f1SDimitry Andric   return __dfsw_gethostname(name, len, name_label, len_label, ret_label);
1136fe6060f1SDimitry Andric }
1137fe6060f1SDimitry Andric 
1138fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
113968d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
114068d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
114168d75effSDimitry Andric                      dfsan_label *ret_label) {
114268d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
114368d75effSDimitry Andric   if (ret == 0) {
114468d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
114568d75effSDimitry Andric   }
114668d75effSDimitry Andric   *ret_label = 0;
114768d75effSDimitry Andric   return ret;
114868d75effSDimitry Andric }
114968d75effSDimitry Andric 
115068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1151fe6060f1SDimitry Andric int __dfso_getrlimit(int resource, struct rlimit *rlim,
1152fe6060f1SDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
1153fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin resource_origin,
1154fe6060f1SDimitry Andric                      dfsan_origin rlim_origin, dfsan_origin *ret_origin) {
1155fe6060f1SDimitry Andric   return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label,
1156fe6060f1SDimitry Andric                           ret_label);
1157fe6060f1SDimitry Andric }
1158fe6060f1SDimitry Andric 
1159fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
116068d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
116168d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
116268d75effSDimitry Andric   int ret = getrusage(who, usage);
116368d75effSDimitry Andric   if (ret == 0) {
116468d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
116568d75effSDimitry Andric   }
116668d75effSDimitry Andric   *ret_label = 0;
116768d75effSDimitry Andric   return ret;
116868d75effSDimitry Andric }
116968d75effSDimitry Andric 
117068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1171fe6060f1SDimitry Andric int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label,
1172fe6060f1SDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label,
1173fe6060f1SDimitry Andric                      dfsan_origin who_origin, dfsan_origin usage_origin,
1174fe6060f1SDimitry Andric                      dfsan_label *ret_origin) {
1175fe6060f1SDimitry Andric   return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label);
1176fe6060f1SDimitry Andric }
1177fe6060f1SDimitry Andric 
1178fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
117968d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
118068d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
1181349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
118268d75effSDimitry Andric   if (ret) {
118304eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, strlen(src) + 1);
118468d75effSDimitry Andric   }
118568d75effSDimitry Andric   *ret_label = dst_label;
118668d75effSDimitry Andric   return ret;
118768d75effSDimitry Andric }
118868d75effSDimitry Andric 
118968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1190fe6060f1SDimitry Andric char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label,
1191fe6060f1SDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label,
1192fe6060f1SDimitry Andric                     dfsan_origin dst_origin, dfsan_origin src_origin,
1193fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1194349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
1195fe6060f1SDimitry Andric   if (ret) {
1196fe6060f1SDimitry Andric     size_t str_len = strlen(src) + 1;
1197fe6060f1SDimitry Andric     dfsan_mem_origin_transfer(dest, src, str_len);
119804eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, str_len);
119968d75effSDimitry Andric   }
1200fe6060f1SDimitry Andric   *ret_label = dst_label;
1201fe6060f1SDimitry Andric   *ret_origin = dst_origin;
1202fe6060f1SDimitry Andric   return ret;
1203fe6060f1SDimitry Andric }
1204*74626c16SDimitry Andric }
1205fe6060f1SDimitry Andric 
1206*74626c16SDimitry Andric template <typename Fn>
1207*74626c16SDimitry Andric static ALWAYS_INLINE auto dfsan_strtol_impl(
1208*74626c16SDimitry Andric     Fn real, const char *nptr, char **endptr, int base,
1209*74626c16SDimitry Andric     char **tmp_endptr) -> decltype(real(nullptr, nullptr, 0)) {
1210fe6060f1SDimitry Andric   assert(tmp_endptr);
1211*74626c16SDimitry Andric   auto ret = real(nptr, tmp_endptr, base);
1212fe6060f1SDimitry Andric   if (endptr)
1213fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1214fe6060f1SDimitry Andric   return ret;
1215fe6060f1SDimitry Andric }
1216fe6060f1SDimitry Andric 
1217*74626c16SDimitry Andric extern "C" {
1218fe6060f1SDimitry Andric static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr,
1219fe6060f1SDimitry Andric                                   dfsan_label base_label,
1220fe6060f1SDimitry Andric                                   dfsan_label *ret_label) {
122168d75effSDimitry Andric   if (tmp_endptr > nptr) {
122268d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
122368d75effSDimitry Andric     *ret_label = dfsan_union(
122468d75effSDimitry Andric         base_label,
122568d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
122668d75effSDimitry Andric   } else {
122768d75effSDimitry Andric     *ret_label = 0;
122868d75effSDimitry Andric   }
1229fe6060f1SDimitry Andric }
1230fe6060f1SDimitry Andric 
1231fe6060f1SDimitry Andric static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr,
1232fe6060f1SDimitry Andric                                    dfsan_label base_label,
1233fe6060f1SDimitry Andric                                    dfsan_label *ret_label,
1234fe6060f1SDimitry Andric                                    dfsan_origin base_origin,
1235fe6060f1SDimitry Andric                                    dfsan_origin *ret_origin) {
1236fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1237fe6060f1SDimitry Andric     // When multiple inputs are tainted, we propagate one of its origins.
1238fe6060f1SDimitry Andric     // Because checking if base_label is tainted does not need additional
1239fe6060f1SDimitry Andric     // computation, we prefer to propagating base_origin.
1240fe6060f1SDimitry Andric     *ret_origin = base_label
1241fe6060f1SDimitry Andric                       ? base_origin
1242fe6060f1SDimitry Andric                       : dfsan_read_origin_of_first_taint(
1243fe6060f1SDimitry Andric                             nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1244fe6060f1SDimitry Andric   }
1245fe6060f1SDimitry Andric }
1246fe6060f1SDimitry Andric 
1247fe6060f1SDimitry Andric static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) {
1248fe6060f1SDimitry Andric   assert(tmp_endptr);
1249fe6060f1SDimitry Andric   double ret = strtod(nptr, tmp_endptr);
1250fe6060f1SDimitry Andric   if (endptr)
1251fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1252fe6060f1SDimitry Andric   return ret;
1253fe6060f1SDimitry Andric }
1254fe6060f1SDimitry Andric 
1255fe6060f1SDimitry Andric static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr,
1256fe6060f1SDimitry Andric                                dfsan_label *ret_label) {
125768d75effSDimitry Andric   if (tmp_endptr > nptr) {
125868d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
125968d75effSDimitry Andric     *ret_label = dfsan_read_label(
126068d75effSDimitry Andric         nptr,
126168d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
126268d75effSDimitry Andric   } else {
126368d75effSDimitry Andric     *ret_label = 0;
126468d75effSDimitry Andric   }
1265fe6060f1SDimitry Andric }
1266fe6060f1SDimitry Andric 
1267fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1268fe6060f1SDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1269fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label) {
1270fe6060f1SDimitry Andric   char *tmp_endptr;
1271fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1272fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1273fe6060f1SDimitry Andric   return ret;
1274fe6060f1SDimitry Andric }
1275fe6060f1SDimitry Andric 
1276fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1277fe6060f1SDimitry Andric double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1278fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label,
1279fe6060f1SDimitry Andric                      dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1280fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1281fe6060f1SDimitry Andric   char *tmp_endptr;
1282fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1283fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1284fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1285fe6060f1SDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
1286fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(
1287fe6060f1SDimitry Andric         nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1288fe6060f1SDimitry Andric   } else {
1289fe6060f1SDimitry Andric     *ret_origin = 0;
1290fe6060f1SDimitry Andric   }
1291fe6060f1SDimitry Andric   return ret;
1292fe6060f1SDimitry Andric }
1293fe6060f1SDimitry Andric 
1294*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtod, strtod)
1295*74626c16SDimitry Andric 
1296*74626c16SDimitry Andric #define WRAPPER_STRTO(ret_type, fun)                                     \
1297*74626c16SDimitry Andric   SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfsw_##fun(                   \
1298*74626c16SDimitry Andric       const char *nptr, char **endptr, int base, dfsan_label nptr_label, \
1299*74626c16SDimitry Andric       dfsan_label endptr_label, dfsan_label base_label,                  \
1300*74626c16SDimitry Andric       dfsan_label *ret_label) {                                          \
1301*74626c16SDimitry Andric     char *tmp_endptr;                                                    \
1302*74626c16SDimitry Andric     auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr);  \
1303*74626c16SDimitry Andric     dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);      \
1304*74626c16SDimitry Andric     return ret;                                                          \
1305*74626c16SDimitry Andric   }                                                                      \
1306*74626c16SDimitry Andric   SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfso_##fun(                   \
1307*74626c16SDimitry Andric       const char *nptr, char **endptr, int base, dfsan_label nptr_label, \
1308*74626c16SDimitry Andric       dfsan_label endptr_label, dfsan_label base_label,                  \
1309*74626c16SDimitry Andric       dfsan_label *ret_label, dfsan_origin nptr_origin,                  \
1310*74626c16SDimitry Andric       dfsan_origin endptr_origin, dfsan_origin base_origin,              \
1311*74626c16SDimitry Andric       dfsan_origin *ret_origin) {                                        \
1312*74626c16SDimitry Andric     char *tmp_endptr;                                                    \
1313*74626c16SDimitry Andric     auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr);  \
1314*74626c16SDimitry Andric     dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);      \
1315*74626c16SDimitry Andric     dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label,      \
1316*74626c16SDimitry Andric                            base_origin, ret_origin);                     \
1317*74626c16SDimitry Andric     return ret;                                                          \
131868d75effSDimitry Andric   }
131968d75effSDimitry Andric 
1320*74626c16SDimitry Andric WRAPPER_STRTO(long, strtol)
1321*74626c16SDimitry Andric WRAPPER_STRTO(long long, strtoll)
1322*74626c16SDimitry Andric WRAPPER_STRTO(unsigned long, strtoul)
1323*74626c16SDimitry Andric WRAPPER_STRTO(unsigned long long, strtoull)
1324*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtol, strtol)
1325*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtoll, strtoll)
1326*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtoul, strtoul)
1327*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtoull, strtoull)
132868d75effSDimitry Andric 
132968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
133068d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
133168d75effSDimitry Andric   time_t ret = time(t);
133268d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
133368d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
133468d75effSDimitry Andric   }
133568d75effSDimitry Andric   *ret_label = 0;
133668d75effSDimitry Andric   return ret;
133768d75effSDimitry Andric }
133868d75effSDimitry Andric 
133968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1340fe6060f1SDimitry Andric time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label,
1341fe6060f1SDimitry Andric                    dfsan_origin t_origin, dfsan_origin *ret_origin) {
1342fe6060f1SDimitry Andric   return __dfsw_time(t, t_label, ret_label);
1343fe6060f1SDimitry Andric }
1344fe6060f1SDimitry Andric 
1345fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
134668d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
134768d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
134868d75effSDimitry Andric                      dfsan_label *ret_label) {
134968d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
135068d75effSDimitry Andric   if (ret == 1) {
135168d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
135268d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
135368d75effSDimitry Andric   }
135468d75effSDimitry Andric   *ret_label = 0;
135568d75effSDimitry Andric   return ret;
135668d75effSDimitry Andric }
135768d75effSDimitry Andric 
135868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1359fe6060f1SDimitry Andric int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
1360fe6060f1SDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
1361fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin af_origin,
1362fe6060f1SDimitry Andric                      dfsan_origin src_origin, dfsan_origin dst_origin,
1363fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1364fe6060f1SDimitry Andric   int ret = inet_pton(af, src, dst);
1365fe6060f1SDimitry Andric   if (ret == 1) {
1366fe6060f1SDimitry Andric     int src_len = strlen(src) + 1;
1367fe6060f1SDimitry Andric     dfsan_set_label_origin(
1368fe6060f1SDimitry Andric         dfsan_read_label(src, src_len),
1369fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(src, src_len), dst,
1370fe6060f1SDimitry Andric         af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
1371fe6060f1SDimitry Andric   }
1372fe6060f1SDimitry Andric   *ret_label = 0;
1373fe6060f1SDimitry Andric   return ret;
1374fe6060f1SDimitry Andric }
1375fe6060f1SDimitry Andric 
1376fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
137768d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
137868d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
137968d75effSDimitry Andric                               dfsan_label *ret_label) {
138068d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
138168d75effSDimitry Andric   if (ret) {
138268d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
138368d75effSDimitry Andric                     sizeof(struct tm));
138468d75effSDimitry Andric     *ret_label = result_label;
138568d75effSDimitry Andric   } else {
138668d75effSDimitry Andric     *ret_label = 0;
138768d75effSDimitry Andric   }
138868d75effSDimitry Andric   return ret;
138968d75effSDimitry Andric }
139068d75effSDimitry Andric 
139168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1392fe6060f1SDimitry Andric struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result,
1393fe6060f1SDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
1394fe6060f1SDimitry Andric                               dfsan_label *ret_label, dfsan_origin timep_origin,
1395fe6060f1SDimitry Andric                               dfsan_origin result_origin,
1396fe6060f1SDimitry Andric                               dfsan_origin *ret_origin) {
1397fe6060f1SDimitry Andric   struct tm *ret = localtime_r(timep, result);
1398fe6060f1SDimitry Andric   if (ret) {
1399fe6060f1SDimitry Andric     dfsan_set_label_origin(
1400fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1401fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result,
1402fe6060f1SDimitry Andric         sizeof(struct tm));
1403fe6060f1SDimitry Andric     *ret_label = result_label;
1404fe6060f1SDimitry Andric     *ret_origin = result_origin;
1405fe6060f1SDimitry Andric   } else {
1406fe6060f1SDimitry Andric     *ret_label = 0;
1407fe6060f1SDimitry Andric   }
1408fe6060f1SDimitry Andric   return ret;
1409fe6060f1SDimitry Andric }
1410fe6060f1SDimitry Andric 
1411fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
141268d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
141368d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
141468d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
141568d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
141668d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
141768d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
141868d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
141968d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
142068d75effSDimitry Andric   if (ret == 0) {
142168d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
142268d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
142368d75effSDimitry Andric   }
142468d75effSDimitry Andric   *ret_label = 0;
142568d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
142668d75effSDimitry Andric   return ret;
142768d75effSDimitry Andric }
142868d75effSDimitry Andric 
142968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1430fe6060f1SDimitry Andric int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen,
1431fe6060f1SDimitry Andric                       struct passwd **result, dfsan_label uid_label,
1432fe6060f1SDimitry Andric                       dfsan_label pwd_label, dfsan_label buf_label,
1433fe6060f1SDimitry Andric                       dfsan_label buflen_label, dfsan_label result_label,
1434fe6060f1SDimitry Andric                       dfsan_label *ret_label, dfsan_origin uid_origin,
1435fe6060f1SDimitry Andric                       dfsan_origin pwd_origin, dfsan_origin buf_origin,
1436fe6060f1SDimitry Andric                       dfsan_origin buflen_origin, dfsan_origin result_origin,
1437fe6060f1SDimitry Andric                       dfsan_origin *ret_origin) {
1438fe6060f1SDimitry Andric   return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label,
1439fe6060f1SDimitry Andric                            buf_label, buflen_label, result_label, ret_label);
1440fe6060f1SDimitry Andric }
1441fe6060f1SDimitry Andric 
1442fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1443e8d8bef9SDimitry Andric int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1444e8d8bef9SDimitry Andric                       int timeout, dfsan_label epfd_label,
1445e8d8bef9SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1446e8d8bef9SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label) {
1447e8d8bef9SDimitry Andric   int ret = epoll_wait(epfd, events, maxevents, timeout);
1448e8d8bef9SDimitry Andric   if (ret > 0)
1449e8d8bef9SDimitry Andric     dfsan_set_label(0, events, ret * sizeof(*events));
1450e8d8bef9SDimitry Andric   *ret_label = 0;
1451e8d8bef9SDimitry Andric   return ret;
1452e8d8bef9SDimitry Andric }
1453e8d8bef9SDimitry Andric 
1454e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1455fe6060f1SDimitry Andric int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1456fe6060f1SDimitry Andric                       int timeout, dfsan_label epfd_label,
1457fe6060f1SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1458fe6060f1SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label,
1459fe6060f1SDimitry Andric                       dfsan_origin epfd_origin, dfsan_origin events_origin,
1460fe6060f1SDimitry Andric                       dfsan_origin maxevents_origin,
1461fe6060f1SDimitry Andric                       dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1462fe6060f1SDimitry Andric   return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label,
1463fe6060f1SDimitry Andric                            events_label, maxevents_label, timeout_label,
1464fe6060f1SDimitry Andric                            ret_label);
1465fe6060f1SDimitry Andric }
1466fe6060f1SDimitry Andric 
1467fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
146868d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
146968d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
147068d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
147168d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
147268d75effSDimitry Andric   if (ret >= 0) {
147368d75effSDimitry Andric     for (; nfds > 0; --nfds) {
147468d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
147568d75effSDimitry Andric     }
147668d75effSDimitry Andric   }
147768d75effSDimitry Andric   *ret_label = 0;
147868d75effSDimitry Andric   return ret;
147968d75effSDimitry Andric }
148068d75effSDimitry Andric 
148168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1482fe6060f1SDimitry Andric int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout,
1483fe6060f1SDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
1484fe6060f1SDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label,
1485fe6060f1SDimitry Andric                 dfsan_origin dfs_origin, dfsan_origin nfds_origin,
1486fe6060f1SDimitry Andric                 dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1487fe6060f1SDimitry Andric   return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label,
1488fe6060f1SDimitry Andric                      ret_label);
1489fe6060f1SDimitry Andric }
1490fe6060f1SDimitry Andric 
1491fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
149268d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
149368d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
149468d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
149568d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
149668d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
149768d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
149868d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
149968d75effSDimitry Andric   // undefined.
150068d75effSDimitry Andric   if (readfds) {
150168d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
150268d75effSDimitry Andric   }
150368d75effSDimitry Andric   if (writefds) {
150468d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
150568d75effSDimitry Andric   }
150668d75effSDimitry Andric   if (exceptfds) {
150768d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
150868d75effSDimitry Andric   }
150968d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
151068d75effSDimitry Andric   *ret_label = 0;
151168d75effSDimitry Andric   return ret;
151268d75effSDimitry Andric }
151368d75effSDimitry Andric 
151468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1515fe6060f1SDimitry Andric int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds,
1516fe6060f1SDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
1517fe6060f1SDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
1518fe6060f1SDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
1519fe6060f1SDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label,
1520fe6060f1SDimitry Andric                   dfsan_origin nfds_origin, dfsan_origin readfds_origin,
1521fe6060f1SDimitry Andric                   dfsan_origin writefds_origin, dfsan_origin exceptfds_origin,
1522fe6060f1SDimitry Andric                   dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1523fe6060f1SDimitry Andric   return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label,
1524fe6060f1SDimitry Andric                        readfds_label, writefds_label, exceptfds_label,
1525fe6060f1SDimitry Andric                        timeout_label, ret_label);
1526fe6060f1SDimitry Andric }
1527fe6060f1SDimitry Andric 
1528fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
152968d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
153068d75effSDimitry Andric                              dfsan_label pid_label,
153168d75effSDimitry Andric                              dfsan_label cpusetsize_label,
153268d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
153368d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
153468d75effSDimitry Andric   if (ret == 0) {
153568d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
153668d75effSDimitry Andric   }
153768d75effSDimitry Andric   *ret_label = 0;
153868d75effSDimitry Andric   return ret;
153968d75effSDimitry Andric }
154068d75effSDimitry Andric 
154168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1542fe6060f1SDimitry Andric int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
1543fe6060f1SDimitry Andric                              dfsan_label pid_label,
1544fe6060f1SDimitry Andric                              dfsan_label cpusetsize_label,
1545fe6060f1SDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label,
1546fe6060f1SDimitry Andric                              dfsan_origin pid_origin,
1547fe6060f1SDimitry Andric                              dfsan_origin cpusetsize_origin,
1548fe6060f1SDimitry Andric                              dfsan_origin mask_origin,
1549fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1550fe6060f1SDimitry Andric   return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label,
1551fe6060f1SDimitry Andric                                   cpusetsize_label, mask_label, ret_label);
1552fe6060f1SDimitry Andric }
1553fe6060f1SDimitry Andric 
1554fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
155568d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
155668d75effSDimitry Andric                        dfsan_label *ret_label) {
155768d75effSDimitry Andric   int ret = sigemptyset(set);
155868d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
1559fe6060f1SDimitry Andric   *ret_label = 0;
156068d75effSDimitry Andric   return ret;
156168d75effSDimitry Andric }
156268d75effSDimitry Andric 
156368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1564fe6060f1SDimitry Andric int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
1565fe6060f1SDimitry Andric                        dfsan_label *ret_label, dfsan_origin set_origin,
1566fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1567fe6060f1SDimitry Andric   return __dfsw_sigemptyset(set, set_label, ret_label);
1568fe6060f1SDimitry Andric }
1569fe6060f1SDimitry Andric 
1570fe6060f1SDimitry Andric class SignalHandlerScope {
1571fe6060f1SDimitry Andric  public:
1572fe6060f1SDimitry Andric   SignalHandlerScope() {
1573fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1574fe6060f1SDimitry Andric       t->EnterSignalHandler();
1575fe6060f1SDimitry Andric   }
1576fe6060f1SDimitry Andric   ~SignalHandlerScope() {
1577fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1578fe6060f1SDimitry Andric       t->LeaveSignalHandler();
1579fe6060f1SDimitry Andric   }
1580fe6060f1SDimitry Andric };
1581fe6060f1SDimitry Andric 
1582fe6060f1SDimitry Andric // Clear DFSan runtime TLS state at the end of a scope.
1583fe6060f1SDimitry Andric //
1584fe6060f1SDimitry Andric // Implementation must be async-signal-safe and use small data size, because
1585fe6060f1SDimitry Andric // instances of this class may live on the signal handler stack.
1586fe6060f1SDimitry Andric //
1587fe6060f1SDimitry Andric // DFSan uses TLS to pass metadata of arguments and return values. When an
1588fe6060f1SDimitry Andric // instrumented function accesses the TLS, if a signal callback happens, and the
1589fe6060f1SDimitry Andric // callback calls other instrumented functions with updating the same TLS, the
1590fe6060f1SDimitry Andric // TLS is in an inconsistent state after the callback ends. This may cause
1591fe6060f1SDimitry Andric // either under-tainting or over-tainting.
1592fe6060f1SDimitry Andric //
1593fe6060f1SDimitry Andric // The current implementation simply resets TLS at restore. This prevents from
1594fe6060f1SDimitry Andric // over-tainting. Although under-tainting may still happen, a taint flow can be
1595fe6060f1SDimitry Andric // found eventually if we run a DFSan-instrumented program multiple times. The
1596fe6060f1SDimitry Andric // alternative option is saving the entire TLS. However the TLS storage takes
1597fe6060f1SDimitry Andric // 2k bytes, and signal calls could be nested. So it does not seem worth.
1598fe6060f1SDimitry Andric class ScopedClearThreadLocalState {
1599fe6060f1SDimitry Andric  public:
1600fe6060f1SDimitry Andric   ScopedClearThreadLocalState() {}
1601fe6060f1SDimitry Andric   ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); }
1602fe6060f1SDimitry Andric };
1603fe6060f1SDimitry Andric 
1604fe6060f1SDimitry Andric // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls.
1605fe6060f1SDimitry Andric const int kMaxSignals = 1024;
1606fe6060f1SDimitry Andric static atomic_uintptr_t sigactions[kMaxSignals];
1607fe6060f1SDimitry Andric 
1608fe6060f1SDimitry Andric static void SignalHandler(int signo) {
1609fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1610fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1611fe6060f1SDimitry Andric 
161281ad6265SDimitry Andric   // Clear shadows for all inputs provided by system.
1613fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, sizeof(dfsan_label));
1614fe6060f1SDimitry Andric 
1615fe6060f1SDimitry Andric   typedef void (*signal_cb)(int x);
1616fe6060f1SDimitry Andric   signal_cb cb =
1617fe6060f1SDimitry Andric       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1618fe6060f1SDimitry Andric   cb(signo);
1619fe6060f1SDimitry Andric }
1620fe6060f1SDimitry Andric 
1621fe6060f1SDimitry Andric static void SignalAction(int signo, siginfo_t *si, void *uc) {
1622fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1623fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1624fe6060f1SDimitry Andric 
1625fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. Similar to SignalHandler.
1626fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label));
1627fe6060f1SDimitry Andric   dfsan_set_label(0, si, sizeof(*si));
1628fe6060f1SDimitry Andric   dfsan_set_label(0, uc, sizeof(ucontext_t));
1629fe6060f1SDimitry Andric 
1630fe6060f1SDimitry Andric   typedef void (*sigaction_cb)(int, siginfo_t *, void *);
1631fe6060f1SDimitry Andric   sigaction_cb cb =
1632fe6060f1SDimitry Andric       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1633fe6060f1SDimitry Andric   cb(signo, si, uc);
1634fe6060f1SDimitry Andric }
1635fe6060f1SDimitry Andric 
1636fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
163768d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
163868d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
163968d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
164068d75effSDimitry Andric                      dfsan_label *ret_label) {
1641fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1642fe6060f1SDimitry Andric   SignalSpinLocker lock;
1643fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1644fe6060f1SDimitry Andric   struct sigaction new_act;
1645fe6060f1SDimitry Andric   struct sigaction *pnew_act = act ? &new_act : nullptr;
1646fe6060f1SDimitry Andric   if (act) {
1647fe6060f1SDimitry Andric     internal_memcpy(pnew_act, act, sizeof(struct sigaction));
1648fe6060f1SDimitry Andric     if (pnew_act->sa_flags & SA_SIGINFO) {
1649fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_sigaction);
1650fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1651fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1652fe6060f1SDimitry Andric         pnew_act->sa_sigaction = SignalAction;
1653fe6060f1SDimitry Andric       }
1654fe6060f1SDimitry Andric     } else {
1655fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_handler);
1656fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1657fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1658fe6060f1SDimitry Andric         pnew_act->sa_handler = SignalHandler;
1659fe6060f1SDimitry Andric       }
1660fe6060f1SDimitry Andric     }
1661fe6060f1SDimitry Andric   }
1662fe6060f1SDimitry Andric 
1663fe6060f1SDimitry Andric   int ret = sigaction(signum, pnew_act, oldact);
1664fe6060f1SDimitry Andric 
1665fe6060f1SDimitry Andric   if (ret == 0 && oldact) {
1666fe6060f1SDimitry Andric     if (oldact->sa_flags & SA_SIGINFO) {
1667fe6060f1SDimitry Andric       if (oldact->sa_sigaction == SignalAction)
1668fe6060f1SDimitry Andric         oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb;
1669fe6060f1SDimitry Andric     } else {
1670fe6060f1SDimitry Andric       if (oldact->sa_handler == SignalHandler)
1671fe6060f1SDimitry Andric         oldact->sa_handler = (decltype(oldact->sa_handler))old_cb;
1672fe6060f1SDimitry Andric     }
1673fe6060f1SDimitry Andric   }
1674fe6060f1SDimitry Andric 
167568d75effSDimitry Andric   if (oldact) {
167668d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
167768d75effSDimitry Andric   }
167868d75effSDimitry Andric   *ret_label = 0;
167968d75effSDimitry Andric   return ret;
168068d75effSDimitry Andric }
168168d75effSDimitry Andric 
168268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1683fe6060f1SDimitry Andric int __dfso_sigaction(int signum, const struct sigaction *act,
1684fe6060f1SDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
1685fe6060f1SDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
1686fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin signum_origin,
1687fe6060f1SDimitry Andric                      dfsan_origin act_origin, dfsan_origin oldact_origin,
1688fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1689fe6060f1SDimitry Andric   return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
1690fe6060f1SDimitry Andric                           oldact_label, ret_label);
1691fe6060f1SDimitry Andric }
1692fe6060f1SDimitry Andric 
1693fe6060f1SDimitry Andric static sighandler_t dfsan_signal(int signum, sighandler_t handler,
1694fe6060f1SDimitry Andric                                  dfsan_label *ret_label) {
1695fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1696fe6060f1SDimitry Andric   SignalSpinLocker lock;
1697fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1698fe6060f1SDimitry Andric   if (handler != SIG_IGN && handler != SIG_DFL) {
1699fe6060f1SDimitry Andric     atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
1700fe6060f1SDimitry Andric     handler = &SignalHandler;
1701fe6060f1SDimitry Andric   }
1702fe6060f1SDimitry Andric 
1703fe6060f1SDimitry Andric   sighandler_t ret = signal(signum, handler);
1704fe6060f1SDimitry Andric 
1705fe6060f1SDimitry Andric   if (ret == SignalHandler)
1706fe6060f1SDimitry Andric     ret = (sighandler_t)old_cb;
1707fe6060f1SDimitry Andric 
1708fe6060f1SDimitry Andric   *ret_label = 0;
1709fe6060f1SDimitry Andric   return ret;
1710fe6060f1SDimitry Andric }
1711fe6060f1SDimitry Andric 
1712fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
171381ad6265SDimitry Andric sighandler_t __dfsw_signal(int signum, sighandler_t handler,
171481ad6265SDimitry Andric                            dfsan_label signum_label, dfsan_label handler_label,
171581ad6265SDimitry Andric                            dfsan_label *ret_label) {
1716fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1717fe6060f1SDimitry Andric }
1718fe6060f1SDimitry Andric 
1719fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
172081ad6265SDimitry Andric sighandler_t __dfso_signal(int signum, sighandler_t handler,
172181ad6265SDimitry Andric                            dfsan_label signum_label, dfsan_label handler_label,
1722fe6060f1SDimitry Andric                            dfsan_label *ret_label, dfsan_origin signum_origin,
172381ad6265SDimitry Andric                            dfsan_origin handler_origin,
172481ad6265SDimitry Andric                            dfsan_origin *ret_origin) {
1725fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1726fe6060f1SDimitry Andric }
1727fe6060f1SDimitry Andric 
1728fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1729e8d8bef9SDimitry Andric int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1730e8d8bef9SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label) {
1731e8d8bef9SDimitry Andric   int ret = sigaltstack(ss, old_ss);
1732e8d8bef9SDimitry Andric   if (ret != -1 && old_ss)
1733e8d8bef9SDimitry Andric     dfsan_set_label(0, old_ss, sizeof(*old_ss));
1734e8d8bef9SDimitry Andric   *ret_label = 0;
1735e8d8bef9SDimitry Andric   return ret;
1736e8d8bef9SDimitry Andric }
1737e8d8bef9SDimitry Andric 
1738e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1739fe6060f1SDimitry Andric int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1740fe6060f1SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label,
1741fe6060f1SDimitry Andric                        dfsan_origin ss_origin, dfsan_origin old_ss_origin,
1742fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1743fe6060f1SDimitry Andric   return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
1744fe6060f1SDimitry Andric }
1745fe6060f1SDimitry Andric 
1746fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
174768d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
174868d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
174968d75effSDimitry Andric                         dfsan_label *ret_label) {
175068d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
175168d75effSDimitry Andric   if (tv) {
175268d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
175368d75effSDimitry Andric   }
175468d75effSDimitry Andric   if (tz) {
175568d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
175668d75effSDimitry Andric   }
175768d75effSDimitry Andric   *ret_label = 0;
175868d75effSDimitry Andric   return ret;
175968d75effSDimitry Andric }
176068d75effSDimitry Andric 
1761fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1762fe6060f1SDimitry Andric int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz,
1763fe6060f1SDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
1764fe6060f1SDimitry Andric                         dfsan_label *ret_label, dfsan_origin tv_origin,
1765fe6060f1SDimitry Andric                         dfsan_origin tz_origin, dfsan_origin *ret_origin) {
1766fe6060f1SDimitry Andric   return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label);
1767fe6060f1SDimitry Andric }
1768fe6060f1SDimitry Andric 
176968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
177068d75effSDimitry Andric                                                   dfsan_label s_label,
177168d75effSDimitry Andric                                                   dfsan_label c_label,
177268d75effSDimitry Andric                                                   dfsan_label n_label,
177368d75effSDimitry Andric                                                   dfsan_label *ret_label) {
177468d75effSDimitry Andric   void *ret = memchr(s, c, n);
177568d75effSDimitry Andric   if (flags().strict_data_dependencies) {
177668d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
177768d75effSDimitry Andric   } else {
177868d75effSDimitry Andric     size_t len =
177968d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
178068d75effSDimitry Andric             : n;
178168d75effSDimitry Andric     *ret_label =
178268d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
178368d75effSDimitry Andric   }
178468d75effSDimitry Andric   return ret;
178568d75effSDimitry Andric }
178668d75effSDimitry Andric 
1787fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr(
1788fe6060f1SDimitry Andric     void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label,
1789fe6060f1SDimitry Andric     dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin,
1790fe6060f1SDimitry Andric     dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) {
1791fe6060f1SDimitry Andric   void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label);
1792fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1793fe6060f1SDimitry Andric     if (ret)
1794fe6060f1SDimitry Andric       *ret_origin = s_origin;
1795fe6060f1SDimitry Andric   } else {
1796fe6060f1SDimitry Andric     size_t len =
1797fe6060f1SDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
1798fe6060f1SDimitry Andric             : n;
1799fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, len);
1800fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1801fe6060f1SDimitry Andric   }
1802fe6060f1SDimitry Andric   return ret;
1803fe6060f1SDimitry Andric }
1804fe6060f1SDimitry Andric 
180568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
180668d75effSDimitry Andric                                                    dfsan_label s_label,
180768d75effSDimitry Andric                                                    dfsan_label c_label,
180868d75effSDimitry Andric                                                    dfsan_label *ret_label) {
180968d75effSDimitry Andric   char *ret = strrchr(s, c);
181068d75effSDimitry Andric   if (flags().strict_data_dependencies) {
181168d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
181268d75effSDimitry Andric   } else {
181368d75effSDimitry Andric     *ret_label =
181468d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
181568d75effSDimitry Andric                     dfsan_union(s_label, c_label));
181668d75effSDimitry Andric   }
181768d75effSDimitry Andric 
181868d75effSDimitry Andric   return ret;
181968d75effSDimitry Andric }
182068d75effSDimitry Andric 
1821fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr(
1822fe6060f1SDimitry Andric     char *s, int c, dfsan_label s_label, dfsan_label c_label,
1823fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
1824fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
1825fe6060f1SDimitry Andric   char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label);
1826fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1827fe6060f1SDimitry Andric     if (ret)
1828fe6060f1SDimitry Andric       *ret_origin = s_origin;
1829fe6060f1SDimitry Andric   } else {
1830fe6060f1SDimitry Andric     size_t s_len = strlen(s) + 1;
1831fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len);
1832fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1833fe6060f1SDimitry Andric   }
1834fe6060f1SDimitry Andric 
1835fe6060f1SDimitry Andric   return ret;
1836fe6060f1SDimitry Andric }
1837fe6060f1SDimitry Andric 
183868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
183968d75effSDimitry Andric                                                   dfsan_label haystack_label,
184068d75effSDimitry Andric                                                   dfsan_label needle_label,
184168d75effSDimitry Andric                                                   dfsan_label *ret_label) {
184268d75effSDimitry Andric   char *ret = strstr(haystack, needle);
184368d75effSDimitry Andric   if (flags().strict_data_dependencies) {
184468d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
184568d75effSDimitry Andric   } else {
184668d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
184768d75effSDimitry Andric     *ret_label =
184868d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
184968d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
185068d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
185168d75effSDimitry Andric   }
185268d75effSDimitry Andric 
185368d75effSDimitry Andric   return ret;
185468d75effSDimitry Andric }
185568d75effSDimitry Andric 
1856fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle,
1857fe6060f1SDimitry Andric                                                   dfsan_label haystack_label,
1858fe6060f1SDimitry Andric                                                   dfsan_label needle_label,
1859fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
1860fe6060f1SDimitry Andric                                                   dfsan_origin haystack_origin,
1861fe6060f1SDimitry Andric                                                   dfsan_origin needle_origin,
1862fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
1863fe6060f1SDimitry Andric   char *ret =
1864fe6060f1SDimitry Andric       __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label);
1865fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1866fe6060f1SDimitry Andric     if (ret)
1867fe6060f1SDimitry Andric       *ret_origin = haystack_origin;
1868fe6060f1SDimitry Andric   } else {
1869fe6060f1SDimitry Andric     size_t needle_len = strlen(needle);
1870fe6060f1SDimitry Andric     size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1;
1871fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len);
1872fe6060f1SDimitry Andric     if (o) {
1873fe6060f1SDimitry Andric       *ret_origin = o;
1874fe6060f1SDimitry Andric     } else {
1875fe6060f1SDimitry Andric       o = dfsan_read_origin_of_first_taint(needle, needle_len + 1);
1876fe6060f1SDimitry Andric       *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin);
1877fe6060f1SDimitry Andric     }
1878fe6060f1SDimitry Andric   }
1879fe6060f1SDimitry Andric 
1880fe6060f1SDimitry Andric   return ret;
1881fe6060f1SDimitry Andric }
1882fe6060f1SDimitry Andric 
188368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
188468d75effSDimitry Andric                                                    struct timespec *rem,
188568d75effSDimitry Andric                                                    dfsan_label req_label,
188668d75effSDimitry Andric                                                    dfsan_label rem_label,
188768d75effSDimitry Andric                                                    dfsan_label *ret_label) {
188868d75effSDimitry Andric   int ret = nanosleep(req, rem);
188968d75effSDimitry Andric   *ret_label = 0;
189068d75effSDimitry Andric   if (ret == -1) {
189168d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
189268d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
189368d75effSDimitry Andric   }
189468d75effSDimitry Andric   return ret;
189568d75effSDimitry Andric }
189668d75effSDimitry Andric 
1897fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
1898fe6060f1SDimitry Andric     const struct timespec *req, struct timespec *rem, dfsan_label req_label,
1899fe6060f1SDimitry Andric     dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin,
1900fe6060f1SDimitry Andric     dfsan_origin rem_origin, dfsan_origin *ret_origin) {
1901fe6060f1SDimitry Andric   return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
1902fe6060f1SDimitry Andric }
1903fe6060f1SDimitry Andric 
1904e8d8bef9SDimitry Andric static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) {
1905e8d8bef9SDimitry Andric   dfsan_set_label(0, msg, sizeof(*msg));
1906e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
1907e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
1908e8d8bef9SDimitry Andric   for (size_t i = 0; bytes_written > 0; ++i) {
1909e8d8bef9SDimitry Andric     assert(i < msg->msg_iovlen);
1910e8d8bef9SDimitry Andric     struct iovec *iov = &msg->msg_iov[i];
1911e8d8bef9SDimitry Andric     size_t iov_written =
1912e8d8bef9SDimitry Andric         bytes_written < iov->iov_len ? bytes_written : iov->iov_len;
1913e8d8bef9SDimitry Andric     dfsan_set_label(0, iov->iov_base, iov_written);
1914e8d8bef9SDimitry Andric     bytes_written -= iov_written;
1915e8d8bef9SDimitry Andric   }
1916e8d8bef9SDimitry Andric }
1917e8d8bef9SDimitry Andric 
1918e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
1919e8d8bef9SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1920e8d8bef9SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1921e8d8bef9SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1922e8d8bef9SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label) {
1923e8d8bef9SDimitry Andric   int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
1924e8d8bef9SDimitry Andric   for (int i = 0; i < ret; ++i) {
1925e8d8bef9SDimitry Andric     dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
1926e8d8bef9SDimitry Andric     clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr);
1927e8d8bef9SDimitry Andric   }
1928e8d8bef9SDimitry Andric   *ret_label = 0;
1929e8d8bef9SDimitry Andric   return ret;
1930e8d8bef9SDimitry Andric }
1931e8d8bef9SDimitry Andric 
1932fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg(
1933fe6060f1SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1934fe6060f1SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1935fe6060f1SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1936fe6060f1SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label,
1937fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msgvec_origin,
1938fe6060f1SDimitry Andric     dfsan_origin vlen_origin, dfsan_origin flags_origin,
1939fe6060f1SDimitry Andric     dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1940fe6060f1SDimitry Andric   return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label,
1941fe6060f1SDimitry Andric                          msgvec_label, vlen_label, flags_label, timeout_label,
1942fe6060f1SDimitry Andric                          ret_label);
1943fe6060f1SDimitry Andric }
1944fe6060f1SDimitry Andric 
1945e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
1946e8d8bef9SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1947e8d8bef9SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
1948e8d8bef9SDimitry Andric   ssize_t ret = recvmsg(sockfd, msg, flags);
1949e8d8bef9SDimitry Andric   if (ret >= 0)
1950e8d8bef9SDimitry Andric     clear_msghdr_labels(ret, msg);
1951e8d8bef9SDimitry Andric   *ret_label = 0;
1952e8d8bef9SDimitry Andric   return ret;
1953e8d8bef9SDimitry Andric }
1954e8d8bef9SDimitry Andric 
1955fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg(
1956fe6060f1SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1957fe6060f1SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label,
1958fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msg_origin,
1959fe6060f1SDimitry Andric     dfsan_origin flags_origin, dfsan_origin *ret_origin) {
1960fe6060f1SDimitry Andric   return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label,
1961fe6060f1SDimitry Andric                         flags_label, ret_label);
1962fe6060f1SDimitry Andric }
1963fe6060f1SDimitry Andric 
196468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
196568d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
196668d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
196768d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
196868d75effSDimitry Andric                   dfsan_label *ret_label) {
196968d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
197068d75effSDimitry Andric   *ret_label = 0;
197168d75effSDimitry Andric   if (ret == 0) {
197268d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
197368d75effSDimitry Andric   }
197468d75effSDimitry Andric   return ret;
197568d75effSDimitry Andric }
197668d75effSDimitry Andric 
1977fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair(
1978fe6060f1SDimitry Andric     int domain, int type, int protocol, int sv[2], dfsan_label domain_label,
1979fe6060f1SDimitry Andric     dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label,
1980fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin domain_origin,
1981fe6060f1SDimitry Andric     dfsan_origin type_origin, dfsan_origin protocol_origin,
1982fe6060f1SDimitry Andric     dfsan_origin sv_origin, dfsan_origin *ret_origin) {
1983fe6060f1SDimitry Andric   return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label,
1984fe6060f1SDimitry Andric                            protocol_label, sv_label, ret_label);
1985fe6060f1SDimitry Andric }
1986fe6060f1SDimitry Andric 
1987e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt(
1988e8d8bef9SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
1989e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
1990e8d8bef9SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
1991e8d8bef9SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label) {
1992e8d8bef9SDimitry Andric   int ret = getsockopt(sockfd, level, optname, optval, optlen);
1993e8d8bef9SDimitry Andric   if (ret != -1 && optval && optlen) {
1994e8d8bef9SDimitry Andric     dfsan_set_label(0, optlen, sizeof(*optlen));
1995e8d8bef9SDimitry Andric     dfsan_set_label(0, optval, *optlen);
1996e8d8bef9SDimitry Andric   }
1997e8d8bef9SDimitry Andric   *ret_label = 0;
1998e8d8bef9SDimitry Andric   return ret;
1999e8d8bef9SDimitry Andric }
2000e8d8bef9SDimitry Andric 
2001fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt(
2002fe6060f1SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2003fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2004fe6060f1SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2005fe6060f1SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label,
2006fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin level_origin,
2007fe6060f1SDimitry Andric     dfsan_origin optname_origin, dfsan_origin optval_origin,
2008fe6060f1SDimitry Andric     dfsan_origin optlen_origin, dfsan_origin *ret_origin) {
2009fe6060f1SDimitry Andric   return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label,
2010fe6060f1SDimitry Andric                            level_label, optname_label, optval_label,
2011fe6060f1SDimitry Andric                            optlen_label, ret_label);
2012fe6060f1SDimitry Andric }
2013fe6060f1SDimitry Andric 
2014e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname(
2015e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2016e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2017e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2018e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2019e8d8bef9SDimitry Andric   int ret = getsockname(sockfd, addr, addrlen);
2020e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2021e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2022e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2023e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2024e8d8bef9SDimitry Andric   }
2025e8d8bef9SDimitry Andric   *ret_label = 0;
2026e8d8bef9SDimitry Andric   return ret;
2027e8d8bef9SDimitry Andric }
2028e8d8bef9SDimitry Andric 
2029fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname(
2030fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2031fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2032fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2033fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2034fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2035fe6060f1SDimitry Andric   return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label,
2036fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2037fe6060f1SDimitry Andric }
2038fe6060f1SDimitry Andric 
2039e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername(
2040e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2041e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2042e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2043e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2044e8d8bef9SDimitry Andric   int ret = getpeername(sockfd, addr, addrlen);
2045e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2046e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2047e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2048e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2049e8d8bef9SDimitry Andric   }
2050e8d8bef9SDimitry Andric   *ret_label = 0;
2051e8d8bef9SDimitry Andric   return ret;
2052e8d8bef9SDimitry Andric }
2053e8d8bef9SDimitry Andric 
2054fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername(
2055fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2056fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2057fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2058fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2059fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2060fe6060f1SDimitry Andric   return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label,
2061fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2062fe6060f1SDimitry Andric }
2063fe6060f1SDimitry Andric 
206481ad6265SDimitry Andric // Type of the function passed to dfsan_set_write_callback.
206581ad6265SDimitry Andric typedef void (*write_dfsan_callback_t)(int fd, const void *buf, ssize_t count);
2066fe6060f1SDimitry Andric 
206768d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
206868d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
206968d75effSDimitry Andric static struct {
207081ad6265SDimitry Andric   write_dfsan_callback_t write_callback = nullptr;
207168d75effSDimitry Andric } write_callback_info;
207268d75effSDimitry Andric 
207381ad6265SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_dfsan_set_write_callback(
207481ad6265SDimitry Andric     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
207568d75effSDimitry Andric     dfsan_label *ret_label) {
207668d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
207768d75effSDimitry Andric }
207868d75effSDimitry Andric 
2079fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
208081ad6265SDimitry Andric     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
208181ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin write_callback_origin,
208281ad6265SDimitry Andric     dfsan_origin *ret_origin) {
208381ad6265SDimitry Andric   write_callback_info.write_callback = write_callback;
208481ad6265SDimitry Andric }
208581ad6265SDimitry Andric 
208681ad6265SDimitry Andric static inline void setup_tls_args_for_write_callback(
208781ad6265SDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
208881ad6265SDimitry Andric     bool origins, dfsan_origin fd_origin, dfsan_origin buf_origin,
208981ad6265SDimitry Andric     dfsan_origin count_origin) {
209081ad6265SDimitry Andric   // The callback code will expect argument shadow labels in the args TLS,
209181ad6265SDimitry Andric   // and origin labels in the origin args TLS.
209281ad6265SDimitry Andric   // Previously this was done by a trampoline, but we want to remove this:
209381ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/issues/54172
209481ad6265SDimitry Andric   //
209581ad6265SDimitry Andric   // Instead, this code is manually setting up the args TLS data.
209681ad6265SDimitry Andric   //
209781ad6265SDimitry Andric   // The offsets used need to correspond with the instrumentation code,
209881ad6265SDimitry Andric   // see llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
209981ad6265SDimitry Andric   // DFSanFunction::getShadowForTLSArgument.
210081ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L1684
210181ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L125
210281ad6265SDimitry Andric   //
210381ad6265SDimitry Andric   // Here the arguments are all primitives, but it can be more complex
210481ad6265SDimitry Andric   // to compute offsets for array/aggregate type arguments.
210581ad6265SDimitry Andric   //
210681ad6265SDimitry Andric   // TODO(browneee): Consider a builtin to improve maintainabliity.
210781ad6265SDimitry Andric   // With a builtin, we would provide the argument labels via builtin,
210881ad6265SDimitry Andric   // and the builtin would reuse parts of the instrumentation code to ensure
210981ad6265SDimitry Andric   // that this code and the instrumentation can never be out of sync.
211081ad6265SDimitry Andric   // Note: Currently DFSan instrumentation does not run on this code, so
211181ad6265SDimitry Andric   // the builtin may need to be handled outside DFSan instrumentation.
211281ad6265SDimitry Andric   dfsan_set_arg_tls(0, fd_label);
211381ad6265SDimitry Andric   dfsan_set_arg_tls(1, buf_label);
211481ad6265SDimitry Andric   dfsan_set_arg_tls(2, count_label);
211581ad6265SDimitry Andric   if (origins) {
211681ad6265SDimitry Andric     dfsan_set_arg_origin_tls(0, fd_origin);
211781ad6265SDimitry Andric     dfsan_set_arg_origin_tls(1, buf_origin);
211881ad6265SDimitry Andric     dfsan_set_arg_origin_tls(2, count_origin);
211981ad6265SDimitry Andric   }
2120fe6060f1SDimitry Andric }
2121fe6060f1SDimitry Andric 
212268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
212368d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
212468d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
212568d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
212668d75effSDimitry Andric   if (write_callback_info.write_callback) {
212781ad6265SDimitry Andric     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, false,
212881ad6265SDimitry Andric                                       0, 0, 0);
212981ad6265SDimitry Andric     write_callback_info.write_callback(fd, buf, count);
213068d75effSDimitry Andric   }
213168d75effSDimitry Andric 
213268d75effSDimitry Andric   *ret_label = 0;
213368d75effSDimitry Andric   return write(fd, buf, count);
213468d75effSDimitry Andric }
2135fe6060f1SDimitry Andric 
2136fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
2137fe6060f1SDimitry Andric     int fd, const void *buf, size_t count, dfsan_label fd_label,
2138fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
2139fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
2140fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
214181ad6265SDimitry Andric   if (write_callback_info.write_callback) {
214281ad6265SDimitry Andric     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, true,
214381ad6265SDimitry Andric                                       fd_origin, buf_origin, count_origin);
214481ad6265SDimitry Andric     write_callback_info.write_callback(fd, buf, count);
2145fe6060f1SDimitry Andric   }
2146fe6060f1SDimitry Andric 
2147fe6060f1SDimitry Andric   *ret_label = 0;
2148fe6060f1SDimitry Andric   return write(fd, buf, count);
2149fe6060f1SDimitry Andric }
215068d75effSDimitry Andric }  // namespace __dfsan
215168d75effSDimitry Andric 
215268d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
215368d75effSDimitry Andric typedef int dfsan_label_va;
215468d75effSDimitry Andric 
215568d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
215668d75effSDimitry Andric // '%.3f').
215768d75effSDimitry Andric struct Formatter {
215868d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
21595f757f3fSDimitry Andric       : str(str_),
21605f757f3fSDimitry Andric         str_off(0),
21615f757f3fSDimitry Andric         size(size_),
21625f757f3fSDimitry Andric         fmt_start(fmt_),
21635f757f3fSDimitry Andric         fmt_cur(fmt_),
21645f757f3fSDimitry Andric         width(-1),
21655f757f3fSDimitry Andric         num_scanned(-1),
21665f757f3fSDimitry Andric         skip(false) {}
216768d75effSDimitry Andric 
216868d75effSDimitry Andric   int format() {
216968d75effSDimitry Andric     char *tmp_fmt = build_format_string();
217068d75effSDimitry Andric     int retval =
217168d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
217268d75effSDimitry Andric                  0 /* used only to avoid warnings */);
217368d75effSDimitry Andric     free(tmp_fmt);
217468d75effSDimitry Andric     return retval;
217568d75effSDimitry Andric   }
217668d75effSDimitry Andric 
217768d75effSDimitry Andric   template <typename T> int format(T arg) {
217868d75effSDimitry Andric     char *tmp_fmt = build_format_string();
217968d75effSDimitry Andric     int retval;
218068d75effSDimitry Andric     if (width >= 0) {
218168d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
218268d75effSDimitry Andric                         tmp_fmt, width, arg);
218368d75effSDimitry Andric     } else {
218468d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
218568d75effSDimitry Andric                         tmp_fmt, arg);
218668d75effSDimitry Andric     }
218768d75effSDimitry Andric     free(tmp_fmt);
218868d75effSDimitry Andric     return retval;
218968d75effSDimitry Andric   }
219068d75effSDimitry Andric 
21915f757f3fSDimitry Andric   int scan() {
21925f757f3fSDimitry Andric     char *tmp_fmt = build_format_string(true);
21935f757f3fSDimitry Andric     int read_count = 0;
21945f757f3fSDimitry Andric     int retval = sscanf(str + str_off, tmp_fmt, &read_count);
21955f757f3fSDimitry Andric     if (retval > 0) {
21965f757f3fSDimitry Andric       if (-1 == num_scanned)
21975f757f3fSDimitry Andric         num_scanned = 0;
21985f757f3fSDimitry Andric       num_scanned += retval;
21995f757f3fSDimitry Andric     }
22005f757f3fSDimitry Andric     free(tmp_fmt);
22015f757f3fSDimitry Andric     return read_count;
22025f757f3fSDimitry Andric   }
22035f757f3fSDimitry Andric 
22045f757f3fSDimitry Andric   template <typename T>
22055f757f3fSDimitry Andric   int scan(T arg) {
22065f757f3fSDimitry Andric     char *tmp_fmt = build_format_string(true);
22075f757f3fSDimitry Andric     int read_count = 0;
22085f757f3fSDimitry Andric     int retval = sscanf(str + str_off, tmp_fmt, arg, &read_count);
22095f757f3fSDimitry Andric     if (retval > 0) {
22105f757f3fSDimitry Andric       if (-1 == num_scanned)
22115f757f3fSDimitry Andric         num_scanned = 0;
22125f757f3fSDimitry Andric       num_scanned += retval;
22135f757f3fSDimitry Andric     }
22145f757f3fSDimitry Andric     free(tmp_fmt);
22155f757f3fSDimitry Andric     return read_count;
22165f757f3fSDimitry Andric   }
22175f757f3fSDimitry Andric 
22185f757f3fSDimitry Andric   // with_n -> toggles adding %n on/off; off by default
22195f757f3fSDimitry Andric   char *build_format_string(bool with_n = false) {
222068d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
22215f757f3fSDimitry Andric     size_t add_size = 0;
22225f757f3fSDimitry Andric     if (with_n)
22235f757f3fSDimitry Andric       add_size = 2;
22245f757f3fSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1 + add_size);
222568d75effSDimitry Andric     assert(new_fmt);
222668d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
22275f757f3fSDimitry Andric     if (!with_n) {
222868d75effSDimitry Andric       new_fmt[fmt_size] = '\0';
22295f757f3fSDimitry Andric     } else {
22305f757f3fSDimitry Andric       new_fmt[fmt_size] = '%';
22315f757f3fSDimitry Andric       new_fmt[fmt_size + 1] = 'n';
22325f757f3fSDimitry Andric       new_fmt[fmt_size + 2] = '\0';
22335f757f3fSDimitry Andric     }
22345f757f3fSDimitry Andric 
223568d75effSDimitry Andric     return new_fmt;
223668d75effSDimitry Andric   }
223768d75effSDimitry Andric 
223868d75effSDimitry Andric   char *str_cur() { return str + str_off; }
223968d75effSDimitry Andric 
224068d75effSDimitry Andric   size_t num_written_bytes(int retval) {
224168d75effSDimitry Andric     if (retval < 0) {
224268d75effSDimitry Andric       return 0;
224368d75effSDimitry Andric     }
224468d75effSDimitry Andric 
224568d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
224668d75effSDimitry Andric     if (num_avail == 0) {
224768d75effSDimitry Andric       return 0;
224868d75effSDimitry Andric     }
224968d75effSDimitry Andric 
225068d75effSDimitry Andric     size_t num_written = retval;
225168d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
225268d75effSDimitry Andric     // truncated.
225368d75effSDimitry Andric     if (num_written >= num_avail) {
225468d75effSDimitry Andric       num_written -= num_avail;
225568d75effSDimitry Andric     }
225668d75effSDimitry Andric 
225768d75effSDimitry Andric     return num_written;
225868d75effSDimitry Andric   }
225968d75effSDimitry Andric 
226068d75effSDimitry Andric   char *str;
226168d75effSDimitry Andric   size_t str_off;
226268d75effSDimitry Andric   size_t size;
226368d75effSDimitry Andric   const char *fmt_start;
226468d75effSDimitry Andric   const char *fmt_cur;
226568d75effSDimitry Andric   int width;
22665f757f3fSDimitry Andric   int num_scanned;
22675f757f3fSDimitry Andric   bool skip;
226868d75effSDimitry Andric };
226968d75effSDimitry Andric 
227068d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
227168d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
227268d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
227368d75effSDimitry Andric // the return value vsnprintf would return.
227468d75effSDimitry Andric //
227568d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
227668d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
227768d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
227868d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
227968d75effSDimitry Andric // propagate labels more precisely.
228068d75effSDimitry Andric //
228168d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
228268d75effSDimitry Andric // positional arguments.
228368d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
228468d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
2285fe6060f1SDimitry Andric                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
228668d75effSDimitry Andric                          va_list ap) {
228768d75effSDimitry Andric   Formatter formatter(str, fmt, size);
228868d75effSDimitry Andric 
228968d75effSDimitry Andric   while (*formatter.fmt_cur) {
229068d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
229168d75effSDimitry Andric     formatter.width = -1;
229268d75effSDimitry Andric     int retval = 0;
229368d75effSDimitry Andric 
229468d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
229568d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
229668d75effSDimitry Andric       // of the string.
229768d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
229868d75effSDimitry Andric            ++formatter.fmt_cur) {}
229968d75effSDimitry Andric       retval = formatter.format();
230068d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
230168d75effSDimitry Andric                       formatter.num_written_bytes(retval));
230268d75effSDimitry Andric     } else {
230368d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
230468d75effSDimitry Andric       // specifier or the end of the string.
230568d75effSDimitry Andric       bool end_fmt = false;
230668d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
230768d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
230868d75effSDimitry Andric         case 'd':
230968d75effSDimitry Andric         case 'i':
231068d75effSDimitry Andric         case 'o':
231168d75effSDimitry Andric         case 'u':
231268d75effSDimitry Andric         case 'x':
231368d75effSDimitry Andric         case 'X':
231468d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
231568d75effSDimitry Andric           case 'h':
231668d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
231768d75effSDimitry Andric             // an int).
231868d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
231968d75effSDimitry Andric             break;
232068d75effSDimitry Andric           case 'l':
232168d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
232268d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
232368d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
232468d75effSDimitry Andric             } else {
232568d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
232668d75effSDimitry Andric             }
232768d75effSDimitry Andric             break;
232868d75effSDimitry Andric           case 'q':
232968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
233068d75effSDimitry Andric             break;
233168d75effSDimitry Andric           case 'j':
233268d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
233368d75effSDimitry Andric             break;
233468d75effSDimitry Andric           case 'z':
233568d75effSDimitry Andric           case 't':
233668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
233768d75effSDimitry Andric             break;
233868d75effSDimitry Andric           default:
233968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
234068d75effSDimitry Andric           }
2341fe6060f1SDimitry Andric           if (va_origins == nullptr)
234268d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
234368d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2344fe6060f1SDimitry Andric           else
2345fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2346fe6060f1SDimitry Andric                                    formatter.str_cur(),
2347fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
234868d75effSDimitry Andric           end_fmt = true;
234968d75effSDimitry Andric           break;
235068d75effSDimitry Andric 
235168d75effSDimitry Andric         case 'a':
235268d75effSDimitry Andric         case 'A':
235368d75effSDimitry Andric         case 'e':
235468d75effSDimitry Andric         case 'E':
235568d75effSDimitry Andric         case 'f':
235668d75effSDimitry Andric         case 'F':
235768d75effSDimitry Andric         case 'g':
235868d75effSDimitry Andric         case 'G':
235968d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
236068d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
236168d75effSDimitry Andric           } else {
236268d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
236368d75effSDimitry Andric           }
2364fe6060f1SDimitry Andric           if (va_origins == nullptr)
236568d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
236668d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2367fe6060f1SDimitry Andric           else
2368fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2369fe6060f1SDimitry Andric                                    formatter.str_cur(),
2370fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
237168d75effSDimitry Andric           end_fmt = true;
237268d75effSDimitry Andric           break;
237368d75effSDimitry Andric 
237468d75effSDimitry Andric         case 'c':
237568d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
2376fe6060f1SDimitry Andric           if (va_origins == nullptr)
237768d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
237868d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2379fe6060f1SDimitry Andric           else
2380fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2381fe6060f1SDimitry Andric                                    formatter.str_cur(),
2382fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
238368d75effSDimitry Andric           end_fmt = true;
238468d75effSDimitry Andric           break;
238568d75effSDimitry Andric 
238668d75effSDimitry Andric         case 's': {
238768d75effSDimitry Andric           char *arg = va_arg(ap, char *);
238868d75effSDimitry Andric           retval = formatter.format(arg);
2389fe6060f1SDimitry Andric           if (va_origins) {
2390fe6060f1SDimitry Andric             va_origins++;
2391fe6060f1SDimitry Andric             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
2392fe6060f1SDimitry Andric                                       formatter.num_written_bytes(retval));
2393fe6060f1SDimitry Andric           }
239468d75effSDimitry Andric           va_labels++;
239504eeddc0SDimitry Andric           dfsan_mem_shadow_transfer(formatter.str_cur(), arg,
239668d75effSDimitry Andric                                     formatter.num_written_bytes(retval));
239768d75effSDimitry Andric           end_fmt = true;
239868d75effSDimitry Andric           break;
239968d75effSDimitry Andric         }
240068d75effSDimitry Andric 
240168d75effSDimitry Andric         case 'p':
240268d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
2403fe6060f1SDimitry Andric           if (va_origins == nullptr)
240468d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
240568d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2406fe6060f1SDimitry Andric           else
2407fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2408fe6060f1SDimitry Andric                                    formatter.str_cur(),
2409fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
241068d75effSDimitry Andric           end_fmt = true;
241168d75effSDimitry Andric           break;
241268d75effSDimitry Andric 
241368d75effSDimitry Andric         case 'n': {
241468d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
241568d75effSDimitry Andric           *ptr = (int)formatter.str_off;
241668d75effSDimitry Andric           va_labels++;
2417fe6060f1SDimitry Andric           if (va_origins)
2418fe6060f1SDimitry Andric             va_origins++;
241968d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
242068d75effSDimitry Andric           end_fmt = true;
242168d75effSDimitry Andric           break;
242268d75effSDimitry Andric         }
242368d75effSDimitry Andric 
242468d75effSDimitry Andric         case '%':
242568d75effSDimitry Andric           retval = formatter.format();
242668d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
242768d75effSDimitry Andric                           formatter.num_written_bytes(retval));
242868d75effSDimitry Andric           end_fmt = true;
242968d75effSDimitry Andric           break;
243068d75effSDimitry Andric 
243168d75effSDimitry Andric         case '*':
243268d75effSDimitry Andric           formatter.width = va_arg(ap, int);
243368d75effSDimitry Andric           va_labels++;
2434fe6060f1SDimitry Andric           if (va_origins)
2435fe6060f1SDimitry Andric             va_origins++;
243668d75effSDimitry Andric           break;
243768d75effSDimitry Andric 
243868d75effSDimitry Andric         default:
243968d75effSDimitry Andric           break;
244068d75effSDimitry Andric         }
244168d75effSDimitry Andric       }
244268d75effSDimitry Andric     }
244368d75effSDimitry Andric 
244468d75effSDimitry Andric     if (retval < 0) {
244568d75effSDimitry Andric       return retval;
244668d75effSDimitry Andric     }
244768d75effSDimitry Andric 
244868d75effSDimitry Andric     formatter.fmt_cur++;
244968d75effSDimitry Andric     formatter.str_off += retval;
245068d75effSDimitry Andric   }
245168d75effSDimitry Andric 
245268d75effSDimitry Andric   *ret_label = 0;
2453fe6060f1SDimitry Andric   if (ret_origin)
2454fe6060f1SDimitry Andric     *ret_origin = 0;
245568d75effSDimitry Andric 
245668d75effSDimitry Andric   // Number of bytes written in total.
245768d75effSDimitry Andric   return formatter.str_off;
245868d75effSDimitry Andric }
245968d75effSDimitry Andric 
24605f757f3fSDimitry Andric // This function is an inverse of format_buffer: we take the input buffer,
24615f757f3fSDimitry Andric // scan it in search for format strings and store the results in the varargs.
24625f757f3fSDimitry Andric // The labels are propagated from the input buffer to the varargs.
24635f757f3fSDimitry Andric static int scan_buffer(char *str, size_t size, const char *fmt,
24645f757f3fSDimitry Andric                        dfsan_label *va_labels, dfsan_label *ret_label,
24655f757f3fSDimitry Andric                        dfsan_origin *str_origin, dfsan_origin *ret_origin,
24665f757f3fSDimitry Andric                        va_list ap) {
24675f757f3fSDimitry Andric   Formatter formatter(str, fmt, size);
24685f757f3fSDimitry Andric   while (*formatter.fmt_cur) {
24695f757f3fSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
24705f757f3fSDimitry Andric     formatter.width = -1;
24715f757f3fSDimitry Andric     formatter.skip = false;
24725f757f3fSDimitry Andric     int read_count = 0;
24735f757f3fSDimitry Andric     void *dst_ptr = 0;
24745f757f3fSDimitry Andric     size_t write_size = 0;
24755f757f3fSDimitry Andric     if (*formatter.fmt_cur != '%') {
24765f757f3fSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
24775f757f3fSDimitry Andric       // of the string.
24785f757f3fSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
24795f757f3fSDimitry Andric            ++formatter.fmt_cur) {
24805f757f3fSDimitry Andric       }
24815f757f3fSDimitry Andric       read_count = formatter.scan();
24825f757f3fSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
24835f757f3fSDimitry Andric                       formatter.num_written_bytes(read_count));
24845f757f3fSDimitry Andric     } else {
24855f757f3fSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
24865f757f3fSDimitry Andric       // specifier or the end of the string.
24875f757f3fSDimitry Andric       bool end_fmt = false;
24885f757f3fSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt;) {
24895f757f3fSDimitry Andric         switch (*++formatter.fmt_cur) {
24905f757f3fSDimitry Andric         case 'd':
24915f757f3fSDimitry Andric         case 'i':
24925f757f3fSDimitry Andric         case 'o':
24935f757f3fSDimitry Andric         case 'u':
24945f757f3fSDimitry Andric         case 'x':
24955f757f3fSDimitry Andric         case 'X':
24965f757f3fSDimitry Andric           if (formatter.skip) {
24975f757f3fSDimitry Andric             read_count = formatter.scan();
24985f757f3fSDimitry Andric           } else {
24995f757f3fSDimitry Andric             switch (*(formatter.fmt_cur - 1)) {
25005f757f3fSDimitry Andric             case 'h':
25015f757f3fSDimitry Andric               // Also covers the 'hh' case (since the size of the arg is still
25025f757f3fSDimitry Andric               // an int).
25035f757f3fSDimitry Andric               dst_ptr = va_arg(ap, int *);
25045f757f3fSDimitry Andric               read_count = formatter.scan((int *)dst_ptr);
25055f757f3fSDimitry Andric               write_size = sizeof(int);
25065f757f3fSDimitry Andric               break;
25075f757f3fSDimitry Andric             case 'l':
25085f757f3fSDimitry Andric               if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
25095f757f3fSDimitry Andric                   *(formatter.fmt_cur - 2) == 'l') {
25105f757f3fSDimitry Andric                 dst_ptr = va_arg(ap, long long int *);
25115f757f3fSDimitry Andric                 read_count = formatter.scan((long long int *)dst_ptr);
25125f757f3fSDimitry Andric                 write_size = sizeof(long long int);
25135f757f3fSDimitry Andric               } else {
25145f757f3fSDimitry Andric                 dst_ptr = va_arg(ap, long int *);
25155f757f3fSDimitry Andric                 read_count = formatter.scan((long int *)dst_ptr);
25165f757f3fSDimitry Andric                 write_size = sizeof(long int);
25175f757f3fSDimitry Andric               }
25185f757f3fSDimitry Andric               break;
25195f757f3fSDimitry Andric             case 'q':
25205f757f3fSDimitry Andric               dst_ptr = va_arg(ap, long long int *);
25215f757f3fSDimitry Andric               read_count = formatter.scan((long long int *)dst_ptr);
25225f757f3fSDimitry Andric               write_size = sizeof(long long int);
25235f757f3fSDimitry Andric               break;
25245f757f3fSDimitry Andric             case 'j':
25255f757f3fSDimitry Andric               dst_ptr = va_arg(ap, intmax_t *);
25265f757f3fSDimitry Andric               read_count = formatter.scan((intmax_t *)dst_ptr);
25275f757f3fSDimitry Andric               write_size = sizeof(intmax_t);
25285f757f3fSDimitry Andric               break;
25295f757f3fSDimitry Andric             case 'z':
25305f757f3fSDimitry Andric             case 't':
25315f757f3fSDimitry Andric               dst_ptr = va_arg(ap, size_t *);
25325f757f3fSDimitry Andric               read_count = formatter.scan((size_t *)dst_ptr);
25335f757f3fSDimitry Andric               write_size = sizeof(size_t);
25345f757f3fSDimitry Andric               break;
25355f757f3fSDimitry Andric             default:
25365f757f3fSDimitry Andric               dst_ptr = va_arg(ap, int *);
25375f757f3fSDimitry Andric               read_count = formatter.scan((int *)dst_ptr);
25385f757f3fSDimitry Andric               write_size = sizeof(int);
25395f757f3fSDimitry Andric             }
25405f757f3fSDimitry Andric             // get the label associated with the string at the corresponding
25415f757f3fSDimitry Andric             // place
25425f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
25435f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
25445f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
25455f757f3fSDimitry Andric             if (str_origin != nullptr) {
25465f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
25475f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
25485f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
25495f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
25505f757f3fSDimitry Andric             }
25515f757f3fSDimitry Andric           }
25525f757f3fSDimitry Andric           end_fmt = true;
25535f757f3fSDimitry Andric 
25545f757f3fSDimitry Andric           break;
25555f757f3fSDimitry Andric 
25565f757f3fSDimitry Andric         case 'a':
25575f757f3fSDimitry Andric         case 'A':
25585f757f3fSDimitry Andric         case 'e':
25595f757f3fSDimitry Andric         case 'E':
25605f757f3fSDimitry Andric         case 'f':
25615f757f3fSDimitry Andric         case 'F':
25625f757f3fSDimitry Andric         case 'g':
25635f757f3fSDimitry Andric         case 'G':
25645f757f3fSDimitry Andric           if (formatter.skip) {
25655f757f3fSDimitry Andric             read_count = formatter.scan();
25665f757f3fSDimitry Andric           } else {
25675f757f3fSDimitry Andric             if (*(formatter.fmt_cur - 1) == 'L') {
25685f757f3fSDimitry Andric             dst_ptr = va_arg(ap, long double *);
25695f757f3fSDimitry Andric             read_count = formatter.scan((long double *)dst_ptr);
25705f757f3fSDimitry Andric             write_size = sizeof(long double);
25715f757f3fSDimitry Andric             } else if (*(formatter.fmt_cur - 1) == 'l') {
25725f757f3fSDimitry Andric             dst_ptr = va_arg(ap, double *);
25735f757f3fSDimitry Andric             read_count = formatter.scan((double *)dst_ptr);
25745f757f3fSDimitry Andric             write_size = sizeof(double);
25755f757f3fSDimitry Andric             } else {
25765f757f3fSDimitry Andric             dst_ptr = va_arg(ap, float *);
25775f757f3fSDimitry Andric             read_count = formatter.scan((float *)dst_ptr);
25785f757f3fSDimitry Andric             write_size = sizeof(float);
25795f757f3fSDimitry Andric             }
25805f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
25815f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
25825f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
25835f757f3fSDimitry Andric             if (str_origin != nullptr) {
25845f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
25855f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
25865f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
25875f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
25885f757f3fSDimitry Andric             }
25895f757f3fSDimitry Andric           }
25905f757f3fSDimitry Andric           end_fmt = true;
25915f757f3fSDimitry Andric           break;
25925f757f3fSDimitry Andric 
25935f757f3fSDimitry Andric         case 'c':
25945f757f3fSDimitry Andric           if (formatter.skip) {
25955f757f3fSDimitry Andric             read_count = formatter.scan();
25965f757f3fSDimitry Andric           } else {
25975f757f3fSDimitry Andric             dst_ptr = va_arg(ap, char *);
25985f757f3fSDimitry Andric             read_count = formatter.scan((char *)dst_ptr);
25995f757f3fSDimitry Andric             write_size = sizeof(char);
26005f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
26015f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
26025f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26035f757f3fSDimitry Andric             if (str_origin != nullptr) {
26045f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
26055f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
26065f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
26075f757f3fSDimitry Andric             }
26085f757f3fSDimitry Andric           }
26095f757f3fSDimitry Andric           end_fmt = true;
26105f757f3fSDimitry Andric           break;
26115f757f3fSDimitry Andric 
26125f757f3fSDimitry Andric         case 's': {
26135f757f3fSDimitry Andric           if (formatter.skip) {
26145f757f3fSDimitry Andric             read_count = formatter.scan();
26155f757f3fSDimitry Andric           } else {
26165f757f3fSDimitry Andric             dst_ptr = va_arg(ap, char *);
26175f757f3fSDimitry Andric             read_count = formatter.scan((char *)dst_ptr);
26185f757f3fSDimitry Andric             if (1 == read_count) {
26195f757f3fSDimitry Andric             // special case: we have parsed a single string and we need to
26205f757f3fSDimitry Andric             // update read_count with the string size
26215f757f3fSDimitry Andric             read_count = strlen((char *)dst_ptr);
26225f757f3fSDimitry Andric             }
26235f757f3fSDimitry Andric             if (str_origin)
26245f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(),
26255f757f3fSDimitry Andric                                       formatter.num_written_bytes(read_count));
26265f757f3fSDimitry Andric             va_labels++;
26275f757f3fSDimitry Andric             dfsan_mem_shadow_transfer(dst_ptr, formatter.str_cur(),
26285f757f3fSDimitry Andric                                       formatter.num_written_bytes(read_count));
26295f757f3fSDimitry Andric           }
26305f757f3fSDimitry Andric           end_fmt = true;
26315f757f3fSDimitry Andric           break;
26325f757f3fSDimitry Andric         }
26335f757f3fSDimitry Andric 
26345f757f3fSDimitry Andric         case 'p':
26355f757f3fSDimitry Andric           if (formatter.skip) {
26365f757f3fSDimitry Andric             read_count = formatter.scan();
26375f757f3fSDimitry Andric           } else {
26385f757f3fSDimitry Andric             dst_ptr = va_arg(ap, void *);
26395f757f3fSDimitry Andric             read_count =
26405f757f3fSDimitry Andric                 formatter.scan((int *)dst_ptr);  // note: changing void* to int*
26415f757f3fSDimitry Andric                                                  // since we need to call sizeof
26425f757f3fSDimitry Andric             write_size = sizeof(int);
26435f757f3fSDimitry Andric 
26445f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
26455f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
26465f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26475f757f3fSDimitry Andric             if (str_origin != nullptr) {
26485f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26495f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
26505f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
26515f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
26525f757f3fSDimitry Andric             }
26535f757f3fSDimitry Andric           }
26545f757f3fSDimitry Andric           end_fmt = true;
26555f757f3fSDimitry Andric           break;
26565f757f3fSDimitry Andric 
26575f757f3fSDimitry Andric         case 'n': {
26585f757f3fSDimitry Andric           if (!formatter.skip) {
26595f757f3fSDimitry Andric             int *ptr = va_arg(ap, int *);
26605f757f3fSDimitry Andric             *ptr = (int)formatter.str_off;
26615f757f3fSDimitry Andric             *va_labels++ = 0;
26625f757f3fSDimitry Andric             dfsan_set_label(0, ptr, sizeof(*ptr));
26635f757f3fSDimitry Andric             if (str_origin != nullptr)
26645f757f3fSDimitry Andric             *str_origin++ = 0;
26655f757f3fSDimitry Andric           }
26665f757f3fSDimitry Andric           end_fmt = true;
26675f757f3fSDimitry Andric           break;
26685f757f3fSDimitry Andric         }
26695f757f3fSDimitry Andric 
26705f757f3fSDimitry Andric         case '%':
26715f757f3fSDimitry Andric           read_count = formatter.scan();
26725f757f3fSDimitry Andric           end_fmt = true;
26735f757f3fSDimitry Andric           break;
26745f757f3fSDimitry Andric 
26755f757f3fSDimitry Andric         case '*':
26765f757f3fSDimitry Andric           formatter.skip = true;
26775f757f3fSDimitry Andric           break;
26785f757f3fSDimitry Andric 
26795f757f3fSDimitry Andric         default:
26805f757f3fSDimitry Andric           break;
26815f757f3fSDimitry Andric         }
26825f757f3fSDimitry Andric       }
26835f757f3fSDimitry Andric     }
26845f757f3fSDimitry Andric 
26855f757f3fSDimitry Andric     if (read_count < 0) {
26865f757f3fSDimitry Andric       // There was an error.
26875f757f3fSDimitry Andric       return read_count;
26885f757f3fSDimitry Andric     }
26895f757f3fSDimitry Andric 
26905f757f3fSDimitry Andric     formatter.fmt_cur++;
26915f757f3fSDimitry Andric     formatter.str_off += read_count;
26925f757f3fSDimitry Andric   }
26935f757f3fSDimitry Andric 
26945f757f3fSDimitry Andric   (void)va_labels; // Silence unused-but-set-parameter warning
26955f757f3fSDimitry Andric   *ret_label = 0;
26965f757f3fSDimitry Andric   if (ret_origin)
26975f757f3fSDimitry Andric     *ret_origin = 0;
26985f757f3fSDimitry Andric 
26995f757f3fSDimitry Andric   // Number of items scanned in total.
27005f757f3fSDimitry Andric   return formatter.num_scanned;
27015f757f3fSDimitry Andric }
27025f757f3fSDimitry Andric 
270368d75effSDimitry Andric extern "C" {
270468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
270568d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
270668d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
270768d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
270868d75effSDimitry Andric   va_list ap;
270968d75effSDimitry Andric   va_start(ap, ret_label);
27105f757f3fSDimitry Andric 
27117a6dacacSDimitry Andric   int ret = format_buffer(str, INT32_MAX, format, va_labels, ret_label, nullptr,
2712fe6060f1SDimitry Andric                           nullptr, ap);
2713fe6060f1SDimitry Andric   va_end(ap);
2714fe6060f1SDimitry Andric   return ret;
2715fe6060f1SDimitry Andric }
2716fe6060f1SDimitry Andric 
2717fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2718fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
2719fe6060f1SDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
2720fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin str_origin,
2721fe6060f1SDimitry Andric                    dfsan_origin format_origin, dfsan_origin *va_origins,
2722fe6060f1SDimitry Andric                    dfsan_origin *ret_origin, ...) {
2723fe6060f1SDimitry Andric   va_list ap;
2724fe6060f1SDimitry Andric   va_start(ap, ret_origin);
27257a6dacacSDimitry Andric   int ret = format_buffer(str, INT32_MAX, format, va_labels, ret_label,
27267a6dacacSDimitry Andric                           va_origins, ret_origin, ap);
272768d75effSDimitry Andric   va_end(ap);
272868d75effSDimitry Andric   return ret;
272968d75effSDimitry Andric }
273068d75effSDimitry Andric 
273168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
273268d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
273368d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
273468d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
273568d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
273668d75effSDimitry Andric   va_list ap;
273768d75effSDimitry Andric   va_start(ap, ret_label);
2738fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
2739fe6060f1SDimitry Andric                           nullptr, ap);
274068d75effSDimitry Andric   va_end(ap);
274168d75effSDimitry Andric   return ret;
274268d75effSDimitry Andric }
274368d75effSDimitry Andric 
2744fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2745fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format,
2746fe6060f1SDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
2747fe6060f1SDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
2748fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin str_origin,
2749fe6060f1SDimitry Andric                     dfsan_origin size_origin, dfsan_origin format_origin,
2750fe6060f1SDimitry Andric                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
2751fe6060f1SDimitry Andric   va_list ap;
2752fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2753fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
2754fe6060f1SDimitry Andric                           ret_origin, ap);
2755fe6060f1SDimitry Andric   va_end(ap);
2756fe6060f1SDimitry Andric   return ret;
2757fe6060f1SDimitry Andric }
2758fe6060f1SDimitry Andric 
27595f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
27605f757f3fSDimitry Andric int __dfsw_sscanf(char *str, const char *format, dfsan_label str_label,
27615f757f3fSDimitry Andric                   dfsan_label format_label, dfsan_label *va_labels,
27625f757f3fSDimitry Andric                   dfsan_label *ret_label, ...) {
27635f757f3fSDimitry Andric   va_list ap;
27645f757f3fSDimitry Andric   va_start(ap, ret_label);
27655f757f3fSDimitry Andric   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
27665f757f3fSDimitry Andric                         nullptr, ap);
27675f757f3fSDimitry Andric   va_end(ap);
27685f757f3fSDimitry Andric   return ret;
27695f757f3fSDimitry Andric }
27705f757f3fSDimitry Andric 
27715f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
27725f757f3fSDimitry Andric int __dfso_sscanf(char *str, const char *format, dfsan_label str_label,
27735f757f3fSDimitry Andric                   dfsan_label format_label, dfsan_label *va_labels,
27745f757f3fSDimitry Andric                   dfsan_label *ret_label, dfsan_origin str_origin,
27755f757f3fSDimitry Andric                   dfsan_origin format_origin, dfsan_origin *va_origins,
27765f757f3fSDimitry Andric                   dfsan_origin *ret_origin, ...) {
27775f757f3fSDimitry Andric   va_list ap;
27785f757f3fSDimitry Andric   va_start(ap, ret_origin);
27795f757f3fSDimitry Andric   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, &str_origin,
27805f757f3fSDimitry Andric                         ret_origin, ap);
27815f757f3fSDimitry Andric   va_end(ap);
27825f757f3fSDimitry Andric   return ret;
27835f757f3fSDimitry Andric }
27845f757f3fSDimitry Andric 
2785*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc99_sscanf, sscanf)
2786*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_sscanf, sscanf)
27875f757f3fSDimitry Andric 
2788fe6060f1SDimitry Andric static void BeforeFork() {
2789cb14a3feSDimitry Andric   StackDepotLockBeforeFork();
2790cb14a3feSDimitry Andric   ChainedOriginDepotLockBeforeFork();
2791fe6060f1SDimitry Andric }
2792fe6060f1SDimitry Andric 
2793cb14a3feSDimitry Andric static void AfterFork(bool fork_child) {
2794cb14a3feSDimitry Andric   ChainedOriginDepotUnlockAfterFork(fork_child);
2795cb14a3feSDimitry Andric   StackDepotUnlockAfterFork(fork_child);
2796fe6060f1SDimitry Andric }
2797fe6060f1SDimitry Andric 
2798fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2799fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) {
2800fe6060f1SDimitry Andric   pid_t pid = fork();
2801fe6060f1SDimitry Andric   *ret_label = 0;
2802fe6060f1SDimitry Andric   return pid;
2803fe6060f1SDimitry Andric }
2804fe6060f1SDimitry Andric 
2805fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2806fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
2807fe6060f1SDimitry Andric   BeforeFork();
2808fe6060f1SDimitry Andric   pid_t pid = __dfsw_fork(ret_label);
2809cb14a3feSDimitry Andric   AfterFork(/* fork_child= */ pid == 0);
2810fe6060f1SDimitry Andric   return pid;
2811fe6060f1SDimitry Andric }
2812fe6060f1SDimitry Andric 
281368d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
281468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
281568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
281668d75effSDimitry Andric                              u32 *) {}
2817349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
2818349cc55cSDimitry Andric                              const uptr *end) {}
281968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
282068d75effSDimitry Andric 
282168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
282268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
282368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
282468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
282568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
282668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
282768d75effSDimitry Andric                              void) {}
282868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
282968d75effSDimitry Andric                              void) {}
283068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
283168d75effSDimitry Andric                              void) {}
283268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
283368d75effSDimitry Andric                              void) {}
283468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
283568d75effSDimitry Andric }  // extern "C"
2836