xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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 
58fe6060f1SDimitry Andric // Async-safe, non-reentrant spin lock.
59fe6060f1SDimitry Andric class SignalSpinLocker {
60fe6060f1SDimitry Andric  public:
61fe6060f1SDimitry Andric   SignalSpinLocker() {
62fe6060f1SDimitry Andric     sigset_t all_set;
63fe6060f1SDimitry Andric     sigfillset(&all_set);
64fe6060f1SDimitry Andric     pthread_sigmask(SIG_SETMASK, &all_set, &saved_thread_mask_);
65fe6060f1SDimitry Andric     sigactions_mu.Lock();
66fe6060f1SDimitry Andric   }
67fe6060f1SDimitry Andric   ~SignalSpinLocker() {
68fe6060f1SDimitry Andric     sigactions_mu.Unlock();
69fe6060f1SDimitry Andric     pthread_sigmask(SIG_SETMASK, &saved_thread_mask_, nullptr);
70fe6060f1SDimitry Andric   }
71fe6060f1SDimitry Andric 
72fe6060f1SDimitry Andric  private:
73fe6060f1SDimitry Andric   static StaticSpinMutex sigactions_mu;
74fe6060f1SDimitry Andric   sigset_t saved_thread_mask_;
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric   SignalSpinLocker(const SignalSpinLocker &) = delete;
77fe6060f1SDimitry Andric   SignalSpinLocker &operator=(const SignalSpinLocker &) = delete;
78fe6060f1SDimitry Andric };
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric StaticSpinMutex SignalSpinLocker::sigactions_mu;
81fe6060f1SDimitry Andric 
8268d75effSDimitry Andric extern "C" {
8368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
8468d75effSDimitry Andric __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
8568d75effSDimitry Andric             dfsan_label buf_label, dfsan_label *ret_label) {
8668d75effSDimitry Andric   int ret = stat(path, buf);
8768d75effSDimitry Andric   if (ret == 0)
8868d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
8968d75effSDimitry Andric   *ret_label = 0;
9068d75effSDimitry Andric   return ret;
9168d75effSDimitry Andric }
9268d75effSDimitry Andric 
93fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_stat(
94fe6060f1SDimitry Andric     const char *path, struct stat *buf, dfsan_label path_label,
95fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label *ret_label, dfsan_origin path_origin,
96fe6060f1SDimitry Andric     dfsan_origin buf_origin, dfsan_origin *ret_origin) {
97fe6060f1SDimitry Andric   int ret = __dfsw_stat(path, buf, path_label, buf_label, ret_label);
98fe6060f1SDimitry Andric   return ret;
99fe6060f1SDimitry Andric }
100fe6060f1SDimitry Andric 
10168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
10268d75effSDimitry Andric                                                dfsan_label fd_label,
10368d75effSDimitry Andric                                                dfsan_label buf_label,
10468d75effSDimitry Andric                                                dfsan_label *ret_label) {
10568d75effSDimitry Andric   int ret = fstat(fd, buf);
10668d75effSDimitry Andric   if (ret == 0)
10768d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
10868d75effSDimitry Andric   *ret_label = 0;
10968d75effSDimitry Andric   return ret;
11068d75effSDimitry Andric }
11168d75effSDimitry Andric 
112fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_fstat(
113fe6060f1SDimitry Andric     int fd, struct stat *buf, dfsan_label fd_label, dfsan_label buf_label,
114fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
115fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
116fe6060f1SDimitry Andric   int ret = __dfsw_fstat(fd, buf, fd_label, buf_label, ret_label);
117fe6060f1SDimitry Andric   return ret;
118fe6060f1SDimitry Andric }
119fe6060f1SDimitry Andric 
120fe6060f1SDimitry Andric static char *dfsan_strchr_with_label(const char *s, int c, size_t *bytes_read,
121fe6060f1SDimitry Andric                                      dfsan_label s_label, dfsan_label c_label,
122fe6060f1SDimitry Andric                                      dfsan_label *ret_label) {
123fe6060f1SDimitry Andric   char *match_pos = nullptr;
124fe6060f1SDimitry Andric   for (size_t i = 0;; ++i) {
125fe6060f1SDimitry Andric     if (s[i] == c || s[i] == 0) {
126fe6060f1SDimitry Andric       // If s[i] is the \0 at the end of the string, and \0 is not the
127fe6060f1SDimitry Andric       // character we are searching for, then return null.
128fe6060f1SDimitry Andric       *bytes_read = i + 1;
129fe6060f1SDimitry Andric       match_pos = s[i] == 0 && c != 0 ? nullptr : const_cast<char *>(s + i);
130fe6060f1SDimitry Andric       break;
131fe6060f1SDimitry Andric     }
132fe6060f1SDimitry Andric   }
133fe6060f1SDimitry Andric   if (flags().strict_data_dependencies)
134fe6060f1SDimitry Andric     *ret_label = s_label;
135fe6060f1SDimitry Andric   else
136fe6060f1SDimitry Andric     *ret_label = dfsan_union(dfsan_read_label(s, *bytes_read),
137fe6060f1SDimitry Andric                              dfsan_union(s_label, c_label));
138fe6060f1SDimitry Andric   return match_pos;
139fe6060f1SDimitry Andric }
140fe6060f1SDimitry Andric 
14168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
14268d75effSDimitry Andric                                                   dfsan_label s_label,
14368d75effSDimitry Andric                                                   dfsan_label c_label,
14468d75effSDimitry Andric                                                   dfsan_label *ret_label) {
145fe6060f1SDimitry Andric   size_t bytes_read;
146fe6060f1SDimitry Andric   return dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label,
147fe6060f1SDimitry Andric                                  ret_label);
14868d75effSDimitry Andric }
1495ffd83dbSDimitry Andric 
150fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strchr(
151fe6060f1SDimitry Andric     const char *s, int c, dfsan_label s_label, dfsan_label c_label,
152fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
153fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
154fe6060f1SDimitry Andric   size_t bytes_read;
155fe6060f1SDimitry Andric   char *r =
156fe6060f1SDimitry Andric       dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label, ret_label);
157fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
158fe6060f1SDimitry Andric     *ret_origin = s_origin;
159fe6060f1SDimitry Andric   } else if (*ret_label) {
160fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, bytes_read);
161fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1625ffd83dbSDimitry Andric   }
163fe6060f1SDimitry Andric   return r;
16468d75effSDimitry Andric }
16568d75effSDimitry Andric 
166e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strpbrk(const char *s,
167e8d8bef9SDimitry Andric                                                    const char *accept,
168e8d8bef9SDimitry Andric                                                    dfsan_label s_label,
169e8d8bef9SDimitry Andric                                                    dfsan_label accept_label,
17068d75effSDimitry Andric                                                    dfsan_label *ret_label) {
171e8d8bef9SDimitry Andric   const char *ret = strpbrk(s, accept);
172e8d8bef9SDimitry Andric   if (flags().strict_data_dependencies) {
173e8d8bef9SDimitry Andric     *ret_label = ret ? s_label : 0;
174e8d8bef9SDimitry Andric   } else {
175e8d8bef9SDimitry Andric     size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
176e8d8bef9SDimitry Andric     *ret_label =
177e8d8bef9SDimitry Andric         dfsan_union(dfsan_read_label(s, s_bytes_read),
178e8d8bef9SDimitry Andric                     dfsan_union(dfsan_read_label(accept, strlen(accept) + 1),
179e8d8bef9SDimitry Andric                                 dfsan_union(s_label, accept_label)));
180e8d8bef9SDimitry Andric   }
181e8d8bef9SDimitry Andric   return const_cast<char *>(ret);
182e8d8bef9SDimitry Andric }
183e8d8bef9SDimitry Andric 
184fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strpbrk(
185fe6060f1SDimitry Andric     const char *s, const char *accept, dfsan_label s_label,
186fe6060f1SDimitry Andric     dfsan_label accept_label, dfsan_label *ret_label, dfsan_origin s_origin,
187fe6060f1SDimitry Andric     dfsan_origin accept_origin, dfsan_origin *ret_origin) {
188fe6060f1SDimitry Andric   const char *ret = __dfsw_strpbrk(s, accept, s_label, accept_label, ret_label);
189fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
190fe6060f1SDimitry Andric     if (ret)
191fe6060f1SDimitry Andric       *ret_origin = s_origin;
192fe6060f1SDimitry Andric   } else {
193fe6060f1SDimitry Andric     if (*ret_label) {
194fe6060f1SDimitry Andric       size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
195fe6060f1SDimitry Andric       dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_bytes_read);
196fe6060f1SDimitry Andric       if (o) {
197fe6060f1SDimitry Andric         *ret_origin = o;
198fe6060f1SDimitry Andric       } else {
199fe6060f1SDimitry Andric         o = dfsan_read_origin_of_first_taint(accept, strlen(accept) + 1);
200fe6060f1SDimitry Andric         *ret_origin = o ? o : (s_label ? s_origin : accept_origin);
201fe6060f1SDimitry Andric       }
202fe6060f1SDimitry Andric     }
203fe6060f1SDimitry Andric   }
204fe6060f1SDimitry Andric   return const_cast<char *>(ret);
205fe6060f1SDimitry Andric }
206fe6060f1SDimitry Andric 
20706c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strsep(char **s, const char *delim,
20806c3fb27SDimitry Andric                                                   dfsan_label s_label,
20906c3fb27SDimitry Andric                                                   dfsan_label delim_label,
21006c3fb27SDimitry Andric                                                   dfsan_label *ret_label) {
21106c3fb27SDimitry Andric   dfsan_label base_label = dfsan_read_label(s, sizeof(*s));
21206c3fb27SDimitry Andric   char *base = *s;
21306c3fb27SDimitry Andric   char *res = strsep(s, delim);
21406c3fb27SDimitry Andric   if (res != *s) {
21506c3fb27SDimitry Andric     char *token_start = res;
21606c3fb27SDimitry Andric     int token_length = strlen(res);
21706c3fb27SDimitry Andric     // the delimiter byte has been set to NULL
21806c3fb27SDimitry Andric     dfsan_set_label(0, token_start + token_length, 1);
21906c3fb27SDimitry Andric   }
22006c3fb27SDimitry Andric 
22106c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
22206c3fb27SDimitry Andric     *ret_label = res ? base_label : 0;
22306c3fb27SDimitry Andric   } else {
22406c3fb27SDimitry Andric     size_t s_bytes_read = (res ? strlen(res) : strlen(base)) + 1;
22506c3fb27SDimitry Andric     *ret_label = dfsan_union(
22606c3fb27SDimitry Andric         dfsan_union(base_label, dfsan_read_label(base, sizeof(s_bytes_read))),
22706c3fb27SDimitry Andric         dfsan_union(dfsan_read_label(delim, strlen(delim) + 1),
22806c3fb27SDimitry Andric                     dfsan_union(s_label, delim_label)));
22906c3fb27SDimitry Andric   }
23006c3fb27SDimitry Andric 
23106c3fb27SDimitry Andric   return res;
23206c3fb27SDimitry Andric }
23306c3fb27SDimitry Andric 
23406c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strsep(
23506c3fb27SDimitry Andric     char **s, const char *delim, dfsan_label s_label, dfsan_label delim_label,
23606c3fb27SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin delim_origin,
23706c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
23806c3fb27SDimitry Andric   dfsan_origin base_origin = dfsan_read_origin_of_first_taint(s, sizeof(*s));
23906c3fb27SDimitry Andric   char *res = __dfsw_strsep(s, delim, s_label, delim_label, ret_label);
24006c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
24106c3fb27SDimitry Andric     if (res)
24206c3fb27SDimitry Andric       *ret_origin = base_origin;
24306c3fb27SDimitry Andric   } else {
24406c3fb27SDimitry Andric     if (*ret_label) {
24506c3fb27SDimitry Andric       if (base_origin) {
24606c3fb27SDimitry Andric         *ret_origin = base_origin;
24706c3fb27SDimitry Andric       } else {
24806c3fb27SDimitry Andric         dfsan_origin o =
24906c3fb27SDimitry Andric             dfsan_read_origin_of_first_taint(delim, strlen(delim) + 1);
25006c3fb27SDimitry Andric         *ret_origin = o ? o : (s_label ? s_origin : delim_origin);
25106c3fb27SDimitry Andric       }
25206c3fb27SDimitry Andric     }
25306c3fb27SDimitry Andric   }
25406c3fb27SDimitry Andric 
25506c3fb27SDimitry Andric   return res;
25606c3fb27SDimitry Andric }
25706c3fb27SDimitry Andric 
258e8d8bef9SDimitry Andric static int dfsan_memcmp_bcmp(const void *s1, const void *s2, size_t n,
259fe6060f1SDimitry Andric                              size_t *bytes_read) {
26068d75effSDimitry Andric   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
26168d75effSDimitry Andric   for (size_t i = 0; i != n; ++i) {
26268d75effSDimitry Andric     if (cs1[i] != cs2[i]) {
263fe6060f1SDimitry Andric       *bytes_read = i + 1;
26468d75effSDimitry Andric       return cs1[i] - cs2[i];
26568d75effSDimitry Andric     }
26668d75effSDimitry Andric   }
267fe6060f1SDimitry Andric   *bytes_read = n;
26868d75effSDimitry Andric   return 0;
26968d75effSDimitry Andric }
27068d75effSDimitry Andric 
271fe6060f1SDimitry Andric static dfsan_label dfsan_get_memcmp_label(const void *s1, const void *s2,
272fe6060f1SDimitry Andric                                           size_t pos) {
273fe6060f1SDimitry Andric   if (flags().strict_data_dependencies)
274fe6060f1SDimitry Andric     return 0;
275fe6060f1SDimitry Andric   return dfsan_union(dfsan_read_label(s1, pos), dfsan_read_label(s2, pos));
276fe6060f1SDimitry Andric }
277fe6060f1SDimitry Andric 
278fe6060f1SDimitry Andric static void dfsan_get_memcmp_origin(const void *s1, const void *s2, size_t pos,
279fe6060f1SDimitry Andric                                     dfsan_label *ret_label,
280fe6060f1SDimitry Andric                                     dfsan_origin *ret_origin) {
281fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, pos);
282fe6060f1SDimitry Andric   if (*ret_label == 0)
283fe6060f1SDimitry Andric     return;
284fe6060f1SDimitry Andric   dfsan_origin o = dfsan_read_origin_of_first_taint(s1, pos);
285fe6060f1SDimitry Andric   *ret_origin = o ? o : dfsan_read_origin_of_first_taint(s2, pos);
286fe6060f1SDimitry Andric }
287fe6060f1SDimitry Andric 
288fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_label(const void *s1, const void *s2, size_t n,
289fe6060f1SDimitry Andric                                    dfsan_label *ret_label) {
290fe6060f1SDimitry Andric   size_t bytes_read;
291fe6060f1SDimitry Andric   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
292fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
293fe6060f1SDimitry Andric   return r;
294fe6060f1SDimitry Andric }
295fe6060f1SDimitry Andric 
296fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_origin(const void *s1, const void *s2, size_t n,
297fe6060f1SDimitry Andric                                     dfsan_label *ret_label,
298fe6060f1SDimitry Andric                                     dfsan_origin *ret_origin) {
299fe6060f1SDimitry Andric   size_t bytes_read;
300fe6060f1SDimitry Andric   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
301fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
302fe6060f1SDimitry Andric   return r;
303fe6060f1SDimitry Andric }
304fe6060f1SDimitry Andric 
305e8d8bef9SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
306e8d8bef9SDimitry Andric                               const void *s1, const void *s2, size_t n,
307e8d8bef9SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
308e8d8bef9SDimitry Andric                               dfsan_label n_label)
309e8d8bef9SDimitry Andric 
310fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, uptr caller_pc,
311fe6060f1SDimitry Andric                               const void *s1, const void *s2, size_t n,
312fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
313fe6060f1SDimitry Andric                               dfsan_label n_label, dfsan_origin s1_origin,
314fe6060f1SDimitry Andric                               dfsan_origin s2_origin, dfsan_origin n_origin)
315fe6060f1SDimitry Andric 
316e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
317e8d8bef9SDimitry Andric                                                 size_t n, dfsan_label s1_label,
318e8d8bef9SDimitry Andric                                                 dfsan_label s2_label,
319e8d8bef9SDimitry Andric                                                 dfsan_label n_label,
320e8d8bef9SDimitry Andric                                                 dfsan_label *ret_label) {
321e8d8bef9SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
322e8d8bef9SDimitry Andric                              s1_label, s2_label, n_label);
323fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
324fe6060f1SDimitry Andric }
325fe6060f1SDimitry Andric 
326fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_memcmp(
327fe6060f1SDimitry Andric     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
328fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
329fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
330fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
331fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, GET_CALLER_PC(), s1,
332fe6060f1SDimitry Andric                              s2, n, s1_label, s2_label, n_label, s1_origin,
333fe6060f1SDimitry Andric                              s2_origin, n_origin);
334fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
335e8d8bef9SDimitry Andric }
336e8d8bef9SDimitry Andric 
337e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_bcmp(const void *s1, const void *s2,
338e8d8bef9SDimitry Andric                                               size_t n, dfsan_label s1_label,
339e8d8bef9SDimitry Andric                                               dfsan_label s2_label,
340e8d8bef9SDimitry Andric                                               dfsan_label n_label,
341e8d8bef9SDimitry Andric                                               dfsan_label *ret_label) {
342fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
343fe6060f1SDimitry Andric }
344fe6060f1SDimitry Andric 
345fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_bcmp(
346fe6060f1SDimitry Andric     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
347fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
348fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
349fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
350fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
351fe6060f1SDimitry Andric }
352fe6060f1SDimitry Andric 
353fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit.
354fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2.
355fe6060f1SDimitry Andric static int dfsan_strncmp(const char *s1, const char *s2, size_t n,
356fe6060f1SDimitry Andric                          size_t *bytes_read) {
357fe6060f1SDimitry Andric   for (size_t i = 0;; ++i) {
358fe6060f1SDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || (n > 0 && i == n - 1)) {
359fe6060f1SDimitry Andric       *bytes_read = i + 1;
360fe6060f1SDimitry Andric       return s1[i] - s2[i];
361fe6060f1SDimitry Andric     }
362fe6060f1SDimitry Andric   }
363e8d8bef9SDimitry Andric }
364e8d8bef9SDimitry Andric 
36568d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
36668d75effSDimitry Andric                               const char *s1, const char *s2,
36768d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label)
36868d75effSDimitry Andric 
369fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, uptr caller_pc,
370fe6060f1SDimitry Andric                               const char *s1, const char *s2,
371fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
372fe6060f1SDimitry Andric                               dfsan_origin s1_origin, dfsan_origin s2_origin)
373fe6060f1SDimitry Andric 
37468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
37568d75effSDimitry Andric                                                 dfsan_label s1_label,
37668d75effSDimitry Andric                                                 dfsan_label s2_label,
37768d75effSDimitry Andric                                                 dfsan_label *ret_label) {
37868d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
37968d75effSDimitry Andric                              s1_label, s2_label);
380fe6060f1SDimitry Andric   size_t bytes_read;
381fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
382fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
383fe6060f1SDimitry Andric   return r;
38468d75effSDimitry Andric }
38568d75effSDimitry Andric 
386fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcmp(
387fe6060f1SDimitry Andric     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
388fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
389fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
390fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, GET_CALLER_PC(), s1,
391fe6060f1SDimitry Andric                              s2, s1_label, s2_label, s1_origin, s2_origin);
392fe6060f1SDimitry Andric   size_t bytes_read;
393fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
394fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
395fe6060f1SDimitry Andric   return r;
396fe6060f1SDimitry Andric }
397fe6060f1SDimitry Andric 
398fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit.
399fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2.
400fe6060f1SDimitry Andric static int dfsan_strncasecmp(const char *s1, const char *s2, size_t n,
401fe6060f1SDimitry Andric                              size_t *bytes_read) {
40268d75effSDimitry Andric   for (size_t i = 0;; ++i) {
4035ffd83dbSDimitry Andric     char s1_lower = tolower(s1[i]);
4045ffd83dbSDimitry Andric     char s2_lower = tolower(s2[i]);
4055ffd83dbSDimitry Andric 
406fe6060f1SDimitry Andric     if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0 ||
407fe6060f1SDimitry Andric         (n > 0 && i == n - 1)) {
408fe6060f1SDimitry Andric       *bytes_read = i + 1;
4095ffd83dbSDimitry Andric       return s1_lower - s2_lower;
41068d75effSDimitry Andric     }
41168d75effSDimitry Andric   }
412fe6060f1SDimitry Andric }
413fe6060f1SDimitry Andric 
414fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcasecmp(const char *s1,
415fe6060f1SDimitry Andric                                                     const char *s2,
416fe6060f1SDimitry Andric                                                     dfsan_label s1_label,
417fe6060f1SDimitry Andric                                                     dfsan_label s2_label,
418fe6060f1SDimitry Andric                                                     dfsan_label *ret_label) {
419fe6060f1SDimitry Andric   size_t bytes_read;
420fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
421fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
422fe6060f1SDimitry Andric   return r;
423fe6060f1SDimitry Andric }
424fe6060f1SDimitry Andric 
425fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcasecmp(
426fe6060f1SDimitry Andric     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
427fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
428fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
429fe6060f1SDimitry Andric   size_t bytes_read;
430fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
431fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
432fe6060f1SDimitry Andric   return r;
43368d75effSDimitry Andric }
43468d75effSDimitry Andric 
43568d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
43668d75effSDimitry Andric                               const char *s1, const char *s2, size_t n,
43768d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
43868d75effSDimitry Andric                               dfsan_label n_label)
43968d75effSDimitry Andric 
440fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, uptr caller_pc,
441fe6060f1SDimitry Andric                               const char *s1, const char *s2, size_t n,
442fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
443fe6060f1SDimitry Andric                               dfsan_label n_label, dfsan_origin s1_origin,
444fe6060f1SDimitry Andric                               dfsan_origin s2_origin, dfsan_origin n_origin)
445fe6060f1SDimitry Andric 
44668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
44768d75effSDimitry Andric                                                  size_t n, dfsan_label s1_label,
44868d75effSDimitry Andric                                                  dfsan_label s2_label,
44968d75effSDimitry Andric                                                  dfsan_label n_label,
45068d75effSDimitry Andric                                                  dfsan_label *ret_label) {
45168d75effSDimitry Andric   if (n == 0) {
45268d75effSDimitry Andric     *ret_label = 0;
45368d75effSDimitry Andric     return 0;
45468d75effSDimitry Andric   }
45568d75effSDimitry Andric 
45668d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
45768d75effSDimitry Andric                              n, s1_label, s2_label, n_label);
45868d75effSDimitry Andric 
459fe6060f1SDimitry Andric   size_t bytes_read;
460fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
461fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
462fe6060f1SDimitry Andric   return r;
46368d75effSDimitry Andric }
46468d75effSDimitry Andric 
465fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncmp(
466fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
467fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
468fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
469fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
47068d75effSDimitry Andric   if (n == 0) {
47168d75effSDimitry Andric     *ret_label = 0;
47268d75effSDimitry Andric     return 0;
47368d75effSDimitry Andric   }
47468d75effSDimitry Andric 
475fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, GET_CALLER_PC(),
476fe6060f1SDimitry Andric                              s1, s2, n, s1_label, s2_label, n_label, s1_origin,
477fe6060f1SDimitry Andric                              s2_origin, n_origin);
4785ffd83dbSDimitry Andric 
479fe6060f1SDimitry Andric   size_t bytes_read;
480fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
481fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
482fe6060f1SDimitry Andric   return r;
483fe6060f1SDimitry Andric }
484fe6060f1SDimitry Andric 
485fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncasecmp(
486fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
487fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) {
488fe6060f1SDimitry Andric   if (n == 0) {
48968d75effSDimitry Andric     *ret_label = 0;
49068d75effSDimitry Andric     return 0;
49168d75effSDimitry Andric   }
49268d75effSDimitry Andric 
493fe6060f1SDimitry Andric   size_t bytes_read;
494fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
495fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
496fe6060f1SDimitry Andric   return r;
49768d75effSDimitry Andric }
49868d75effSDimitry Andric 
499fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncasecmp(
500fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
501fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
502fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
503fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
504fe6060f1SDimitry Andric   if (n == 0) {
505fe6060f1SDimitry Andric     *ret_label = 0;
506fe6060f1SDimitry Andric     return 0;
507fe6060f1SDimitry Andric   }
508fe6060f1SDimitry Andric 
509fe6060f1SDimitry Andric   size_t bytes_read;
510fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
511fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
512fe6060f1SDimitry Andric   return r;
513fe6060f1SDimitry Andric }
514fe6060f1SDimitry Andric 
515fe6060f1SDimitry Andric 
51668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t
51768d75effSDimitry Andric __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
51868d75effSDimitry Andric   size_t ret = strlen(s);
51968d75effSDimitry Andric   if (flags().strict_data_dependencies) {
52068d75effSDimitry Andric     *ret_label = 0;
52168d75effSDimitry Andric   } else {
52268d75effSDimitry Andric     *ret_label = dfsan_read_label(s, ret + 1);
52368d75effSDimitry Andric   }
52468d75effSDimitry Andric   return ret;
52568d75effSDimitry Andric }
52668d75effSDimitry Andric 
527fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s,
528fe6060f1SDimitry Andric                                                    dfsan_label s_label,
529fe6060f1SDimitry Andric                                                    dfsan_label *ret_label,
530fe6060f1SDimitry Andric                                                    dfsan_origin s_origin,
531fe6060f1SDimitry Andric                                                    dfsan_origin *ret_origin) {
532fe6060f1SDimitry Andric   size_t ret = __dfsw_strlen(s, s_label, ret_label);
533fe6060f1SDimitry Andric   if (!flags().strict_data_dependencies)
534fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1);
535fe6060f1SDimitry Andric   return ret;
536fe6060f1SDimitry Andric }
537fe6060f1SDimitry Andric 
53806c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strnlen(const char *s,
53906c3fb27SDimitry Andric                                                     size_t maxlen,
54006c3fb27SDimitry Andric                                                     dfsan_label s_label,
54106c3fb27SDimitry Andric                                                     dfsan_label maxlen_label,
54206c3fb27SDimitry Andric                                                     dfsan_label *ret_label) {
54306c3fb27SDimitry Andric   size_t ret = strnlen(s, maxlen);
54406c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
54506c3fb27SDimitry Andric     *ret_label = 0;
54606c3fb27SDimitry Andric   } else {
54706c3fb27SDimitry Andric     size_t full_len = strlen(s);
54806c3fb27SDimitry Andric     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
54906c3fb27SDimitry Andric     *ret_label = dfsan_union(maxlen_label, dfsan_read_label(s, covered_len));
55006c3fb27SDimitry Andric   }
55106c3fb27SDimitry Andric   return ret;
55206c3fb27SDimitry Andric }
55306c3fb27SDimitry Andric 
55406c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strnlen(
55506c3fb27SDimitry Andric     const char *s, size_t maxlen, dfsan_label s_label, dfsan_label maxlen_label,
55606c3fb27SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin maxlen_origin,
55706c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
55806c3fb27SDimitry Andric   size_t ret = __dfsw_strnlen(s, maxlen, s_label, maxlen_label, ret_label);
55906c3fb27SDimitry Andric   if (!flags().strict_data_dependencies) {
56006c3fb27SDimitry Andric     size_t full_len = strlen(s);
56106c3fb27SDimitry Andric     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
56206c3fb27SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, covered_len);
56306c3fb27SDimitry Andric     *ret_origin = o ? o : maxlen_origin;
56406c3fb27SDimitry Andric   }
56506c3fb27SDimitry Andric   return ret;
56606c3fb27SDimitry Andric }
56706c3fb27SDimitry Andric 
568fe6060f1SDimitry Andric static void *dfsan_memmove(void *dest, const void *src, size_t n) {
569fe6060f1SDimitry Andric   dfsan_label *sdest = shadow_for(dest);
570fe6060f1SDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
571fe6060f1SDimitry Andric   internal_memmove((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
572fe6060f1SDimitry Andric   return internal_memmove(dest, src, n);
573fe6060f1SDimitry Andric }
574fe6060f1SDimitry Andric 
575fe6060f1SDimitry Andric static void *dfsan_memmove_with_origin(void *dest, const void *src, size_t n) {
576fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
577fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
578fe6060f1SDimitry Andric }
57968d75effSDimitry Andric 
58068d75effSDimitry Andric static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
58104eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest, src, n);
58268d75effSDimitry Andric   return internal_memcpy(dest, src, n);
58368d75effSDimitry Andric }
58468d75effSDimitry Andric 
585fe6060f1SDimitry Andric static void *dfsan_memcpy_with_origin(void *dest, const void *src, size_t n) {
586fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
587fe6060f1SDimitry Andric   return dfsan_memcpy(dest, src, n);
588fe6060f1SDimitry Andric }
589fe6060f1SDimitry Andric 
59068d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
59168d75effSDimitry Andric   internal_memset(s, c, n);
59268d75effSDimitry Andric   dfsan_set_label(c_label, s, n);
59368d75effSDimitry Andric }
59468d75effSDimitry Andric 
595fe6060f1SDimitry Andric static void dfsan_memset_with_origin(void *s, int c, dfsan_label c_label,
596fe6060f1SDimitry Andric                                      dfsan_origin c_origin, size_t n) {
597fe6060f1SDimitry Andric   internal_memset(s, c, n);
598fe6060f1SDimitry Andric   dfsan_set_label_origin(c_label, c_origin, s, n);
599fe6060f1SDimitry Andric }
600fe6060f1SDimitry Andric 
60168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
60268d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n,
60368d75effSDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
60468d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
60568d75effSDimitry Andric   *ret_label = dest_label;
60668d75effSDimitry Andric   return dfsan_memcpy(dest, src, n);
60768d75effSDimitry Andric }
60868d75effSDimitry Andric 
60968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
610fe6060f1SDimitry Andric void *__dfso_memcpy(void *dest, const void *src, size_t n,
611fe6060f1SDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
612fe6060f1SDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label,
613fe6060f1SDimitry Andric                     dfsan_origin dest_origin, dfsan_origin src_origin,
614fe6060f1SDimitry Andric                     dfsan_origin n_origin, dfsan_origin *ret_origin) {
615fe6060f1SDimitry Andric   *ret_label = dest_label;
616fe6060f1SDimitry Andric   *ret_origin = dest_origin;
617fe6060f1SDimitry Andric   return dfsan_memcpy_with_origin(dest, src, n);
618fe6060f1SDimitry Andric }
619fe6060f1SDimitry Andric 
620fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
621fe6060f1SDimitry Andric void *__dfsw_memmove(void *dest, const void *src, size_t n,
622fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
623fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label) {
624fe6060f1SDimitry Andric   *ret_label = dest_label;
625fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
626fe6060f1SDimitry Andric }
627fe6060f1SDimitry Andric 
628fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
629fe6060f1SDimitry Andric void *__dfso_memmove(void *dest, const void *src, size_t n,
630fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
631fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label,
632fe6060f1SDimitry Andric                      dfsan_origin dest_origin, dfsan_origin src_origin,
633fe6060f1SDimitry Andric                      dfsan_origin n_origin, dfsan_origin *ret_origin) {
634fe6060f1SDimitry Andric   *ret_label = dest_label;
635fe6060f1SDimitry Andric   *ret_origin = dest_origin;
636fe6060f1SDimitry Andric   return dfsan_memmove_with_origin(dest, src, n);
637fe6060f1SDimitry Andric }
638fe6060f1SDimitry Andric 
639fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
64068d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n,
64168d75effSDimitry Andric                     dfsan_label s_label, dfsan_label c_label,
64268d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
64368d75effSDimitry Andric   dfsan_memset(s, c, c_label, n);
64468d75effSDimitry Andric   *ret_label = s_label;
64568d75effSDimitry Andric   return s;
64668d75effSDimitry Andric }
64768d75effSDimitry Andric 
648fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
649fe6060f1SDimitry Andric void *__dfso_memset(void *s, int c, size_t n, dfsan_label s_label,
650fe6060f1SDimitry Andric                     dfsan_label c_label, dfsan_label n_label,
651fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin s_origin,
652fe6060f1SDimitry Andric                     dfsan_origin c_origin, dfsan_origin n_origin,
653fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
654fe6060f1SDimitry Andric   dfsan_memset_with_origin(s, c, c_label, c_origin, n);
655fe6060f1SDimitry Andric   *ret_label = s_label;
656fe6060f1SDimitry Andric   *ret_origin = s_origin;
657fe6060f1SDimitry Andric   return s;
658fe6060f1SDimitry Andric }
659fe6060f1SDimitry Andric 
660fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src,
661fe6060f1SDimitry Andric                                                   dfsan_label dest_label,
662fe6060f1SDimitry Andric                                                   dfsan_label src_label,
663fe6060f1SDimitry Andric                                                   dfsan_label *ret_label) {
664fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
665349cc55cSDimitry Andric   char *ret = strcat(dest, src);
66604eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, strlen(src));
667fe6060f1SDimitry Andric   *ret_label = dest_label;
668fe6060f1SDimitry Andric   return ret;
669fe6060f1SDimitry Andric }
670fe6060f1SDimitry Andric 
671fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat(
672fe6060f1SDimitry Andric     char *dest, const char *src, dfsan_label dest_label, dfsan_label src_label,
673fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin,
674fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
675fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
676349cc55cSDimitry Andric   char *ret = strcat(dest, src);
677fe6060f1SDimitry Andric   size_t src_len = strlen(src);
678fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
67904eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
680fe6060f1SDimitry Andric   *ret_label = dest_label;
681fe6060f1SDimitry Andric   *ret_origin = dest_origin;
682fe6060f1SDimitry Andric   return ret;
683fe6060f1SDimitry Andric }
684fe6060f1SDimitry Andric 
68506c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strncat(
68606c3fb27SDimitry Andric     char *dest, const char *src, size_t num, dfsan_label dest_label,
68706c3fb27SDimitry Andric     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label) {
68806c3fb27SDimitry Andric   size_t src_len = strlen(src);
68906c3fb27SDimitry Andric   src_len = src_len < num ? src_len : num;
69006c3fb27SDimitry Andric   size_t dest_len = strlen(dest);
69106c3fb27SDimitry Andric 
69206c3fb27SDimitry Andric   char *ret = strncat(dest, src, num);
69306c3fb27SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
69406c3fb27SDimitry Andric   *ret_label = dest_label;
69506c3fb27SDimitry Andric   return ret;
69606c3fb27SDimitry Andric }
69706c3fb27SDimitry Andric 
69806c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncat(
69906c3fb27SDimitry Andric     char *dest, const char *src, size_t num, dfsan_label dest_label,
70006c3fb27SDimitry Andric     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label,
70106c3fb27SDimitry Andric     dfsan_origin dest_origin, dfsan_origin src_origin, dfsan_origin num_origin,
70206c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
70306c3fb27SDimitry Andric   size_t src_len = strlen(src);
70406c3fb27SDimitry Andric   src_len = src_len < num ? src_len : num;
70506c3fb27SDimitry Andric   size_t dest_len = strlen(dest);
70606c3fb27SDimitry Andric 
70706c3fb27SDimitry Andric   char *ret = strncat(dest, src, num);
70806c3fb27SDimitry Andric 
70906c3fb27SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
71006c3fb27SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
71106c3fb27SDimitry Andric   *ret_label = dest_label;
71206c3fb27SDimitry Andric   *ret_origin = dest_origin;
71306c3fb27SDimitry Andric   return ret;
71406c3fb27SDimitry Andric }
71506c3fb27SDimitry Andric 
71668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
71768d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
71868d75effSDimitry Andric   size_t len = strlen(s);
71968d75effSDimitry Andric   void *p = malloc(len+1);
72068d75effSDimitry Andric   dfsan_memcpy(p, s, len+1);
72168d75effSDimitry Andric   *ret_label = 0;
72268d75effSDimitry Andric   return static_cast<char *>(p);
72368d75effSDimitry Andric }
72468d75effSDimitry Andric 
725fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strdup(const char *s,
726fe6060f1SDimitry Andric                                                   dfsan_label s_label,
727fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
728fe6060f1SDimitry Andric                                                   dfsan_origin s_origin,
729fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
730fe6060f1SDimitry Andric   size_t len = strlen(s);
731fe6060f1SDimitry Andric   void *p = malloc(len + 1);
732fe6060f1SDimitry Andric   dfsan_memcpy_with_origin(p, s, len + 1);
733fe6060f1SDimitry Andric   *ret_label = 0;
734fe6060f1SDimitry Andric   return static_cast<char *>(p);
735fe6060f1SDimitry Andric }
736fe6060f1SDimitry Andric 
73768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
73868d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
73968d75effSDimitry Andric                dfsan_label s2_label, dfsan_label n_label,
74068d75effSDimitry Andric                dfsan_label *ret_label) {
74168d75effSDimitry Andric   size_t len = strlen(s2);
74268d75effSDimitry Andric   if (len < n) {
74368d75effSDimitry Andric     dfsan_memcpy(s1, s2, len+1);
74468d75effSDimitry Andric     dfsan_memset(s1+len+1, 0, 0, n-len-1);
74568d75effSDimitry Andric   } else {
74668d75effSDimitry Andric     dfsan_memcpy(s1, s2, n);
74768d75effSDimitry Andric   }
74868d75effSDimitry Andric 
74968d75effSDimitry Andric   *ret_label = s1_label;
75068d75effSDimitry Andric   return s1;
75168d75effSDimitry Andric }
75268d75effSDimitry Andric 
753fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncpy(
754fe6060f1SDimitry Andric     char *s1, const char *s2, size_t n, dfsan_label s1_label,
755fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
756fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
757fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
758fe6060f1SDimitry Andric   size_t len = strlen(s2);
759fe6060f1SDimitry Andric   if (len < n) {
760fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, len + 1);
761fe6060f1SDimitry Andric     dfsan_memset_with_origin(s1 + len + 1, 0, 0, 0, n - len - 1);
762fe6060f1SDimitry Andric   } else {
763fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, n);
764fe6060f1SDimitry Andric   }
765fe6060f1SDimitry Andric 
766fe6060f1SDimitry Andric   *ret_label = s1_label;
767fe6060f1SDimitry Andric   *ret_origin = s1_origin;
768fe6060f1SDimitry Andric   return s1;
769fe6060f1SDimitry Andric }
770fe6060f1SDimitry Andric 
77168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
77268d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
77368d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
77468d75effSDimitry Andric              dfsan_label count_label, dfsan_label offset_label,
77568d75effSDimitry Andric              dfsan_label *ret_label) {
77668d75effSDimitry Andric   ssize_t ret = pread(fd, buf, count, offset);
77768d75effSDimitry Andric   if (ret > 0)
77868d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
77968d75effSDimitry Andric   *ret_label = 0;
78068d75effSDimitry Andric   return ret;
78168d75effSDimitry Andric }
78268d75effSDimitry Andric 
783fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_pread(
784fe6060f1SDimitry Andric     int fd, void *buf, size_t count, off_t offset, dfsan_label fd_label,
785fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label offset_label,
786fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
787fe6060f1SDimitry Andric     dfsan_origin count_origin, dfsan_label offset_origin,
788fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
789fe6060f1SDimitry Andric   return __dfsw_pread(fd, buf, count, offset, fd_label, buf_label, count_label,
790fe6060f1SDimitry Andric                       offset_label, ret_label);
791fe6060f1SDimitry Andric }
792fe6060f1SDimitry Andric 
79368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
79468d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count,
79568d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
79668d75effSDimitry Andric              dfsan_label count_label,
79768d75effSDimitry Andric              dfsan_label *ret_label) {
79868d75effSDimitry Andric   ssize_t ret = read(fd, buf, count);
79968d75effSDimitry Andric   if (ret > 0)
80068d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
80168d75effSDimitry Andric   *ret_label = 0;
80268d75effSDimitry Andric   return ret;
80368d75effSDimitry Andric }
80468d75effSDimitry Andric 
805fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_read(
806fe6060f1SDimitry Andric     int fd, void *buf, size_t count, dfsan_label fd_label,
807fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
808fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
809fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
810fe6060f1SDimitry Andric   return __dfsw_read(fd, buf, count, fd_label, buf_label, count_label,
811fe6060f1SDimitry Andric                      ret_label);
812fe6060f1SDimitry Andric }
813fe6060f1SDimitry Andric 
81468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
81568d75effSDimitry Andric                                                        struct timespec *tp,
81668d75effSDimitry Andric                                                        dfsan_label clk_id_label,
81768d75effSDimitry Andric                                                        dfsan_label tp_label,
81868d75effSDimitry Andric                                                        dfsan_label *ret_label) {
81968d75effSDimitry Andric   int ret = clock_gettime(clk_id, tp);
82068d75effSDimitry Andric   if (ret == 0)
82168d75effSDimitry Andric     dfsan_set_label(0, tp, sizeof(struct timespec));
82268d75effSDimitry Andric   *ret_label = 0;
82368d75effSDimitry Andric   return ret;
82468d75effSDimitry Andric }
82568d75effSDimitry Andric 
826fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_clock_gettime(
827fe6060f1SDimitry Andric     clockid_t clk_id, struct timespec *tp, dfsan_label clk_id_label,
828fe6060f1SDimitry Andric     dfsan_label tp_label, dfsan_label *ret_label, dfsan_origin clk_id_origin,
829fe6060f1SDimitry Andric     dfsan_origin tp_origin, dfsan_origin *ret_origin) {
830fe6060f1SDimitry Andric   return __dfsw_clock_gettime(clk_id, tp, clk_id_label, tp_label, ret_label);
831fe6060f1SDimitry Andric }
832fe6060f1SDimitry Andric 
833fe6060f1SDimitry Andric static void dfsan_set_zero_label(const void *ptr, uptr size) {
83468d75effSDimitry Andric   dfsan_set_label(0, const_cast<void *>(ptr), size);
83568d75effSDimitry Andric }
83668d75effSDimitry Andric 
83768d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally
83868d75effSDimitry Andric // doesn't participate in dynamic symbol resolution.  Therefore we won't
83968d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here.
84068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *
84168d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
84268d75effSDimitry Andric               dfsan_label flag_label, dfsan_label *ret_label) {
84368d75effSDimitry Andric   void *handle = dlopen(filename, flag);
84468d75effSDimitry Andric   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
84568d75effSDimitry Andric   if (map)
846fe6060f1SDimitry Andric     ForEachMappedRegion(map, dfsan_set_zero_label);
84768d75effSDimitry Andric   *ret_label = 0;
84868d75effSDimitry Andric   return handle;
84968d75effSDimitry Andric }
85068d75effSDimitry Andric 
851fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen(
852fe6060f1SDimitry Andric     const char *filename, int flag, dfsan_label filename_label,
853fe6060f1SDimitry Andric     dfsan_label flag_label, dfsan_label *ret_label,
854fe6060f1SDimitry Andric     dfsan_origin filename_origin, dfsan_origin flag_origin,
855fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
856fe6060f1SDimitry Andric   return __dfsw_dlopen(filename, flag, filename_label, flag_label, ret_label);
857fe6060f1SDimitry Andric }
85868d75effSDimitry Andric 
859fe6060f1SDimitry Andric static void *DFsanThreadStartFunc(void *arg) {
860fe6060f1SDimitry Andric   DFsanThread *t = (DFsanThread *)arg;
861fe6060f1SDimitry Andric   SetCurrentThread(t);
862349cc55cSDimitry Andric   t->Init();
863349cc55cSDimitry Andric   SetSigProcMask(&t->starting_sigset_, nullptr);
864fe6060f1SDimitry Andric   return t->ThreadStart();
865fe6060f1SDimitry Andric }
866fe6060f1SDimitry Andric 
867fe6060f1SDimitry Andric static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
868fe6060f1SDimitry Andric                                 void *start_routine, void *arg,
869fe6060f1SDimitry Andric                                 dfsan_label *ret_label,
870fe6060f1SDimitry Andric                                 bool track_origins = false) {
871fe6060f1SDimitry Andric   pthread_attr_t myattr;
872fe6060f1SDimitry Andric   if (!attr) {
873fe6060f1SDimitry Andric     pthread_attr_init(&myattr);
874fe6060f1SDimitry Andric     attr = &myattr;
875fe6060f1SDimitry Andric   }
876fe6060f1SDimitry Andric 
877fe6060f1SDimitry Andric   // Ensure that the thread stack is large enough to hold all TLS data.
878fe6060f1SDimitry Andric   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
879fe6060f1SDimitry Andric 
880fe6060f1SDimitry Andric   DFsanThread *t =
88181ad6265SDimitry Andric       DFsanThread::Create((thread_callback_t)start_routine, arg, track_origins);
882349cc55cSDimitry Andric   ScopedBlockSignals block(&t->starting_sigset_);
883fe6060f1SDimitry Andric   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
884fe6060f1SDimitry Andric 
885fe6060f1SDimitry Andric   if (attr == &myattr)
886fe6060f1SDimitry Andric     pthread_attr_destroy(&myattr);
887fe6060f1SDimitry Andric   *ret_label = 0;
888fe6060f1SDimitry Andric   return res;
88968d75effSDimitry Andric }
89068d75effSDimitry Andric 
89168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
89281ad6265SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
89381ad6265SDimitry Andric     void *arg, dfsan_label thread_label, dfsan_label attr_label,
89481ad6265SDimitry Andric     dfsan_label start_routine_label, dfsan_label arg_label,
89581ad6265SDimitry Andric     dfsan_label *ret_label) {
89681ad6265SDimitry Andric   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label);
897fe6060f1SDimitry Andric }
898fe6060f1SDimitry Andric 
899fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
90081ad6265SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
90181ad6265SDimitry Andric     void *arg, dfsan_label thread_label, dfsan_label attr_label,
90281ad6265SDimitry Andric     dfsan_label start_routine_label, dfsan_label arg_label,
90381ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin thread_origin,
904fe6060f1SDimitry Andric     dfsan_origin attr_origin, dfsan_origin start_routine_origin,
905fe6060f1SDimitry Andric     dfsan_origin arg_origin, dfsan_origin *ret_origin) {
90681ad6265SDimitry Andric   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label,
90781ad6265SDimitry Andric                               true);
90868d75effSDimitry Andric }
90968d75effSDimitry Andric 
910e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
911e8d8bef9SDimitry Andric                                                       void **retval,
912e8d8bef9SDimitry Andric                                                       dfsan_label thread_label,
913e8d8bef9SDimitry Andric                                                       dfsan_label retval_label,
914e8d8bef9SDimitry Andric                                                       dfsan_label *ret_label) {
915e8d8bef9SDimitry Andric   int ret = pthread_join(thread, retval);
916e8d8bef9SDimitry Andric   if (ret == 0 && retval)
917e8d8bef9SDimitry Andric     dfsan_set_label(0, retval, sizeof(*retval));
918e8d8bef9SDimitry Andric   *ret_label = 0;
919e8d8bef9SDimitry Andric   return ret;
920e8d8bef9SDimitry Andric }
921e8d8bef9SDimitry Andric 
922fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
923fe6060f1SDimitry Andric     pthread_t thread, void **retval, dfsan_label thread_label,
924fe6060f1SDimitry Andric     dfsan_label retval_label, dfsan_label *ret_label,
925fe6060f1SDimitry Andric     dfsan_origin thread_origin, dfsan_origin retval_origin,
926fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
927fe6060f1SDimitry Andric   return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
928fe6060f1SDimitry Andric                              ret_label);
929fe6060f1SDimitry Andric }
930fe6060f1SDimitry Andric 
93168d75effSDimitry Andric struct dl_iterate_phdr_info {
93281ad6265SDimitry Andric   int (*callback)(struct dl_phdr_info *info, size_t size, void *data);
933fe6060f1SDimitry Andric   void *data;
934fe6060f1SDimitry Andric };
935fe6060f1SDimitry Andric 
93668d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
93768d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
93868d75effSDimitry Andric   dfsan_set_label(0, *info);
93968d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
94068d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
94168d75effSDimitry Andric   dfsan_set_label(
94268d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
94368d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
94468d75effSDimitry Andric 
94581ad6265SDimitry Andric   dfsan_clear_thread_local_state();
94681ad6265SDimitry Andric   return dipi->callback(info, size, dipi->data);
947fe6060f1SDimitry Andric }
948fe6060f1SDimitry Andric 
94968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
95081ad6265SDimitry Andric     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
95181ad6265SDimitry Andric     void *data, dfsan_label callback_label, dfsan_label data_label,
95281ad6265SDimitry Andric     dfsan_label *ret_label) {
95381ad6265SDimitry Andric   dl_iterate_phdr_info dipi = {callback, data};
95468d75effSDimitry Andric   *ret_label = 0;
95568d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
95668d75effSDimitry Andric }
95768d75effSDimitry Andric 
958fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr(
95981ad6265SDimitry Andric     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
96081ad6265SDimitry Andric     void *data, dfsan_label callback_label, dfsan_label data_label,
96181ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin callback_origin,
96281ad6265SDimitry Andric     dfsan_origin data_origin, dfsan_origin *ret_origin) {
96381ad6265SDimitry Andric   dl_iterate_phdr_info dipi = {callback, data};
964fe6060f1SDimitry Andric   *ret_label = 0;
96581ad6265SDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
966fe6060f1SDimitry Andric }
967fe6060f1SDimitry Andric 
968e8d8bef9SDimitry Andric // This function is only available for glibc 2.27 or newer.  Mark it weak so
969e8d8bef9SDimitry Andric // linking succeeds with older glibcs.
970e8d8bef9SDimitry Andric SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep,
971e8d8bef9SDimitry Andric                                                       size_t *alignp);
972e8d8bef9SDimitry Andric 
973e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info(
974e8d8bef9SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
975e8d8bef9SDimitry Andric     dfsan_label alignp_label) {
976e8d8bef9SDimitry Andric   assert(_dl_get_tls_static_info);
977e8d8bef9SDimitry Andric   _dl_get_tls_static_info(sizep, alignp);
978e8d8bef9SDimitry Andric   dfsan_set_label(0, sizep, sizeof(*sizep));
979e8d8bef9SDimitry Andric   dfsan_set_label(0, alignp, sizeof(*alignp));
980e8d8bef9SDimitry Andric }
981e8d8bef9SDimitry Andric 
982fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info(
983fe6060f1SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
984fe6060f1SDimitry Andric     dfsan_label alignp_label, dfsan_origin sizep_origin,
985fe6060f1SDimitry Andric     dfsan_origin alignp_origin) {
986fe6060f1SDimitry Andric   __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label);
987fe6060f1SDimitry Andric }
988fe6060f1SDimitry Andric 
98968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
99068d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
99168d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
99268d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
99368d75effSDimitry Andric   if (ret) {
99468d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
99568d75effSDimitry Andric                     strlen(buf) + 1);
99668d75effSDimitry Andric     *ret_label = buf_label;
99768d75effSDimitry Andric   } else {
99868d75effSDimitry Andric     *ret_label = 0;
99968d75effSDimitry Andric   }
100068d75effSDimitry Andric   return ret;
100168d75effSDimitry Andric }
100268d75effSDimitry Andric 
100368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1004fe6060f1SDimitry Andric char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
1005fe6060f1SDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label,
1006fe6060f1SDimitry Andric                      dfsan_origin timep_origin, dfsan_origin buf_origin,
1007fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1008fe6060f1SDimitry Andric   char *ret = ctime_r(timep, buf);
1009fe6060f1SDimitry Andric   if (ret) {
1010fe6060f1SDimitry Andric     dfsan_set_label_origin(
1011fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1012fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf,
1013fe6060f1SDimitry Andric         strlen(buf) + 1);
1014fe6060f1SDimitry Andric     *ret_label = buf_label;
1015fe6060f1SDimitry Andric     *ret_origin = buf_origin;
1016fe6060f1SDimitry Andric   } else {
1017fe6060f1SDimitry Andric     *ret_label = 0;
1018fe6060f1SDimitry Andric   }
1019fe6060f1SDimitry Andric   return ret;
1020fe6060f1SDimitry Andric }
1021fe6060f1SDimitry Andric 
1022fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
102368d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
102468d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
102568d75effSDimitry Andric                    dfsan_label *ret_label) {
102668d75effSDimitry Andric   char *ret = fgets(s, size, stream);
102768d75effSDimitry Andric   if (ret) {
102868d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
102968d75effSDimitry Andric     *ret_label = s_label;
103068d75effSDimitry Andric   } else {
103168d75effSDimitry Andric     *ret_label = 0;
103268d75effSDimitry Andric   }
103368d75effSDimitry Andric   return ret;
103468d75effSDimitry Andric }
103568d75effSDimitry Andric 
103668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1037fe6060f1SDimitry Andric char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
1038fe6060f1SDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
1039fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin s_origin,
1040fe6060f1SDimitry Andric                    dfsan_origin size_origin, dfsan_origin stream_origin,
1041fe6060f1SDimitry Andric                    dfsan_origin *ret_origin) {
1042fe6060f1SDimitry Andric   char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label,
1043fe6060f1SDimitry Andric                            ret_label);
1044fe6060f1SDimitry Andric   if (ret)
1045fe6060f1SDimitry Andric     *ret_origin = s_origin;
1046fe6060f1SDimitry Andric   return ret;
1047fe6060f1SDimitry Andric }
1048fe6060f1SDimitry Andric 
1049fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
105068d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
105168d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
105268d75effSDimitry Andric   char *ret = getcwd(buf, size);
105368d75effSDimitry Andric   if (ret) {
105468d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
105568d75effSDimitry Andric     *ret_label = buf_label;
105668d75effSDimitry Andric   } else {
105768d75effSDimitry Andric     *ret_label = 0;
105868d75effSDimitry Andric   }
105968d75effSDimitry Andric   return ret;
106068d75effSDimitry Andric }
106168d75effSDimitry Andric 
106268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1063fe6060f1SDimitry Andric char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label,
1064fe6060f1SDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label,
1065fe6060f1SDimitry Andric                     dfsan_origin buf_origin, dfsan_origin size_origin,
1066fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1067fe6060f1SDimitry Andric   char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label);
1068fe6060f1SDimitry Andric   if (ret)
1069fe6060f1SDimitry Andric     *ret_origin = buf_origin;
1070fe6060f1SDimitry Andric   return ret;
1071fe6060f1SDimitry Andric }
1072fe6060f1SDimitry Andric 
1073fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
107468d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
107568d75effSDimitry Andric   char *ret = get_current_dir_name();
1076fe6060f1SDimitry Andric   if (ret)
107768d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
107868d75effSDimitry Andric   *ret_label = 0;
107968d75effSDimitry Andric   return ret;
108068d75effSDimitry Andric }
108168d75effSDimitry Andric 
108268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1083fe6060f1SDimitry Andric char *__dfso_get_current_dir_name(dfsan_label *ret_label,
1084fe6060f1SDimitry Andric                                   dfsan_origin *ret_origin) {
1085fe6060f1SDimitry Andric   return __dfsw_get_current_dir_name(ret_label);
1086fe6060f1SDimitry Andric }
1087fe6060f1SDimitry Andric 
1088349cc55cSDimitry Andric // This function is only available for glibc 2.25 or newer.  Mark it weak so
1089349cc55cSDimitry Andric // linking succeeds with older glibcs.
1090349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length);
1091349cc55cSDimitry Andric 
1092349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length,
1093349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1094349cc55cSDimitry Andric                                                     dfsan_label length_label,
1095349cc55cSDimitry Andric                                                     dfsan_label *ret_label) {
1096349cc55cSDimitry Andric   int ret = getentropy(buffer, length);
1097349cc55cSDimitry Andric   if (ret == 0) {
1098349cc55cSDimitry Andric     dfsan_set_label(0, buffer, length);
1099349cc55cSDimitry Andric   }
1100349cc55cSDimitry Andric   *ret_label = 0;
1101349cc55cSDimitry Andric   return ret;
1102349cc55cSDimitry Andric }
1103349cc55cSDimitry Andric 
1104349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length,
1105349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1106349cc55cSDimitry Andric                                                     dfsan_label length_label,
1107349cc55cSDimitry Andric                                                     dfsan_label *ret_label,
1108349cc55cSDimitry Andric                                                     dfsan_origin buffer_origin,
1109349cc55cSDimitry Andric                                                     dfsan_origin length_origin,
1110349cc55cSDimitry Andric                                                     dfsan_origin *ret_origin) {
1111349cc55cSDimitry Andric   return __dfsw_getentropy(buffer, length, buffer_label, length_label,
1112349cc55cSDimitry Andric                            ret_label);
1113349cc55cSDimitry Andric }
1114349cc55cSDimitry Andric 
1115fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
111668d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
111768d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
111868d75effSDimitry Andric   int ret = gethostname(name, len);
111968d75effSDimitry Andric   if (ret == 0) {
112068d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
112168d75effSDimitry Andric   }
112268d75effSDimitry Andric   *ret_label = 0;
112368d75effSDimitry Andric   return ret;
112468d75effSDimitry Andric }
112568d75effSDimitry Andric 
112668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1127fe6060f1SDimitry Andric int __dfso_gethostname(char *name, size_t len, dfsan_label name_label,
1128fe6060f1SDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label,
1129fe6060f1SDimitry Andric                        dfsan_origin name_origin, dfsan_origin len_origin,
1130fe6060f1SDimitry Andric                        dfsan_label *ret_origin) {
1131fe6060f1SDimitry Andric   return __dfsw_gethostname(name, len, name_label, len_label, ret_label);
1132fe6060f1SDimitry Andric }
1133fe6060f1SDimitry Andric 
1134fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
113568d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
113668d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
113768d75effSDimitry Andric                      dfsan_label *ret_label) {
113868d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
113968d75effSDimitry Andric   if (ret == 0) {
114068d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
114168d75effSDimitry Andric   }
114268d75effSDimitry Andric   *ret_label = 0;
114368d75effSDimitry Andric   return ret;
114468d75effSDimitry Andric }
114568d75effSDimitry Andric 
114668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1147fe6060f1SDimitry Andric int __dfso_getrlimit(int resource, struct rlimit *rlim,
1148fe6060f1SDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
1149fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin resource_origin,
1150fe6060f1SDimitry Andric                      dfsan_origin rlim_origin, dfsan_origin *ret_origin) {
1151fe6060f1SDimitry Andric   return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label,
1152fe6060f1SDimitry Andric                           ret_label);
1153fe6060f1SDimitry Andric }
1154fe6060f1SDimitry Andric 
1155fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
115668d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
115768d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
115868d75effSDimitry Andric   int ret = getrusage(who, usage);
115968d75effSDimitry Andric   if (ret == 0) {
116068d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
116168d75effSDimitry Andric   }
116268d75effSDimitry Andric   *ret_label = 0;
116368d75effSDimitry Andric   return ret;
116468d75effSDimitry Andric }
116568d75effSDimitry Andric 
116668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1167fe6060f1SDimitry Andric int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label,
1168fe6060f1SDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label,
1169fe6060f1SDimitry Andric                      dfsan_origin who_origin, dfsan_origin usage_origin,
1170fe6060f1SDimitry Andric                      dfsan_label *ret_origin) {
1171fe6060f1SDimitry Andric   return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label);
1172fe6060f1SDimitry Andric }
1173fe6060f1SDimitry Andric 
1174fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
117568d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
117668d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
1177349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
117868d75effSDimitry Andric   if (ret) {
117904eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, strlen(src) + 1);
118068d75effSDimitry Andric   }
118168d75effSDimitry Andric   *ret_label = dst_label;
118268d75effSDimitry Andric   return ret;
118368d75effSDimitry Andric }
118468d75effSDimitry Andric 
118568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1186fe6060f1SDimitry Andric char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label,
1187fe6060f1SDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label,
1188fe6060f1SDimitry Andric                     dfsan_origin dst_origin, dfsan_origin src_origin,
1189fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1190349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
1191fe6060f1SDimitry Andric   if (ret) {
1192fe6060f1SDimitry Andric     size_t str_len = strlen(src) + 1;
1193fe6060f1SDimitry Andric     dfsan_mem_origin_transfer(dest, src, str_len);
119404eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, str_len);
119568d75effSDimitry Andric   }
1196fe6060f1SDimitry Andric   *ret_label = dst_label;
1197fe6060f1SDimitry Andric   *ret_origin = dst_origin;
1198fe6060f1SDimitry Andric   return ret;
1199fe6060f1SDimitry Andric }
1200fe6060f1SDimitry Andric 
1201fe6060f1SDimitry Andric static long int dfsan_strtol(const char *nptr, char **endptr, int base,
1202fe6060f1SDimitry Andric                              char **tmp_endptr) {
1203fe6060f1SDimitry Andric   assert(tmp_endptr);
1204fe6060f1SDimitry Andric   long int ret = strtol(nptr, tmp_endptr, base);
1205fe6060f1SDimitry Andric   if (endptr)
1206fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1207fe6060f1SDimitry Andric   return ret;
1208fe6060f1SDimitry Andric }
1209fe6060f1SDimitry Andric 
1210fe6060f1SDimitry Andric static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr,
1211fe6060f1SDimitry Andric                                   dfsan_label base_label,
1212fe6060f1SDimitry Andric                                   dfsan_label *ret_label) {
121368d75effSDimitry Andric   if (tmp_endptr > nptr) {
121468d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
121568d75effSDimitry Andric     *ret_label = dfsan_union(
121668d75effSDimitry Andric         base_label,
121768d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
121868d75effSDimitry Andric   } else {
121968d75effSDimitry Andric     *ret_label = 0;
122068d75effSDimitry Andric   }
1221fe6060f1SDimitry Andric }
1222fe6060f1SDimitry Andric 
1223fe6060f1SDimitry Andric static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr,
1224fe6060f1SDimitry Andric                                    dfsan_label base_label,
1225fe6060f1SDimitry Andric                                    dfsan_label *ret_label,
1226fe6060f1SDimitry Andric                                    dfsan_origin base_origin,
1227fe6060f1SDimitry Andric                                    dfsan_origin *ret_origin) {
1228fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1229fe6060f1SDimitry Andric     // When multiple inputs are tainted, we propagate one of its origins.
1230fe6060f1SDimitry Andric     // Because checking if base_label is tainted does not need additional
1231fe6060f1SDimitry Andric     // computation, we prefer to propagating base_origin.
1232fe6060f1SDimitry Andric     *ret_origin = base_label
1233fe6060f1SDimitry Andric                       ? base_origin
1234fe6060f1SDimitry Andric                       : dfsan_read_origin_of_first_taint(
1235fe6060f1SDimitry Andric                             nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1236fe6060f1SDimitry Andric   }
1237fe6060f1SDimitry Andric }
1238fe6060f1SDimitry Andric 
1239fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1240fe6060f1SDimitry Andric long int __dfsw_strtol(const char *nptr, char **endptr, int base,
1241fe6060f1SDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1242fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
1243fe6060f1SDimitry Andric   char *tmp_endptr;
1244fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1245fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
124668d75effSDimitry Andric   return ret;
124768d75effSDimitry Andric }
124868d75effSDimitry Andric 
124968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1250fe6060f1SDimitry Andric long int __dfso_strtol(const char *nptr, char **endptr, int base,
125168d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1252fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label,
1253fe6060f1SDimitry Andric                        dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1254fe6060f1SDimitry Andric                        dfsan_origin base_origin, dfsan_origin *ret_origin) {
125568d75effSDimitry Andric   char *tmp_endptr;
1256fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1257fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1258fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1259fe6060f1SDimitry Andric                          ret_origin);
1260fe6060f1SDimitry Andric   return ret;
126168d75effSDimitry Andric }
1262fe6060f1SDimitry Andric 
1263fe6060f1SDimitry Andric static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) {
1264fe6060f1SDimitry Andric   assert(tmp_endptr);
1265fe6060f1SDimitry Andric   double ret = strtod(nptr, tmp_endptr);
1266fe6060f1SDimitry Andric   if (endptr)
1267fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1268fe6060f1SDimitry Andric   return ret;
1269fe6060f1SDimitry Andric }
1270fe6060f1SDimitry Andric 
1271fe6060f1SDimitry Andric static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr,
1272fe6060f1SDimitry Andric                                dfsan_label *ret_label) {
127368d75effSDimitry Andric   if (tmp_endptr > nptr) {
127468d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
127568d75effSDimitry Andric     *ret_label = dfsan_read_label(
127668d75effSDimitry Andric         nptr,
127768d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
127868d75effSDimitry Andric   } else {
127968d75effSDimitry Andric     *ret_label = 0;
128068d75effSDimitry Andric   }
1281fe6060f1SDimitry Andric }
1282fe6060f1SDimitry Andric 
1283fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1284fe6060f1SDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1285fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label) {
1286fe6060f1SDimitry Andric   char *tmp_endptr;
1287fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1288fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1289fe6060f1SDimitry Andric   return ret;
1290fe6060f1SDimitry Andric }
1291fe6060f1SDimitry Andric 
1292fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1293fe6060f1SDimitry Andric double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1294fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label,
1295fe6060f1SDimitry Andric                      dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1296fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1297fe6060f1SDimitry Andric   char *tmp_endptr;
1298fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1299fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1300fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1301fe6060f1SDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
1302fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(
1303fe6060f1SDimitry Andric         nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1304fe6060f1SDimitry Andric   } else {
1305fe6060f1SDimitry Andric     *ret_origin = 0;
1306fe6060f1SDimitry Andric   }
1307fe6060f1SDimitry Andric   return ret;
1308fe6060f1SDimitry Andric }
1309fe6060f1SDimitry Andric 
1310fe6060f1SDimitry Andric static long long int dfsan_strtoll(const char *nptr, char **endptr, int base,
1311fe6060f1SDimitry Andric                                    char **tmp_endptr) {
1312fe6060f1SDimitry Andric   assert(tmp_endptr);
1313fe6060f1SDimitry Andric   long long int ret = strtoll(nptr, tmp_endptr, base);
1314fe6060f1SDimitry Andric   if (endptr)
1315fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
131668d75effSDimitry Andric   return ret;
131768d75effSDimitry Andric }
131868d75effSDimitry Andric 
131968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
132068d75effSDimitry Andric long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
132168d75effSDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
132268d75effSDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label) {
132368d75effSDimitry Andric   char *tmp_endptr;
1324fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1325fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1326fe6060f1SDimitry Andric   return ret;
132768d75effSDimitry Andric }
1328fe6060f1SDimitry Andric 
1329fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1330fe6060f1SDimitry Andric long long int __dfso_strtoll(const char *nptr, char **endptr, int base,
1331fe6060f1SDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
1332fe6060f1SDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label,
1333fe6060f1SDimitry Andric                              dfsan_origin nptr_origin,
1334fe6060f1SDimitry Andric                              dfsan_origin endptr_origin,
1335fe6060f1SDimitry Andric                              dfsan_origin base_origin,
1336fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1337fe6060f1SDimitry Andric   char *tmp_endptr;
1338fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1339fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1340fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1341fe6060f1SDimitry Andric                          ret_origin);
1342fe6060f1SDimitry Andric   return ret;
134368d75effSDimitry Andric }
1344fe6060f1SDimitry Andric 
1345fe6060f1SDimitry Andric static unsigned long int dfsan_strtoul(const char *nptr, char **endptr,
1346fe6060f1SDimitry Andric                                        int base, char **tmp_endptr) {
1347fe6060f1SDimitry Andric   assert(tmp_endptr);
1348fe6060f1SDimitry Andric   unsigned long int ret = strtoul(nptr, tmp_endptr, base);
1349fe6060f1SDimitry Andric   if (endptr)
1350fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
135168d75effSDimitry Andric   return ret;
135268d75effSDimitry Andric }
135368d75effSDimitry Andric 
135468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
135568d75effSDimitry Andric unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
135668d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
135768d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
135868d75effSDimitry Andric   char *tmp_endptr;
1359fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1360fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1361fe6060f1SDimitry Andric   return ret;
136268d75effSDimitry Andric }
1363fe6060f1SDimitry Andric 
1364fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1365fe6060f1SDimitry Andric unsigned long int __dfso_strtoul(
1366fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1367fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1368fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1369fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1370fe6060f1SDimitry Andric   char *tmp_endptr;
1371fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1372fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1373fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1374fe6060f1SDimitry Andric                          ret_origin);
1375fe6060f1SDimitry Andric   return ret;
137668d75effSDimitry Andric }
1377fe6060f1SDimitry Andric 
1378fe6060f1SDimitry Andric static long long unsigned int dfsan_strtoull(const char *nptr, char **endptr,
1379fe6060f1SDimitry Andric                                              int base, char **tmp_endptr) {
1380fe6060f1SDimitry Andric   assert(tmp_endptr);
1381fe6060f1SDimitry Andric   long long unsigned int ret = strtoull(nptr, tmp_endptr, base);
1382fe6060f1SDimitry Andric   if (endptr)
1383fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
138468d75effSDimitry Andric   return ret;
138568d75effSDimitry Andric }
138668d75effSDimitry Andric 
138768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
138868d75effSDimitry Andric long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
1389e8d8bef9SDimitry Andric                                        int base, dfsan_label nptr_label,
1390e8d8bef9SDimitry Andric                                        dfsan_label endptr_label,
139168d75effSDimitry Andric                                        dfsan_label base_label,
139268d75effSDimitry Andric                                        dfsan_label *ret_label) {
139368d75effSDimitry Andric   char *tmp_endptr;
1394fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1395fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1396fe6060f1SDimitry Andric   return ret;
139768d75effSDimitry Andric }
1398fe6060f1SDimitry Andric 
1399fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1400fe6060f1SDimitry Andric long long unsigned int __dfso_strtoull(
1401fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1402fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1403fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1404fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1405fe6060f1SDimitry Andric   char *tmp_endptr;
1406fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1407fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1408fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1409fe6060f1SDimitry Andric                          ret_origin);
141068d75effSDimitry Andric   return ret;
141168d75effSDimitry Andric }
141268d75effSDimitry Andric 
141368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
141468d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
141568d75effSDimitry Andric   time_t ret = time(t);
141668d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
141768d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
141868d75effSDimitry Andric   }
141968d75effSDimitry Andric   *ret_label = 0;
142068d75effSDimitry Andric   return ret;
142168d75effSDimitry Andric }
142268d75effSDimitry Andric 
142368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1424fe6060f1SDimitry Andric time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label,
1425fe6060f1SDimitry Andric                    dfsan_origin t_origin, dfsan_origin *ret_origin) {
1426fe6060f1SDimitry Andric   return __dfsw_time(t, t_label, ret_label);
1427fe6060f1SDimitry Andric }
1428fe6060f1SDimitry Andric 
1429fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
143068d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
143168d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
143268d75effSDimitry Andric                      dfsan_label *ret_label) {
143368d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
143468d75effSDimitry Andric   if (ret == 1) {
143568d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
143668d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
143768d75effSDimitry Andric   }
143868d75effSDimitry Andric   *ret_label = 0;
143968d75effSDimitry Andric   return ret;
144068d75effSDimitry Andric }
144168d75effSDimitry Andric 
144268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1443fe6060f1SDimitry Andric int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
1444fe6060f1SDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
1445fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin af_origin,
1446fe6060f1SDimitry Andric                      dfsan_origin src_origin, dfsan_origin dst_origin,
1447fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1448fe6060f1SDimitry Andric   int ret = inet_pton(af, src, dst);
1449fe6060f1SDimitry Andric   if (ret == 1) {
1450fe6060f1SDimitry Andric     int src_len = strlen(src) + 1;
1451fe6060f1SDimitry Andric     dfsan_set_label_origin(
1452fe6060f1SDimitry Andric         dfsan_read_label(src, src_len),
1453fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(src, src_len), dst,
1454fe6060f1SDimitry Andric         af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
1455fe6060f1SDimitry Andric   }
1456fe6060f1SDimitry Andric   *ret_label = 0;
1457fe6060f1SDimitry Andric   return ret;
1458fe6060f1SDimitry Andric }
1459fe6060f1SDimitry Andric 
1460fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
146168d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
146268d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
146368d75effSDimitry Andric                               dfsan_label *ret_label) {
146468d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
146568d75effSDimitry Andric   if (ret) {
146668d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
146768d75effSDimitry Andric                     sizeof(struct tm));
146868d75effSDimitry Andric     *ret_label = result_label;
146968d75effSDimitry Andric   } else {
147068d75effSDimitry Andric     *ret_label = 0;
147168d75effSDimitry Andric   }
147268d75effSDimitry Andric   return ret;
147368d75effSDimitry Andric }
147468d75effSDimitry Andric 
147568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1476fe6060f1SDimitry Andric struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result,
1477fe6060f1SDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
1478fe6060f1SDimitry Andric                               dfsan_label *ret_label, dfsan_origin timep_origin,
1479fe6060f1SDimitry Andric                               dfsan_origin result_origin,
1480fe6060f1SDimitry Andric                               dfsan_origin *ret_origin) {
1481fe6060f1SDimitry Andric   struct tm *ret = localtime_r(timep, result);
1482fe6060f1SDimitry Andric   if (ret) {
1483fe6060f1SDimitry Andric     dfsan_set_label_origin(
1484fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1485fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result,
1486fe6060f1SDimitry Andric         sizeof(struct tm));
1487fe6060f1SDimitry Andric     *ret_label = result_label;
1488fe6060f1SDimitry Andric     *ret_origin = result_origin;
1489fe6060f1SDimitry Andric   } else {
1490fe6060f1SDimitry Andric     *ret_label = 0;
1491fe6060f1SDimitry Andric   }
1492fe6060f1SDimitry Andric   return ret;
1493fe6060f1SDimitry Andric }
1494fe6060f1SDimitry Andric 
1495fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
149668d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
149768d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
149868d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
149968d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
150068d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
150168d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
150268d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
150368d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
150468d75effSDimitry Andric   if (ret == 0) {
150568d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
150668d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
150768d75effSDimitry Andric   }
150868d75effSDimitry Andric   *ret_label = 0;
150968d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
151068d75effSDimitry Andric   return ret;
151168d75effSDimitry Andric }
151268d75effSDimitry Andric 
151368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1514fe6060f1SDimitry Andric int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen,
1515fe6060f1SDimitry Andric                       struct passwd **result, dfsan_label uid_label,
1516fe6060f1SDimitry Andric                       dfsan_label pwd_label, dfsan_label buf_label,
1517fe6060f1SDimitry Andric                       dfsan_label buflen_label, dfsan_label result_label,
1518fe6060f1SDimitry Andric                       dfsan_label *ret_label, dfsan_origin uid_origin,
1519fe6060f1SDimitry Andric                       dfsan_origin pwd_origin, dfsan_origin buf_origin,
1520fe6060f1SDimitry Andric                       dfsan_origin buflen_origin, dfsan_origin result_origin,
1521fe6060f1SDimitry Andric                       dfsan_origin *ret_origin) {
1522fe6060f1SDimitry Andric   return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label,
1523fe6060f1SDimitry Andric                            buf_label, buflen_label, result_label, ret_label);
1524fe6060f1SDimitry Andric }
1525fe6060f1SDimitry Andric 
1526fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1527e8d8bef9SDimitry Andric int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1528e8d8bef9SDimitry Andric                       int timeout, dfsan_label epfd_label,
1529e8d8bef9SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1530e8d8bef9SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label) {
1531e8d8bef9SDimitry Andric   int ret = epoll_wait(epfd, events, maxevents, timeout);
1532e8d8bef9SDimitry Andric   if (ret > 0)
1533e8d8bef9SDimitry Andric     dfsan_set_label(0, events, ret * sizeof(*events));
1534e8d8bef9SDimitry Andric   *ret_label = 0;
1535e8d8bef9SDimitry Andric   return ret;
1536e8d8bef9SDimitry Andric }
1537e8d8bef9SDimitry Andric 
1538e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1539fe6060f1SDimitry Andric int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1540fe6060f1SDimitry Andric                       int timeout, dfsan_label epfd_label,
1541fe6060f1SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1542fe6060f1SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label,
1543fe6060f1SDimitry Andric                       dfsan_origin epfd_origin, dfsan_origin events_origin,
1544fe6060f1SDimitry Andric                       dfsan_origin maxevents_origin,
1545fe6060f1SDimitry Andric                       dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1546fe6060f1SDimitry Andric   return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label,
1547fe6060f1SDimitry Andric                            events_label, maxevents_label, timeout_label,
1548fe6060f1SDimitry Andric                            ret_label);
1549fe6060f1SDimitry Andric }
1550fe6060f1SDimitry Andric 
1551fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
155268d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
155368d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
155468d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
155568d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
155668d75effSDimitry Andric   if (ret >= 0) {
155768d75effSDimitry Andric     for (; nfds > 0; --nfds) {
155868d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
155968d75effSDimitry Andric     }
156068d75effSDimitry Andric   }
156168d75effSDimitry Andric   *ret_label = 0;
156268d75effSDimitry Andric   return ret;
156368d75effSDimitry Andric }
156468d75effSDimitry Andric 
156568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1566fe6060f1SDimitry Andric int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout,
1567fe6060f1SDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
1568fe6060f1SDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label,
1569fe6060f1SDimitry Andric                 dfsan_origin dfs_origin, dfsan_origin nfds_origin,
1570fe6060f1SDimitry Andric                 dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1571fe6060f1SDimitry Andric   return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label,
1572fe6060f1SDimitry Andric                      ret_label);
1573fe6060f1SDimitry Andric }
1574fe6060f1SDimitry Andric 
1575fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
157668d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
157768d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
157868d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
157968d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
158068d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
158168d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
158268d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
158368d75effSDimitry Andric   // undefined.
158468d75effSDimitry Andric   if (readfds) {
158568d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
158668d75effSDimitry Andric   }
158768d75effSDimitry Andric   if (writefds) {
158868d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
158968d75effSDimitry Andric   }
159068d75effSDimitry Andric   if (exceptfds) {
159168d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
159268d75effSDimitry Andric   }
159368d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
159468d75effSDimitry Andric   *ret_label = 0;
159568d75effSDimitry Andric   return ret;
159668d75effSDimitry Andric }
159768d75effSDimitry Andric 
159868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1599fe6060f1SDimitry Andric int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds,
1600fe6060f1SDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
1601fe6060f1SDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
1602fe6060f1SDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
1603fe6060f1SDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label,
1604fe6060f1SDimitry Andric                   dfsan_origin nfds_origin, dfsan_origin readfds_origin,
1605fe6060f1SDimitry Andric                   dfsan_origin writefds_origin, dfsan_origin exceptfds_origin,
1606fe6060f1SDimitry Andric                   dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1607fe6060f1SDimitry Andric   return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label,
1608fe6060f1SDimitry Andric                        readfds_label, writefds_label, exceptfds_label,
1609fe6060f1SDimitry Andric                        timeout_label, ret_label);
1610fe6060f1SDimitry Andric }
1611fe6060f1SDimitry Andric 
1612fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
161368d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
161468d75effSDimitry Andric                              dfsan_label pid_label,
161568d75effSDimitry Andric                              dfsan_label cpusetsize_label,
161668d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
161768d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
161868d75effSDimitry Andric   if (ret == 0) {
161968d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
162068d75effSDimitry Andric   }
162168d75effSDimitry Andric   *ret_label = 0;
162268d75effSDimitry Andric   return ret;
162368d75effSDimitry Andric }
162468d75effSDimitry Andric 
162568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1626fe6060f1SDimitry Andric int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
1627fe6060f1SDimitry Andric                              dfsan_label pid_label,
1628fe6060f1SDimitry Andric                              dfsan_label cpusetsize_label,
1629fe6060f1SDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label,
1630fe6060f1SDimitry Andric                              dfsan_origin pid_origin,
1631fe6060f1SDimitry Andric                              dfsan_origin cpusetsize_origin,
1632fe6060f1SDimitry Andric                              dfsan_origin mask_origin,
1633fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1634fe6060f1SDimitry Andric   return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label,
1635fe6060f1SDimitry Andric                                   cpusetsize_label, mask_label, ret_label);
1636fe6060f1SDimitry Andric }
1637fe6060f1SDimitry Andric 
1638fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
163968d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
164068d75effSDimitry Andric                        dfsan_label *ret_label) {
164168d75effSDimitry Andric   int ret = sigemptyset(set);
164268d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
1643fe6060f1SDimitry Andric   *ret_label = 0;
164468d75effSDimitry Andric   return ret;
164568d75effSDimitry Andric }
164668d75effSDimitry Andric 
164768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1648fe6060f1SDimitry Andric int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
1649fe6060f1SDimitry Andric                        dfsan_label *ret_label, dfsan_origin set_origin,
1650fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1651fe6060f1SDimitry Andric   return __dfsw_sigemptyset(set, set_label, ret_label);
1652fe6060f1SDimitry Andric }
1653fe6060f1SDimitry Andric 
1654fe6060f1SDimitry Andric class SignalHandlerScope {
1655fe6060f1SDimitry Andric  public:
1656fe6060f1SDimitry Andric   SignalHandlerScope() {
1657fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1658fe6060f1SDimitry Andric       t->EnterSignalHandler();
1659fe6060f1SDimitry Andric   }
1660fe6060f1SDimitry Andric   ~SignalHandlerScope() {
1661fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1662fe6060f1SDimitry Andric       t->LeaveSignalHandler();
1663fe6060f1SDimitry Andric   }
1664fe6060f1SDimitry Andric };
1665fe6060f1SDimitry Andric 
1666fe6060f1SDimitry Andric // Clear DFSan runtime TLS state at the end of a scope.
1667fe6060f1SDimitry Andric //
1668fe6060f1SDimitry Andric // Implementation must be async-signal-safe and use small data size, because
1669fe6060f1SDimitry Andric // instances of this class may live on the signal handler stack.
1670fe6060f1SDimitry Andric //
1671fe6060f1SDimitry Andric // DFSan uses TLS to pass metadata of arguments and return values. When an
1672fe6060f1SDimitry Andric // instrumented function accesses the TLS, if a signal callback happens, and the
1673fe6060f1SDimitry Andric // callback calls other instrumented functions with updating the same TLS, the
1674fe6060f1SDimitry Andric // TLS is in an inconsistent state after the callback ends. This may cause
1675fe6060f1SDimitry Andric // either under-tainting or over-tainting.
1676fe6060f1SDimitry Andric //
1677fe6060f1SDimitry Andric // The current implementation simply resets TLS at restore. This prevents from
1678fe6060f1SDimitry Andric // over-tainting. Although under-tainting may still happen, a taint flow can be
1679fe6060f1SDimitry Andric // found eventually if we run a DFSan-instrumented program multiple times. The
1680fe6060f1SDimitry Andric // alternative option is saving the entire TLS. However the TLS storage takes
1681fe6060f1SDimitry Andric // 2k bytes, and signal calls could be nested. So it does not seem worth.
1682fe6060f1SDimitry Andric class ScopedClearThreadLocalState {
1683fe6060f1SDimitry Andric  public:
1684fe6060f1SDimitry Andric   ScopedClearThreadLocalState() {}
1685fe6060f1SDimitry Andric   ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); }
1686fe6060f1SDimitry Andric };
1687fe6060f1SDimitry Andric 
1688fe6060f1SDimitry Andric // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls.
1689fe6060f1SDimitry Andric const int kMaxSignals = 1024;
1690fe6060f1SDimitry Andric static atomic_uintptr_t sigactions[kMaxSignals];
1691fe6060f1SDimitry Andric 
1692fe6060f1SDimitry Andric static void SignalHandler(int signo) {
1693fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1694fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1695fe6060f1SDimitry Andric 
169681ad6265SDimitry Andric   // Clear shadows for all inputs provided by system.
1697fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, sizeof(dfsan_label));
1698fe6060f1SDimitry Andric 
1699fe6060f1SDimitry Andric   typedef void (*signal_cb)(int x);
1700fe6060f1SDimitry Andric   signal_cb cb =
1701fe6060f1SDimitry Andric       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1702fe6060f1SDimitry Andric   cb(signo);
1703fe6060f1SDimitry Andric }
1704fe6060f1SDimitry Andric 
1705fe6060f1SDimitry Andric static void SignalAction(int signo, siginfo_t *si, void *uc) {
1706fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1707fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1708fe6060f1SDimitry Andric 
1709fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. Similar to SignalHandler.
1710fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label));
1711fe6060f1SDimitry Andric   dfsan_set_label(0, si, sizeof(*si));
1712fe6060f1SDimitry Andric   dfsan_set_label(0, uc, sizeof(ucontext_t));
1713fe6060f1SDimitry Andric 
1714fe6060f1SDimitry Andric   typedef void (*sigaction_cb)(int, siginfo_t *, void *);
1715fe6060f1SDimitry Andric   sigaction_cb cb =
1716fe6060f1SDimitry Andric       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1717fe6060f1SDimitry Andric   cb(signo, si, uc);
1718fe6060f1SDimitry Andric }
1719fe6060f1SDimitry Andric 
1720fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
172168d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
172268d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
172368d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
172468d75effSDimitry Andric                      dfsan_label *ret_label) {
1725fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1726fe6060f1SDimitry Andric   SignalSpinLocker lock;
1727fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1728fe6060f1SDimitry Andric   struct sigaction new_act;
1729fe6060f1SDimitry Andric   struct sigaction *pnew_act = act ? &new_act : nullptr;
1730fe6060f1SDimitry Andric   if (act) {
1731fe6060f1SDimitry Andric     internal_memcpy(pnew_act, act, sizeof(struct sigaction));
1732fe6060f1SDimitry Andric     if (pnew_act->sa_flags & SA_SIGINFO) {
1733fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_sigaction);
1734fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1735fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1736fe6060f1SDimitry Andric         pnew_act->sa_sigaction = SignalAction;
1737fe6060f1SDimitry Andric       }
1738fe6060f1SDimitry Andric     } else {
1739fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_handler);
1740fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1741fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1742fe6060f1SDimitry Andric         pnew_act->sa_handler = SignalHandler;
1743fe6060f1SDimitry Andric       }
1744fe6060f1SDimitry Andric     }
1745fe6060f1SDimitry Andric   }
1746fe6060f1SDimitry Andric 
1747fe6060f1SDimitry Andric   int ret = sigaction(signum, pnew_act, oldact);
1748fe6060f1SDimitry Andric 
1749fe6060f1SDimitry Andric   if (ret == 0 && oldact) {
1750fe6060f1SDimitry Andric     if (oldact->sa_flags & SA_SIGINFO) {
1751fe6060f1SDimitry Andric       if (oldact->sa_sigaction == SignalAction)
1752fe6060f1SDimitry Andric         oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb;
1753fe6060f1SDimitry Andric     } else {
1754fe6060f1SDimitry Andric       if (oldact->sa_handler == SignalHandler)
1755fe6060f1SDimitry Andric         oldact->sa_handler = (decltype(oldact->sa_handler))old_cb;
1756fe6060f1SDimitry Andric     }
1757fe6060f1SDimitry Andric   }
1758fe6060f1SDimitry Andric 
175968d75effSDimitry Andric   if (oldact) {
176068d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
176168d75effSDimitry Andric   }
176268d75effSDimitry Andric   *ret_label = 0;
176368d75effSDimitry Andric   return ret;
176468d75effSDimitry Andric }
176568d75effSDimitry Andric 
176668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1767fe6060f1SDimitry Andric int __dfso_sigaction(int signum, const struct sigaction *act,
1768fe6060f1SDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
1769fe6060f1SDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
1770fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin signum_origin,
1771fe6060f1SDimitry Andric                      dfsan_origin act_origin, dfsan_origin oldact_origin,
1772fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1773fe6060f1SDimitry Andric   return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
1774fe6060f1SDimitry Andric                           oldact_label, ret_label);
1775fe6060f1SDimitry Andric }
1776fe6060f1SDimitry Andric 
1777fe6060f1SDimitry Andric static sighandler_t dfsan_signal(int signum, sighandler_t handler,
1778fe6060f1SDimitry Andric                                  dfsan_label *ret_label) {
1779fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1780fe6060f1SDimitry Andric   SignalSpinLocker lock;
1781fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1782fe6060f1SDimitry Andric   if (handler != SIG_IGN && handler != SIG_DFL) {
1783fe6060f1SDimitry Andric     atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
1784fe6060f1SDimitry Andric     handler = &SignalHandler;
1785fe6060f1SDimitry Andric   }
1786fe6060f1SDimitry Andric 
1787fe6060f1SDimitry Andric   sighandler_t ret = signal(signum, handler);
1788fe6060f1SDimitry Andric 
1789fe6060f1SDimitry Andric   if (ret == SignalHandler)
1790fe6060f1SDimitry Andric     ret = (sighandler_t)old_cb;
1791fe6060f1SDimitry Andric 
1792fe6060f1SDimitry Andric   *ret_label = 0;
1793fe6060f1SDimitry Andric   return ret;
1794fe6060f1SDimitry Andric }
1795fe6060f1SDimitry Andric 
1796fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
179781ad6265SDimitry Andric sighandler_t __dfsw_signal(int signum, sighandler_t handler,
179881ad6265SDimitry Andric                            dfsan_label signum_label, dfsan_label handler_label,
179981ad6265SDimitry Andric                            dfsan_label *ret_label) {
1800fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1801fe6060f1SDimitry Andric }
1802fe6060f1SDimitry Andric 
1803fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
180481ad6265SDimitry Andric sighandler_t __dfso_signal(int signum, sighandler_t handler,
180581ad6265SDimitry Andric                            dfsan_label signum_label, dfsan_label handler_label,
1806fe6060f1SDimitry Andric                            dfsan_label *ret_label, dfsan_origin signum_origin,
180781ad6265SDimitry Andric                            dfsan_origin handler_origin,
180881ad6265SDimitry Andric                            dfsan_origin *ret_origin) {
1809fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1810fe6060f1SDimitry Andric }
1811fe6060f1SDimitry Andric 
1812fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1813e8d8bef9SDimitry Andric int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1814e8d8bef9SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label) {
1815e8d8bef9SDimitry Andric   int ret = sigaltstack(ss, old_ss);
1816e8d8bef9SDimitry Andric   if (ret != -1 && old_ss)
1817e8d8bef9SDimitry Andric     dfsan_set_label(0, old_ss, sizeof(*old_ss));
1818e8d8bef9SDimitry Andric   *ret_label = 0;
1819e8d8bef9SDimitry Andric   return ret;
1820e8d8bef9SDimitry Andric }
1821e8d8bef9SDimitry Andric 
1822e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1823fe6060f1SDimitry Andric int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1824fe6060f1SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label,
1825fe6060f1SDimitry Andric                        dfsan_origin ss_origin, dfsan_origin old_ss_origin,
1826fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1827fe6060f1SDimitry Andric   return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
1828fe6060f1SDimitry Andric }
1829fe6060f1SDimitry Andric 
1830fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
183168d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
183268d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
183368d75effSDimitry Andric                         dfsan_label *ret_label) {
183468d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
183568d75effSDimitry Andric   if (tv) {
183668d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
183768d75effSDimitry Andric   }
183868d75effSDimitry Andric   if (tz) {
183968d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
184068d75effSDimitry Andric   }
184168d75effSDimitry Andric   *ret_label = 0;
184268d75effSDimitry Andric   return ret;
184368d75effSDimitry Andric }
184468d75effSDimitry Andric 
1845fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1846fe6060f1SDimitry Andric int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz,
1847fe6060f1SDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
1848fe6060f1SDimitry Andric                         dfsan_label *ret_label, dfsan_origin tv_origin,
1849fe6060f1SDimitry Andric                         dfsan_origin tz_origin, dfsan_origin *ret_origin) {
1850fe6060f1SDimitry Andric   return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label);
1851fe6060f1SDimitry Andric }
1852fe6060f1SDimitry Andric 
185368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
185468d75effSDimitry Andric                                                   dfsan_label s_label,
185568d75effSDimitry Andric                                                   dfsan_label c_label,
185668d75effSDimitry Andric                                                   dfsan_label n_label,
185768d75effSDimitry Andric                                                   dfsan_label *ret_label) {
185868d75effSDimitry Andric   void *ret = memchr(s, c, n);
185968d75effSDimitry Andric   if (flags().strict_data_dependencies) {
186068d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
186168d75effSDimitry Andric   } else {
186268d75effSDimitry Andric     size_t len =
186368d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
186468d75effSDimitry Andric             : n;
186568d75effSDimitry Andric     *ret_label =
186668d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
186768d75effSDimitry Andric   }
186868d75effSDimitry Andric   return ret;
186968d75effSDimitry Andric }
187068d75effSDimitry Andric 
1871fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr(
1872fe6060f1SDimitry Andric     void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label,
1873fe6060f1SDimitry Andric     dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin,
1874fe6060f1SDimitry Andric     dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) {
1875fe6060f1SDimitry Andric   void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label);
1876fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1877fe6060f1SDimitry Andric     if (ret)
1878fe6060f1SDimitry Andric       *ret_origin = s_origin;
1879fe6060f1SDimitry Andric   } else {
1880fe6060f1SDimitry Andric     size_t len =
1881fe6060f1SDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
1882fe6060f1SDimitry Andric             : n;
1883fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, len);
1884fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1885fe6060f1SDimitry Andric   }
1886fe6060f1SDimitry Andric   return ret;
1887fe6060f1SDimitry Andric }
1888fe6060f1SDimitry Andric 
188968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
189068d75effSDimitry Andric                                                    dfsan_label s_label,
189168d75effSDimitry Andric                                                    dfsan_label c_label,
189268d75effSDimitry Andric                                                    dfsan_label *ret_label) {
189368d75effSDimitry Andric   char *ret = strrchr(s, c);
189468d75effSDimitry Andric   if (flags().strict_data_dependencies) {
189568d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
189668d75effSDimitry Andric   } else {
189768d75effSDimitry Andric     *ret_label =
189868d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
189968d75effSDimitry Andric                     dfsan_union(s_label, c_label));
190068d75effSDimitry Andric   }
190168d75effSDimitry Andric 
190268d75effSDimitry Andric   return ret;
190368d75effSDimitry Andric }
190468d75effSDimitry Andric 
1905fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr(
1906fe6060f1SDimitry Andric     char *s, int c, dfsan_label s_label, dfsan_label c_label,
1907fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
1908fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
1909fe6060f1SDimitry Andric   char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label);
1910fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1911fe6060f1SDimitry Andric     if (ret)
1912fe6060f1SDimitry Andric       *ret_origin = s_origin;
1913fe6060f1SDimitry Andric   } else {
1914fe6060f1SDimitry Andric     size_t s_len = strlen(s) + 1;
1915fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len);
1916fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1917fe6060f1SDimitry Andric   }
1918fe6060f1SDimitry Andric 
1919fe6060f1SDimitry Andric   return ret;
1920fe6060f1SDimitry Andric }
1921fe6060f1SDimitry Andric 
192268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
192368d75effSDimitry Andric                                                   dfsan_label haystack_label,
192468d75effSDimitry Andric                                                   dfsan_label needle_label,
192568d75effSDimitry Andric                                                   dfsan_label *ret_label) {
192668d75effSDimitry Andric   char *ret = strstr(haystack, needle);
192768d75effSDimitry Andric   if (flags().strict_data_dependencies) {
192868d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
192968d75effSDimitry Andric   } else {
193068d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
193168d75effSDimitry Andric     *ret_label =
193268d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
193368d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
193468d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
193568d75effSDimitry Andric   }
193668d75effSDimitry Andric 
193768d75effSDimitry Andric   return ret;
193868d75effSDimitry Andric }
193968d75effSDimitry Andric 
1940fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle,
1941fe6060f1SDimitry Andric                                                   dfsan_label haystack_label,
1942fe6060f1SDimitry Andric                                                   dfsan_label needle_label,
1943fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
1944fe6060f1SDimitry Andric                                                   dfsan_origin haystack_origin,
1945fe6060f1SDimitry Andric                                                   dfsan_origin needle_origin,
1946fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
1947fe6060f1SDimitry Andric   char *ret =
1948fe6060f1SDimitry Andric       __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label);
1949fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1950fe6060f1SDimitry Andric     if (ret)
1951fe6060f1SDimitry Andric       *ret_origin = haystack_origin;
1952fe6060f1SDimitry Andric   } else {
1953fe6060f1SDimitry Andric     size_t needle_len = strlen(needle);
1954fe6060f1SDimitry Andric     size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1;
1955fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len);
1956fe6060f1SDimitry Andric     if (o) {
1957fe6060f1SDimitry Andric       *ret_origin = o;
1958fe6060f1SDimitry Andric     } else {
1959fe6060f1SDimitry Andric       o = dfsan_read_origin_of_first_taint(needle, needle_len + 1);
1960fe6060f1SDimitry Andric       *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin);
1961fe6060f1SDimitry Andric     }
1962fe6060f1SDimitry Andric   }
1963fe6060f1SDimitry Andric 
1964fe6060f1SDimitry Andric   return ret;
1965fe6060f1SDimitry Andric }
1966fe6060f1SDimitry Andric 
196768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
196868d75effSDimitry Andric                                                    struct timespec *rem,
196968d75effSDimitry Andric                                                    dfsan_label req_label,
197068d75effSDimitry Andric                                                    dfsan_label rem_label,
197168d75effSDimitry Andric                                                    dfsan_label *ret_label) {
197268d75effSDimitry Andric   int ret = nanosleep(req, rem);
197368d75effSDimitry Andric   *ret_label = 0;
197468d75effSDimitry Andric   if (ret == -1) {
197568d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
197668d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
197768d75effSDimitry Andric   }
197868d75effSDimitry Andric   return ret;
197968d75effSDimitry Andric }
198068d75effSDimitry Andric 
1981fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
1982fe6060f1SDimitry Andric     const struct timespec *req, struct timespec *rem, dfsan_label req_label,
1983fe6060f1SDimitry Andric     dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin,
1984fe6060f1SDimitry Andric     dfsan_origin rem_origin, dfsan_origin *ret_origin) {
1985fe6060f1SDimitry Andric   return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
1986fe6060f1SDimitry Andric }
1987fe6060f1SDimitry Andric 
1988e8d8bef9SDimitry Andric static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) {
1989e8d8bef9SDimitry Andric   dfsan_set_label(0, msg, sizeof(*msg));
1990e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
1991e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
1992e8d8bef9SDimitry Andric   for (size_t i = 0; bytes_written > 0; ++i) {
1993e8d8bef9SDimitry Andric     assert(i < msg->msg_iovlen);
1994e8d8bef9SDimitry Andric     struct iovec *iov = &msg->msg_iov[i];
1995e8d8bef9SDimitry Andric     size_t iov_written =
1996e8d8bef9SDimitry Andric         bytes_written < iov->iov_len ? bytes_written : iov->iov_len;
1997e8d8bef9SDimitry Andric     dfsan_set_label(0, iov->iov_base, iov_written);
1998e8d8bef9SDimitry Andric     bytes_written -= iov_written;
1999e8d8bef9SDimitry Andric   }
2000e8d8bef9SDimitry Andric }
2001e8d8bef9SDimitry Andric 
2002e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
2003e8d8bef9SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
2004e8d8bef9SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
2005e8d8bef9SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
2006e8d8bef9SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label) {
2007e8d8bef9SDimitry Andric   int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
2008e8d8bef9SDimitry Andric   for (int i = 0; i < ret; ++i) {
2009e8d8bef9SDimitry Andric     dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
2010e8d8bef9SDimitry Andric     clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr);
2011e8d8bef9SDimitry Andric   }
2012e8d8bef9SDimitry Andric   *ret_label = 0;
2013e8d8bef9SDimitry Andric   return ret;
2014e8d8bef9SDimitry Andric }
2015e8d8bef9SDimitry Andric 
2016fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg(
2017fe6060f1SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
2018fe6060f1SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
2019fe6060f1SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
2020fe6060f1SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label,
2021fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msgvec_origin,
2022fe6060f1SDimitry Andric     dfsan_origin vlen_origin, dfsan_origin flags_origin,
2023fe6060f1SDimitry Andric     dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
2024fe6060f1SDimitry Andric   return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label,
2025fe6060f1SDimitry Andric                          msgvec_label, vlen_label, flags_label, timeout_label,
2026fe6060f1SDimitry Andric                          ret_label);
2027fe6060f1SDimitry Andric }
2028fe6060f1SDimitry Andric 
2029e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
2030e8d8bef9SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
2031e8d8bef9SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
2032e8d8bef9SDimitry Andric   ssize_t ret = recvmsg(sockfd, msg, flags);
2033e8d8bef9SDimitry Andric   if (ret >= 0)
2034e8d8bef9SDimitry Andric     clear_msghdr_labels(ret, msg);
2035e8d8bef9SDimitry Andric   *ret_label = 0;
2036e8d8bef9SDimitry Andric   return ret;
2037e8d8bef9SDimitry Andric }
2038e8d8bef9SDimitry Andric 
2039fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg(
2040fe6060f1SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
2041fe6060f1SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label,
2042fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msg_origin,
2043fe6060f1SDimitry Andric     dfsan_origin flags_origin, dfsan_origin *ret_origin) {
2044fe6060f1SDimitry Andric   return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label,
2045fe6060f1SDimitry Andric                         flags_label, ret_label);
2046fe6060f1SDimitry Andric }
2047fe6060f1SDimitry Andric 
204868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
204968d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
205068d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
205168d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
205268d75effSDimitry Andric                   dfsan_label *ret_label) {
205368d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
205468d75effSDimitry Andric   *ret_label = 0;
205568d75effSDimitry Andric   if (ret == 0) {
205668d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
205768d75effSDimitry Andric   }
205868d75effSDimitry Andric   return ret;
205968d75effSDimitry Andric }
206068d75effSDimitry Andric 
2061fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair(
2062fe6060f1SDimitry Andric     int domain, int type, int protocol, int sv[2], dfsan_label domain_label,
2063fe6060f1SDimitry Andric     dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label,
2064fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin domain_origin,
2065fe6060f1SDimitry Andric     dfsan_origin type_origin, dfsan_origin protocol_origin,
2066fe6060f1SDimitry Andric     dfsan_origin sv_origin, dfsan_origin *ret_origin) {
2067fe6060f1SDimitry Andric   return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label,
2068fe6060f1SDimitry Andric                            protocol_label, sv_label, ret_label);
2069fe6060f1SDimitry Andric }
2070fe6060f1SDimitry Andric 
2071e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt(
2072e8d8bef9SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2073e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2074e8d8bef9SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2075e8d8bef9SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label) {
2076e8d8bef9SDimitry Andric   int ret = getsockopt(sockfd, level, optname, optval, optlen);
2077e8d8bef9SDimitry Andric   if (ret != -1 && optval && optlen) {
2078e8d8bef9SDimitry Andric     dfsan_set_label(0, optlen, sizeof(*optlen));
2079e8d8bef9SDimitry Andric     dfsan_set_label(0, optval, *optlen);
2080e8d8bef9SDimitry Andric   }
2081e8d8bef9SDimitry Andric   *ret_label = 0;
2082e8d8bef9SDimitry Andric   return ret;
2083e8d8bef9SDimitry Andric }
2084e8d8bef9SDimitry Andric 
2085fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt(
2086fe6060f1SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2087fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2088fe6060f1SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2089fe6060f1SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label,
2090fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin level_origin,
2091fe6060f1SDimitry Andric     dfsan_origin optname_origin, dfsan_origin optval_origin,
2092fe6060f1SDimitry Andric     dfsan_origin optlen_origin, dfsan_origin *ret_origin) {
2093fe6060f1SDimitry Andric   return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label,
2094fe6060f1SDimitry Andric                            level_label, optname_label, optval_label,
2095fe6060f1SDimitry Andric                            optlen_label, ret_label);
2096fe6060f1SDimitry Andric }
2097fe6060f1SDimitry Andric 
2098e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname(
2099e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2100e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2101e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2102e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2103e8d8bef9SDimitry Andric   int ret = getsockname(sockfd, addr, addrlen);
2104e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2105e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2106e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2107e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2108e8d8bef9SDimitry Andric   }
2109e8d8bef9SDimitry Andric   *ret_label = 0;
2110e8d8bef9SDimitry Andric   return ret;
2111e8d8bef9SDimitry Andric }
2112e8d8bef9SDimitry Andric 
2113fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname(
2114fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2115fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2116fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2117fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2118fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2119fe6060f1SDimitry Andric   return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label,
2120fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2121fe6060f1SDimitry Andric }
2122fe6060f1SDimitry Andric 
2123e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername(
2124e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2125e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2126e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2127e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2128e8d8bef9SDimitry Andric   int ret = getpeername(sockfd, addr, addrlen);
2129e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2130e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2131e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2132e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2133e8d8bef9SDimitry Andric   }
2134e8d8bef9SDimitry Andric   *ret_label = 0;
2135e8d8bef9SDimitry Andric   return ret;
2136e8d8bef9SDimitry Andric }
2137e8d8bef9SDimitry Andric 
2138fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername(
2139fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2140fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2141fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2142fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2143fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2144fe6060f1SDimitry Andric   return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label,
2145fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2146fe6060f1SDimitry Andric }
2147fe6060f1SDimitry Andric 
214881ad6265SDimitry Andric // Type of the function passed to dfsan_set_write_callback.
214981ad6265SDimitry Andric typedef void (*write_dfsan_callback_t)(int fd, const void *buf, ssize_t count);
2150fe6060f1SDimitry Andric 
215168d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
215268d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
215368d75effSDimitry Andric static struct {
215481ad6265SDimitry Andric   write_dfsan_callback_t write_callback = nullptr;
215568d75effSDimitry Andric } write_callback_info;
215668d75effSDimitry Andric 
215781ad6265SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_dfsan_set_write_callback(
215881ad6265SDimitry Andric     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
215968d75effSDimitry Andric     dfsan_label *ret_label) {
216068d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
216168d75effSDimitry Andric }
216268d75effSDimitry Andric 
2163fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
216481ad6265SDimitry Andric     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
216581ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin write_callback_origin,
216681ad6265SDimitry Andric     dfsan_origin *ret_origin) {
216781ad6265SDimitry Andric   write_callback_info.write_callback = write_callback;
216881ad6265SDimitry Andric }
216981ad6265SDimitry Andric 
217081ad6265SDimitry Andric static inline void setup_tls_args_for_write_callback(
217181ad6265SDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
217281ad6265SDimitry Andric     bool origins, dfsan_origin fd_origin, dfsan_origin buf_origin,
217381ad6265SDimitry Andric     dfsan_origin count_origin) {
217481ad6265SDimitry Andric   // The callback code will expect argument shadow labels in the args TLS,
217581ad6265SDimitry Andric   // and origin labels in the origin args TLS.
217681ad6265SDimitry Andric   // Previously this was done by a trampoline, but we want to remove this:
217781ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/issues/54172
217881ad6265SDimitry Andric   //
217981ad6265SDimitry Andric   // Instead, this code is manually setting up the args TLS data.
218081ad6265SDimitry Andric   //
218181ad6265SDimitry Andric   // The offsets used need to correspond with the instrumentation code,
218281ad6265SDimitry Andric   // see llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
218381ad6265SDimitry Andric   // DFSanFunction::getShadowForTLSArgument.
218481ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L1684
218581ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L125
218681ad6265SDimitry Andric   //
218781ad6265SDimitry Andric   // Here the arguments are all primitives, but it can be more complex
218881ad6265SDimitry Andric   // to compute offsets for array/aggregate type arguments.
218981ad6265SDimitry Andric   //
219081ad6265SDimitry Andric   // TODO(browneee): Consider a builtin to improve maintainabliity.
219181ad6265SDimitry Andric   // With a builtin, we would provide the argument labels via builtin,
219281ad6265SDimitry Andric   // and the builtin would reuse parts of the instrumentation code to ensure
219381ad6265SDimitry Andric   // that this code and the instrumentation can never be out of sync.
219481ad6265SDimitry Andric   // Note: Currently DFSan instrumentation does not run on this code, so
219581ad6265SDimitry Andric   // the builtin may need to be handled outside DFSan instrumentation.
219681ad6265SDimitry Andric   dfsan_set_arg_tls(0, fd_label);
219781ad6265SDimitry Andric   dfsan_set_arg_tls(1, buf_label);
219881ad6265SDimitry Andric   dfsan_set_arg_tls(2, count_label);
219981ad6265SDimitry Andric   if (origins) {
220081ad6265SDimitry Andric     dfsan_set_arg_origin_tls(0, fd_origin);
220181ad6265SDimitry Andric     dfsan_set_arg_origin_tls(1, buf_origin);
220281ad6265SDimitry Andric     dfsan_set_arg_origin_tls(2, count_origin);
220381ad6265SDimitry Andric   }
2204fe6060f1SDimitry Andric }
2205fe6060f1SDimitry Andric 
220668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
220768d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
220868d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
220968d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
221068d75effSDimitry Andric   if (write_callback_info.write_callback) {
221181ad6265SDimitry Andric     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, false,
221281ad6265SDimitry Andric                                       0, 0, 0);
221381ad6265SDimitry Andric     write_callback_info.write_callback(fd, buf, count);
221468d75effSDimitry Andric   }
221568d75effSDimitry Andric 
221668d75effSDimitry Andric   *ret_label = 0;
221768d75effSDimitry Andric   return write(fd, buf, count);
221868d75effSDimitry Andric }
2219fe6060f1SDimitry Andric 
2220fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
2221fe6060f1SDimitry Andric     int fd, const void *buf, size_t count, dfsan_label fd_label,
2222fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
2223fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
2224fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
222581ad6265SDimitry Andric   if (write_callback_info.write_callback) {
222681ad6265SDimitry Andric     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, true,
222781ad6265SDimitry Andric                                       fd_origin, buf_origin, count_origin);
222881ad6265SDimitry Andric     write_callback_info.write_callback(fd, buf, count);
2229fe6060f1SDimitry Andric   }
2230fe6060f1SDimitry Andric 
2231fe6060f1SDimitry Andric   *ret_label = 0;
2232fe6060f1SDimitry Andric   return write(fd, buf, count);
2233fe6060f1SDimitry Andric }
223468d75effSDimitry Andric } // namespace __dfsan
223568d75effSDimitry Andric 
223668d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
223768d75effSDimitry Andric typedef int dfsan_label_va;
223868d75effSDimitry Andric 
223968d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
224068d75effSDimitry Andric // '%.3f').
224168d75effSDimitry Andric struct Formatter {
224268d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
22435f757f3fSDimitry Andric       : str(str_),
22445f757f3fSDimitry Andric         str_off(0),
22455f757f3fSDimitry Andric         size(size_),
22465f757f3fSDimitry Andric         fmt_start(fmt_),
22475f757f3fSDimitry Andric         fmt_cur(fmt_),
22485f757f3fSDimitry Andric         width(-1),
22495f757f3fSDimitry Andric         num_scanned(-1),
22505f757f3fSDimitry Andric         skip(false) {}
225168d75effSDimitry Andric 
225268d75effSDimitry Andric   int format() {
225368d75effSDimitry Andric     char *tmp_fmt = build_format_string();
225468d75effSDimitry Andric     int retval =
225568d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
225668d75effSDimitry Andric                  0 /* used only to avoid warnings */);
225768d75effSDimitry Andric     free(tmp_fmt);
225868d75effSDimitry Andric     return retval;
225968d75effSDimitry Andric   }
226068d75effSDimitry Andric 
226168d75effSDimitry Andric   template <typename T> int format(T arg) {
226268d75effSDimitry Andric     char *tmp_fmt = build_format_string();
226368d75effSDimitry Andric     int retval;
226468d75effSDimitry Andric     if (width >= 0) {
226568d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
226668d75effSDimitry Andric                         tmp_fmt, width, arg);
226768d75effSDimitry Andric     } else {
226868d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
226968d75effSDimitry Andric                         tmp_fmt, arg);
227068d75effSDimitry Andric     }
227168d75effSDimitry Andric     free(tmp_fmt);
227268d75effSDimitry Andric     return retval;
227368d75effSDimitry Andric   }
227468d75effSDimitry Andric 
22755f757f3fSDimitry Andric   int scan() {
22765f757f3fSDimitry Andric     char *tmp_fmt = build_format_string(true);
22775f757f3fSDimitry Andric     int read_count = 0;
22785f757f3fSDimitry Andric     int retval = sscanf(str + str_off, tmp_fmt, &read_count);
22795f757f3fSDimitry Andric     if (retval > 0) {
22805f757f3fSDimitry Andric       if (-1 == num_scanned)
22815f757f3fSDimitry Andric         num_scanned = 0;
22825f757f3fSDimitry Andric       num_scanned += retval;
22835f757f3fSDimitry Andric     }
22845f757f3fSDimitry Andric     free(tmp_fmt);
22855f757f3fSDimitry Andric     return read_count;
22865f757f3fSDimitry Andric   }
22875f757f3fSDimitry Andric 
22885f757f3fSDimitry Andric   template <typename T>
22895f757f3fSDimitry Andric   int scan(T arg) {
22905f757f3fSDimitry Andric     char *tmp_fmt = build_format_string(true);
22915f757f3fSDimitry Andric     int read_count = 0;
22925f757f3fSDimitry Andric     int retval = sscanf(str + str_off, tmp_fmt, arg, &read_count);
22935f757f3fSDimitry Andric     if (retval > 0) {
22945f757f3fSDimitry Andric       if (-1 == num_scanned)
22955f757f3fSDimitry Andric         num_scanned = 0;
22965f757f3fSDimitry Andric       num_scanned += retval;
22975f757f3fSDimitry Andric     }
22985f757f3fSDimitry Andric     free(tmp_fmt);
22995f757f3fSDimitry Andric     return read_count;
23005f757f3fSDimitry Andric   }
23015f757f3fSDimitry Andric 
23025f757f3fSDimitry Andric   // with_n -> toggles adding %n on/off; off by default
23035f757f3fSDimitry Andric   char *build_format_string(bool with_n = false) {
230468d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
23055f757f3fSDimitry Andric     size_t add_size = 0;
23065f757f3fSDimitry Andric     if (with_n)
23075f757f3fSDimitry Andric       add_size = 2;
23085f757f3fSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1 + add_size);
230968d75effSDimitry Andric     assert(new_fmt);
231068d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
23115f757f3fSDimitry Andric     if (!with_n) {
231268d75effSDimitry Andric       new_fmt[fmt_size] = '\0';
23135f757f3fSDimitry Andric     } else {
23145f757f3fSDimitry Andric       new_fmt[fmt_size] = '%';
23155f757f3fSDimitry Andric       new_fmt[fmt_size + 1] = 'n';
23165f757f3fSDimitry Andric       new_fmt[fmt_size + 2] = '\0';
23175f757f3fSDimitry Andric     }
23185f757f3fSDimitry Andric 
231968d75effSDimitry Andric     return new_fmt;
232068d75effSDimitry Andric   }
232168d75effSDimitry Andric 
232268d75effSDimitry Andric   char *str_cur() { return str + str_off; }
232368d75effSDimitry Andric 
232468d75effSDimitry Andric   size_t num_written_bytes(int retval) {
232568d75effSDimitry Andric     if (retval < 0) {
232668d75effSDimitry Andric       return 0;
232768d75effSDimitry Andric     }
232868d75effSDimitry Andric 
232968d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
233068d75effSDimitry Andric     if (num_avail == 0) {
233168d75effSDimitry Andric       return 0;
233268d75effSDimitry Andric     }
233368d75effSDimitry Andric 
233468d75effSDimitry Andric     size_t num_written = retval;
233568d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
233668d75effSDimitry Andric     // truncated.
233768d75effSDimitry Andric     if (num_written >= num_avail) {
233868d75effSDimitry Andric       num_written -= num_avail;
233968d75effSDimitry Andric     }
234068d75effSDimitry Andric 
234168d75effSDimitry Andric     return num_written;
234268d75effSDimitry Andric   }
234368d75effSDimitry Andric 
234468d75effSDimitry Andric   char *str;
234568d75effSDimitry Andric   size_t str_off;
234668d75effSDimitry Andric   size_t size;
234768d75effSDimitry Andric   const char *fmt_start;
234868d75effSDimitry Andric   const char *fmt_cur;
234968d75effSDimitry Andric   int width;
23505f757f3fSDimitry Andric   int num_scanned;
23515f757f3fSDimitry Andric   bool skip;
235268d75effSDimitry Andric };
235368d75effSDimitry Andric 
235468d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
235568d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
235668d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
235768d75effSDimitry Andric // the return value vsnprintf would return.
235868d75effSDimitry Andric //
235968d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
236068d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
236168d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
236268d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
236368d75effSDimitry Andric // propagate labels more precisely.
236468d75effSDimitry Andric //
236568d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
236668d75effSDimitry Andric // positional arguments.
236768d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
236868d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
2369fe6060f1SDimitry Andric                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
237068d75effSDimitry Andric                          va_list ap) {
237168d75effSDimitry Andric   Formatter formatter(str, fmt, size);
237268d75effSDimitry Andric 
237368d75effSDimitry Andric   while (*formatter.fmt_cur) {
237468d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
237568d75effSDimitry Andric     formatter.width = -1;
237668d75effSDimitry Andric     int retval = 0;
237768d75effSDimitry Andric 
237868d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
237968d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
238068d75effSDimitry Andric       // of the string.
238168d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
238268d75effSDimitry Andric            ++formatter.fmt_cur) {}
238368d75effSDimitry Andric       retval = formatter.format();
238468d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
238568d75effSDimitry Andric                       formatter.num_written_bytes(retval));
238668d75effSDimitry Andric     } else {
238768d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
238868d75effSDimitry Andric       // specifier or the end of the string.
238968d75effSDimitry Andric       bool end_fmt = false;
239068d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
239168d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
239268d75effSDimitry Andric         case 'd':
239368d75effSDimitry Andric         case 'i':
239468d75effSDimitry Andric         case 'o':
239568d75effSDimitry Andric         case 'u':
239668d75effSDimitry Andric         case 'x':
239768d75effSDimitry Andric         case 'X':
239868d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
239968d75effSDimitry Andric           case 'h':
240068d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
240168d75effSDimitry Andric             // an int).
240268d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
240368d75effSDimitry Andric             break;
240468d75effSDimitry Andric           case 'l':
240568d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
240668d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
240768d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
240868d75effSDimitry Andric             } else {
240968d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
241068d75effSDimitry Andric             }
241168d75effSDimitry Andric             break;
241268d75effSDimitry Andric           case 'q':
241368d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
241468d75effSDimitry Andric             break;
241568d75effSDimitry Andric           case 'j':
241668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
241768d75effSDimitry Andric             break;
241868d75effSDimitry Andric           case 'z':
241968d75effSDimitry Andric           case 't':
242068d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
242168d75effSDimitry Andric             break;
242268d75effSDimitry Andric           default:
242368d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
242468d75effSDimitry Andric           }
2425fe6060f1SDimitry Andric           if (va_origins == nullptr)
242668d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
242768d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2428fe6060f1SDimitry Andric           else
2429fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2430fe6060f1SDimitry Andric                                    formatter.str_cur(),
2431fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
243268d75effSDimitry Andric           end_fmt = true;
243368d75effSDimitry Andric           break;
243468d75effSDimitry Andric 
243568d75effSDimitry Andric         case 'a':
243668d75effSDimitry Andric         case 'A':
243768d75effSDimitry Andric         case 'e':
243868d75effSDimitry Andric         case 'E':
243968d75effSDimitry Andric         case 'f':
244068d75effSDimitry Andric         case 'F':
244168d75effSDimitry Andric         case 'g':
244268d75effSDimitry Andric         case 'G':
244368d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
244468d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
244568d75effSDimitry Andric           } else {
244668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
244768d75effSDimitry Andric           }
2448fe6060f1SDimitry Andric           if (va_origins == nullptr)
244968d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
245068d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2451fe6060f1SDimitry Andric           else
2452fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2453fe6060f1SDimitry Andric                                    formatter.str_cur(),
2454fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
245568d75effSDimitry Andric           end_fmt = true;
245668d75effSDimitry Andric           break;
245768d75effSDimitry Andric 
245868d75effSDimitry Andric         case 'c':
245968d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
2460fe6060f1SDimitry Andric           if (va_origins == nullptr)
246168d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
246268d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2463fe6060f1SDimitry Andric           else
2464fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2465fe6060f1SDimitry Andric                                    formatter.str_cur(),
2466fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
246768d75effSDimitry Andric           end_fmt = true;
246868d75effSDimitry Andric           break;
246968d75effSDimitry Andric 
247068d75effSDimitry Andric         case 's': {
247168d75effSDimitry Andric           char *arg = va_arg(ap, char *);
247268d75effSDimitry Andric           retval = formatter.format(arg);
2473fe6060f1SDimitry Andric           if (va_origins) {
2474fe6060f1SDimitry Andric             va_origins++;
2475fe6060f1SDimitry Andric             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
2476fe6060f1SDimitry Andric                                       formatter.num_written_bytes(retval));
2477fe6060f1SDimitry Andric           }
247868d75effSDimitry Andric           va_labels++;
247904eeddc0SDimitry Andric           dfsan_mem_shadow_transfer(formatter.str_cur(), arg,
248068d75effSDimitry Andric                                     formatter.num_written_bytes(retval));
248168d75effSDimitry Andric           end_fmt = true;
248268d75effSDimitry Andric           break;
248368d75effSDimitry Andric         }
248468d75effSDimitry Andric 
248568d75effSDimitry Andric         case 'p':
248668d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
2487fe6060f1SDimitry Andric           if (va_origins == nullptr)
248868d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
248968d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2490fe6060f1SDimitry Andric           else
2491fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2492fe6060f1SDimitry Andric                                    formatter.str_cur(),
2493fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
249468d75effSDimitry Andric           end_fmt = true;
249568d75effSDimitry Andric           break;
249668d75effSDimitry Andric 
249768d75effSDimitry Andric         case 'n': {
249868d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
249968d75effSDimitry Andric           *ptr = (int)formatter.str_off;
250068d75effSDimitry Andric           va_labels++;
2501fe6060f1SDimitry Andric           if (va_origins)
2502fe6060f1SDimitry Andric             va_origins++;
250368d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
250468d75effSDimitry Andric           end_fmt = true;
250568d75effSDimitry Andric           break;
250668d75effSDimitry Andric         }
250768d75effSDimitry Andric 
250868d75effSDimitry Andric         case '%':
250968d75effSDimitry Andric           retval = formatter.format();
251068d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
251168d75effSDimitry Andric                           formatter.num_written_bytes(retval));
251268d75effSDimitry Andric           end_fmt = true;
251368d75effSDimitry Andric           break;
251468d75effSDimitry Andric 
251568d75effSDimitry Andric         case '*':
251668d75effSDimitry Andric           formatter.width = va_arg(ap, int);
251768d75effSDimitry Andric           va_labels++;
2518fe6060f1SDimitry Andric           if (va_origins)
2519fe6060f1SDimitry Andric             va_origins++;
252068d75effSDimitry Andric           break;
252168d75effSDimitry Andric 
252268d75effSDimitry Andric         default:
252368d75effSDimitry Andric           break;
252468d75effSDimitry Andric         }
252568d75effSDimitry Andric       }
252668d75effSDimitry Andric     }
252768d75effSDimitry Andric 
252868d75effSDimitry Andric     if (retval < 0) {
252968d75effSDimitry Andric       return retval;
253068d75effSDimitry Andric     }
253168d75effSDimitry Andric 
253268d75effSDimitry Andric     formatter.fmt_cur++;
253368d75effSDimitry Andric     formatter.str_off += retval;
253468d75effSDimitry Andric   }
253568d75effSDimitry Andric 
253668d75effSDimitry Andric   *ret_label = 0;
2537fe6060f1SDimitry Andric   if (ret_origin)
2538fe6060f1SDimitry Andric     *ret_origin = 0;
253968d75effSDimitry Andric 
254068d75effSDimitry Andric   // Number of bytes written in total.
254168d75effSDimitry Andric   return formatter.str_off;
254268d75effSDimitry Andric }
254368d75effSDimitry Andric 
25445f757f3fSDimitry Andric // This function is an inverse of format_buffer: we take the input buffer,
25455f757f3fSDimitry Andric // scan it in search for format strings and store the results in the varargs.
25465f757f3fSDimitry Andric // The labels are propagated from the input buffer to the varargs.
25475f757f3fSDimitry Andric static int scan_buffer(char *str, size_t size, const char *fmt,
25485f757f3fSDimitry Andric                        dfsan_label *va_labels, dfsan_label *ret_label,
25495f757f3fSDimitry Andric                        dfsan_origin *str_origin, dfsan_origin *ret_origin,
25505f757f3fSDimitry Andric                        va_list ap) {
25515f757f3fSDimitry Andric   Formatter formatter(str, fmt, size);
25525f757f3fSDimitry Andric   while (*formatter.fmt_cur) {
25535f757f3fSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
25545f757f3fSDimitry Andric     formatter.width = -1;
25555f757f3fSDimitry Andric     formatter.skip = false;
25565f757f3fSDimitry Andric     int read_count = 0;
25575f757f3fSDimitry Andric     void *dst_ptr = 0;
25585f757f3fSDimitry Andric     size_t write_size = 0;
25595f757f3fSDimitry Andric     if (*formatter.fmt_cur != '%') {
25605f757f3fSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
25615f757f3fSDimitry Andric       // of the string.
25625f757f3fSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
25635f757f3fSDimitry Andric            ++formatter.fmt_cur) {
25645f757f3fSDimitry Andric       }
25655f757f3fSDimitry Andric       read_count = formatter.scan();
25665f757f3fSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
25675f757f3fSDimitry Andric                       formatter.num_written_bytes(read_count));
25685f757f3fSDimitry Andric     } else {
25695f757f3fSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
25705f757f3fSDimitry Andric       // specifier or the end of the string.
25715f757f3fSDimitry Andric       bool end_fmt = false;
25725f757f3fSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt;) {
25735f757f3fSDimitry Andric         switch (*++formatter.fmt_cur) {
25745f757f3fSDimitry Andric         case 'd':
25755f757f3fSDimitry Andric         case 'i':
25765f757f3fSDimitry Andric         case 'o':
25775f757f3fSDimitry Andric         case 'u':
25785f757f3fSDimitry Andric         case 'x':
25795f757f3fSDimitry Andric         case 'X':
25805f757f3fSDimitry Andric           if (formatter.skip) {
25815f757f3fSDimitry Andric             read_count = formatter.scan();
25825f757f3fSDimitry Andric           } else {
25835f757f3fSDimitry Andric             switch (*(formatter.fmt_cur - 1)) {
25845f757f3fSDimitry Andric             case 'h':
25855f757f3fSDimitry Andric               // Also covers the 'hh' case (since the size of the arg is still
25865f757f3fSDimitry Andric               // an int).
25875f757f3fSDimitry Andric               dst_ptr = va_arg(ap, int *);
25885f757f3fSDimitry Andric               read_count = formatter.scan((int *)dst_ptr);
25895f757f3fSDimitry Andric               write_size = sizeof(int);
25905f757f3fSDimitry Andric               break;
25915f757f3fSDimitry Andric             case 'l':
25925f757f3fSDimitry Andric               if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
25935f757f3fSDimitry Andric                   *(formatter.fmt_cur - 2) == 'l') {
25945f757f3fSDimitry Andric                 dst_ptr = va_arg(ap, long long int *);
25955f757f3fSDimitry Andric                 read_count = formatter.scan((long long int *)dst_ptr);
25965f757f3fSDimitry Andric                 write_size = sizeof(long long int);
25975f757f3fSDimitry Andric               } else {
25985f757f3fSDimitry Andric                 dst_ptr = va_arg(ap, long int *);
25995f757f3fSDimitry Andric                 read_count = formatter.scan((long int *)dst_ptr);
26005f757f3fSDimitry Andric                 write_size = sizeof(long int);
26015f757f3fSDimitry Andric               }
26025f757f3fSDimitry Andric               break;
26035f757f3fSDimitry Andric             case 'q':
26045f757f3fSDimitry Andric               dst_ptr = va_arg(ap, long long int *);
26055f757f3fSDimitry Andric               read_count = formatter.scan((long long int *)dst_ptr);
26065f757f3fSDimitry Andric               write_size = sizeof(long long int);
26075f757f3fSDimitry Andric               break;
26085f757f3fSDimitry Andric             case 'j':
26095f757f3fSDimitry Andric               dst_ptr = va_arg(ap, intmax_t *);
26105f757f3fSDimitry Andric               read_count = formatter.scan((intmax_t *)dst_ptr);
26115f757f3fSDimitry Andric               write_size = sizeof(intmax_t);
26125f757f3fSDimitry Andric               break;
26135f757f3fSDimitry Andric             case 'z':
26145f757f3fSDimitry Andric             case 't':
26155f757f3fSDimitry Andric               dst_ptr = va_arg(ap, size_t *);
26165f757f3fSDimitry Andric               read_count = formatter.scan((size_t *)dst_ptr);
26175f757f3fSDimitry Andric               write_size = sizeof(size_t);
26185f757f3fSDimitry Andric               break;
26195f757f3fSDimitry Andric             default:
26205f757f3fSDimitry Andric               dst_ptr = va_arg(ap, int *);
26215f757f3fSDimitry Andric               read_count = formatter.scan((int *)dst_ptr);
26225f757f3fSDimitry Andric               write_size = sizeof(int);
26235f757f3fSDimitry Andric             }
26245f757f3fSDimitry Andric             // get the label associated with the string at the corresponding
26255f757f3fSDimitry Andric             // place
26265f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
26275f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
26285f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26295f757f3fSDimitry Andric             if (str_origin != nullptr) {
26305f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26315f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
26325f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
26335f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
26345f757f3fSDimitry Andric             }
26355f757f3fSDimitry Andric           }
26365f757f3fSDimitry Andric           end_fmt = true;
26375f757f3fSDimitry Andric 
26385f757f3fSDimitry Andric           break;
26395f757f3fSDimitry Andric 
26405f757f3fSDimitry Andric         case 'a':
26415f757f3fSDimitry Andric         case 'A':
26425f757f3fSDimitry Andric         case 'e':
26435f757f3fSDimitry Andric         case 'E':
26445f757f3fSDimitry Andric         case 'f':
26455f757f3fSDimitry Andric         case 'F':
26465f757f3fSDimitry Andric         case 'g':
26475f757f3fSDimitry Andric         case 'G':
26485f757f3fSDimitry Andric           if (formatter.skip) {
26495f757f3fSDimitry Andric             read_count = formatter.scan();
26505f757f3fSDimitry Andric           } else {
26515f757f3fSDimitry Andric             if (*(formatter.fmt_cur - 1) == 'L') {
26525f757f3fSDimitry Andric             dst_ptr = va_arg(ap, long double *);
26535f757f3fSDimitry Andric             read_count = formatter.scan((long double *)dst_ptr);
26545f757f3fSDimitry Andric             write_size = sizeof(long double);
26555f757f3fSDimitry Andric             } else if (*(formatter.fmt_cur - 1) == 'l') {
26565f757f3fSDimitry Andric             dst_ptr = va_arg(ap, double *);
26575f757f3fSDimitry Andric             read_count = formatter.scan((double *)dst_ptr);
26585f757f3fSDimitry Andric             write_size = sizeof(double);
26595f757f3fSDimitry Andric             } else {
26605f757f3fSDimitry Andric             dst_ptr = va_arg(ap, float *);
26615f757f3fSDimitry Andric             read_count = formatter.scan((float *)dst_ptr);
26625f757f3fSDimitry Andric             write_size = sizeof(float);
26635f757f3fSDimitry Andric             }
26645f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
26655f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
26665f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26675f757f3fSDimitry Andric             if (str_origin != nullptr) {
26685f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26695f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
26705f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
26715f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
26725f757f3fSDimitry Andric             }
26735f757f3fSDimitry Andric           }
26745f757f3fSDimitry Andric           end_fmt = true;
26755f757f3fSDimitry Andric           break;
26765f757f3fSDimitry Andric 
26775f757f3fSDimitry Andric         case 'c':
26785f757f3fSDimitry Andric           if (formatter.skip) {
26795f757f3fSDimitry Andric             read_count = formatter.scan();
26805f757f3fSDimitry Andric           } else {
26815f757f3fSDimitry Andric             dst_ptr = va_arg(ap, char *);
26825f757f3fSDimitry Andric             read_count = formatter.scan((char *)dst_ptr);
26835f757f3fSDimitry Andric             write_size = sizeof(char);
26845f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
26855f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
26865f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
26875f757f3fSDimitry Andric             if (str_origin != nullptr) {
26885f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
26895f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
26905f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
26915f757f3fSDimitry Andric             }
26925f757f3fSDimitry Andric           }
26935f757f3fSDimitry Andric           end_fmt = true;
26945f757f3fSDimitry Andric           break;
26955f757f3fSDimitry Andric 
26965f757f3fSDimitry Andric         case 's': {
26975f757f3fSDimitry Andric           if (formatter.skip) {
26985f757f3fSDimitry Andric             read_count = formatter.scan();
26995f757f3fSDimitry Andric           } else {
27005f757f3fSDimitry Andric             dst_ptr = va_arg(ap, char *);
27015f757f3fSDimitry Andric             read_count = formatter.scan((char *)dst_ptr);
27025f757f3fSDimitry Andric             if (1 == read_count) {
27035f757f3fSDimitry Andric             // special case: we have parsed a single string and we need to
27045f757f3fSDimitry Andric             // update read_count with the string size
27055f757f3fSDimitry Andric             read_count = strlen((char *)dst_ptr);
27065f757f3fSDimitry Andric             }
27075f757f3fSDimitry Andric             if (str_origin)
27085f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(),
27095f757f3fSDimitry Andric                                       formatter.num_written_bytes(read_count));
27105f757f3fSDimitry Andric             va_labels++;
27115f757f3fSDimitry Andric             dfsan_mem_shadow_transfer(dst_ptr, formatter.str_cur(),
27125f757f3fSDimitry Andric                                       formatter.num_written_bytes(read_count));
27135f757f3fSDimitry Andric           }
27145f757f3fSDimitry Andric           end_fmt = true;
27155f757f3fSDimitry Andric           break;
27165f757f3fSDimitry Andric         }
27175f757f3fSDimitry Andric 
27185f757f3fSDimitry Andric         case 'p':
27195f757f3fSDimitry Andric           if (formatter.skip) {
27205f757f3fSDimitry Andric             read_count = formatter.scan();
27215f757f3fSDimitry Andric           } else {
27225f757f3fSDimitry Andric             dst_ptr = va_arg(ap, void *);
27235f757f3fSDimitry Andric             read_count =
27245f757f3fSDimitry Andric                 formatter.scan((int *)dst_ptr);  // note: changing void* to int*
27255f757f3fSDimitry Andric                                                  // since we need to call sizeof
27265f757f3fSDimitry Andric             write_size = sizeof(int);
27275f757f3fSDimitry Andric 
27285f757f3fSDimitry Andric             dfsan_label l = dfsan_read_label(
27295f757f3fSDimitry Andric                 formatter.str_cur(), formatter.num_written_bytes(read_count));
27305f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
27315f757f3fSDimitry Andric             if (str_origin != nullptr) {
27325f757f3fSDimitry Andric             dfsan_set_label(l, dst_ptr, write_size);
27335f757f3fSDimitry Andric             size_t scan_count = formatter.num_written_bytes(read_count);
27345f757f3fSDimitry Andric             size_t size = scan_count > write_size ? write_size : scan_count;
27355f757f3fSDimitry Andric             dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size);
27365f757f3fSDimitry Andric             }
27375f757f3fSDimitry Andric           }
27385f757f3fSDimitry Andric           end_fmt = true;
27395f757f3fSDimitry Andric           break;
27405f757f3fSDimitry Andric 
27415f757f3fSDimitry Andric         case 'n': {
27425f757f3fSDimitry Andric           if (!formatter.skip) {
27435f757f3fSDimitry Andric             int *ptr = va_arg(ap, int *);
27445f757f3fSDimitry Andric             *ptr = (int)formatter.str_off;
27455f757f3fSDimitry Andric             *va_labels++ = 0;
27465f757f3fSDimitry Andric             dfsan_set_label(0, ptr, sizeof(*ptr));
27475f757f3fSDimitry Andric             if (str_origin != nullptr)
27485f757f3fSDimitry Andric             *str_origin++ = 0;
27495f757f3fSDimitry Andric           }
27505f757f3fSDimitry Andric           end_fmt = true;
27515f757f3fSDimitry Andric           break;
27525f757f3fSDimitry Andric         }
27535f757f3fSDimitry Andric 
27545f757f3fSDimitry Andric         case '%':
27555f757f3fSDimitry Andric           read_count = formatter.scan();
27565f757f3fSDimitry Andric           end_fmt = true;
27575f757f3fSDimitry Andric           break;
27585f757f3fSDimitry Andric 
27595f757f3fSDimitry Andric         case '*':
27605f757f3fSDimitry Andric           formatter.skip = true;
27615f757f3fSDimitry Andric           break;
27625f757f3fSDimitry Andric 
27635f757f3fSDimitry Andric         default:
27645f757f3fSDimitry Andric           break;
27655f757f3fSDimitry Andric         }
27665f757f3fSDimitry Andric       }
27675f757f3fSDimitry Andric     }
27685f757f3fSDimitry Andric 
27695f757f3fSDimitry Andric     if (read_count < 0) {
27705f757f3fSDimitry Andric       // There was an error.
27715f757f3fSDimitry Andric       return read_count;
27725f757f3fSDimitry Andric     }
27735f757f3fSDimitry Andric 
27745f757f3fSDimitry Andric     formatter.fmt_cur++;
27755f757f3fSDimitry Andric     formatter.str_off += read_count;
27765f757f3fSDimitry Andric   }
27775f757f3fSDimitry Andric 
27785f757f3fSDimitry Andric   (void)va_labels; // Silence unused-but-set-parameter warning
27795f757f3fSDimitry Andric   *ret_label = 0;
27805f757f3fSDimitry Andric   if (ret_origin)
27815f757f3fSDimitry Andric     *ret_origin = 0;
27825f757f3fSDimitry Andric 
27835f757f3fSDimitry Andric   // Number of items scanned in total.
27845f757f3fSDimitry Andric   return formatter.num_scanned;
27855f757f3fSDimitry Andric }
27865f757f3fSDimitry Andric 
278768d75effSDimitry Andric extern "C" {
278868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
278968d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
279068d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
279168d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
279268d75effSDimitry Andric   va_list ap;
279368d75effSDimitry Andric   va_start(ap, ret_label);
27945f757f3fSDimitry Andric 
2795fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
2796fe6060f1SDimitry Andric                           nullptr, ap);
2797fe6060f1SDimitry Andric   va_end(ap);
2798fe6060f1SDimitry Andric   return ret;
2799fe6060f1SDimitry Andric }
2800fe6060f1SDimitry Andric 
2801fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2802fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
2803fe6060f1SDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
2804fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin str_origin,
2805fe6060f1SDimitry Andric                    dfsan_origin format_origin, dfsan_origin *va_origins,
2806fe6060f1SDimitry Andric                    dfsan_origin *ret_origin, ...) {
2807fe6060f1SDimitry Andric   va_list ap;
2808fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2809fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, va_origins,
2810fe6060f1SDimitry Andric                           ret_origin, ap);
281168d75effSDimitry Andric   va_end(ap);
281268d75effSDimitry Andric   return ret;
281368d75effSDimitry Andric }
281468d75effSDimitry Andric 
281568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
281668d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
281768d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
281868d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
281968d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
282068d75effSDimitry Andric   va_list ap;
282168d75effSDimitry Andric   va_start(ap, ret_label);
2822fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
2823fe6060f1SDimitry Andric                           nullptr, ap);
282468d75effSDimitry Andric   va_end(ap);
282568d75effSDimitry Andric   return ret;
282668d75effSDimitry Andric }
282768d75effSDimitry Andric 
2828fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2829fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format,
2830fe6060f1SDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
2831fe6060f1SDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
2832fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin str_origin,
2833fe6060f1SDimitry Andric                     dfsan_origin size_origin, dfsan_origin format_origin,
2834fe6060f1SDimitry Andric                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
2835fe6060f1SDimitry Andric   va_list ap;
2836fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2837fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
2838fe6060f1SDimitry Andric                           ret_origin, ap);
2839fe6060f1SDimitry Andric   va_end(ap);
2840fe6060f1SDimitry Andric   return ret;
2841fe6060f1SDimitry Andric }
2842fe6060f1SDimitry Andric 
28435f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
28445f757f3fSDimitry Andric int __dfsw_sscanf(char *str, const char *format, dfsan_label str_label,
28455f757f3fSDimitry Andric                   dfsan_label format_label, dfsan_label *va_labels,
28465f757f3fSDimitry Andric                   dfsan_label *ret_label, ...) {
28475f757f3fSDimitry Andric   va_list ap;
28485f757f3fSDimitry Andric   va_start(ap, ret_label);
28495f757f3fSDimitry Andric   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
28505f757f3fSDimitry Andric                         nullptr, ap);
28515f757f3fSDimitry Andric   va_end(ap);
28525f757f3fSDimitry Andric   return ret;
28535f757f3fSDimitry Andric }
28545f757f3fSDimitry Andric 
28555f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
28565f757f3fSDimitry Andric int __dfso_sscanf(char *str, const char *format, dfsan_label str_label,
28575f757f3fSDimitry Andric                   dfsan_label format_label, dfsan_label *va_labels,
28585f757f3fSDimitry Andric                   dfsan_label *ret_label, dfsan_origin str_origin,
28595f757f3fSDimitry Andric                   dfsan_origin format_origin, dfsan_origin *va_origins,
28605f757f3fSDimitry Andric                   dfsan_origin *ret_origin, ...) {
28615f757f3fSDimitry Andric   va_list ap;
28625f757f3fSDimitry Andric   va_start(ap, ret_origin);
28635f757f3fSDimitry Andric   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, &str_origin,
28645f757f3fSDimitry Andric                         ret_origin, ap);
28655f757f3fSDimitry Andric   va_end(ap);
28665f757f3fSDimitry Andric   return ret;
28675f757f3fSDimitry Andric }
28685f757f3fSDimitry Andric 
28695f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
28705f757f3fSDimitry Andric int __dfsw___isoc99_sscanf(char *str, const char *format, dfsan_label str_label,
28715f757f3fSDimitry Andric                            dfsan_label format_label, dfsan_label *va_labels,
28725f757f3fSDimitry Andric                            dfsan_label *ret_label, ...) {
28735f757f3fSDimitry Andric   va_list ap;
28745f757f3fSDimitry Andric   va_start(ap, ret_label);
28755f757f3fSDimitry Andric   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
28765f757f3fSDimitry Andric                         nullptr, ap);
28775f757f3fSDimitry Andric   va_end(ap);
28785f757f3fSDimitry Andric   return ret;
28795f757f3fSDimitry Andric }
28805f757f3fSDimitry Andric 
28815f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
28825f757f3fSDimitry Andric int __dfso___isoc99_sscanf(char *str, const char *format, dfsan_label str_label,
28835f757f3fSDimitry Andric                            dfsan_label format_label, dfsan_label *va_labels,
28845f757f3fSDimitry Andric                            dfsan_label *ret_label, dfsan_origin str_origin,
28855f757f3fSDimitry Andric                            dfsan_origin format_origin, dfsan_origin *va_origins,
28865f757f3fSDimitry Andric                            dfsan_origin *ret_origin, ...) {
28875f757f3fSDimitry Andric   va_list ap;
28885f757f3fSDimitry Andric   va_start(ap, ret_origin);
28895f757f3fSDimitry Andric   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, &str_origin,
28905f757f3fSDimitry Andric                         ret_origin, ap);
28915f757f3fSDimitry Andric   va_end(ap);
28925f757f3fSDimitry Andric   return ret;
28935f757f3fSDimitry Andric }
28945f757f3fSDimitry Andric 
2895fe6060f1SDimitry Andric static void BeforeFork() {
2896*cb14a3feSDimitry Andric   StackDepotLockBeforeFork();
2897*cb14a3feSDimitry Andric   ChainedOriginDepotLockBeforeFork();
2898fe6060f1SDimitry Andric }
2899fe6060f1SDimitry Andric 
2900*cb14a3feSDimitry Andric static void AfterFork(bool fork_child) {
2901*cb14a3feSDimitry Andric   ChainedOriginDepotUnlockAfterFork(fork_child);
2902*cb14a3feSDimitry Andric   StackDepotUnlockAfterFork(fork_child);
2903fe6060f1SDimitry Andric }
2904fe6060f1SDimitry Andric 
2905fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2906fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) {
2907fe6060f1SDimitry Andric   pid_t pid = fork();
2908fe6060f1SDimitry Andric   *ret_label = 0;
2909fe6060f1SDimitry Andric   return pid;
2910fe6060f1SDimitry Andric }
2911fe6060f1SDimitry Andric 
2912fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2913fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
2914fe6060f1SDimitry Andric   BeforeFork();
2915fe6060f1SDimitry Andric   pid_t pid = __dfsw_fork(ret_label);
2916*cb14a3feSDimitry Andric   AfterFork(/* fork_child= */ pid == 0);
2917fe6060f1SDimitry Andric   return pid;
2918fe6060f1SDimitry Andric }
2919fe6060f1SDimitry Andric 
292068d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
292168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
292268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
292368d75effSDimitry Andric                              u32 *) {}
2924349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
2925349cc55cSDimitry Andric                              const uptr *end) {}
292668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
292768d75effSDimitry Andric 
292868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
292968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
293068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
293168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
293268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
293368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
293468d75effSDimitry Andric                              void) {}
293568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
293668d75effSDimitry Andric                              void) {}
293768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
293868d75effSDimitry Andric                              void) {}
293968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
294068d75effSDimitry Andric                              void) {}
294168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
294268d75effSDimitry Andric }  // extern "C"
2943