xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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 
207*06c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strsep(char **s, const char *delim,
208*06c3fb27SDimitry Andric                                                   dfsan_label s_label,
209*06c3fb27SDimitry Andric                                                   dfsan_label delim_label,
210*06c3fb27SDimitry Andric                                                   dfsan_label *ret_label) {
211*06c3fb27SDimitry Andric   dfsan_label base_label = dfsan_read_label(s, sizeof(*s));
212*06c3fb27SDimitry Andric   char *base = *s;
213*06c3fb27SDimitry Andric   char *res = strsep(s, delim);
214*06c3fb27SDimitry Andric   if (res != *s) {
215*06c3fb27SDimitry Andric     char *token_start = res;
216*06c3fb27SDimitry Andric     int token_length = strlen(res);
217*06c3fb27SDimitry Andric     // the delimiter byte has been set to NULL
218*06c3fb27SDimitry Andric     dfsan_set_label(0, token_start + token_length, 1);
219*06c3fb27SDimitry Andric   }
220*06c3fb27SDimitry Andric 
221*06c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
222*06c3fb27SDimitry Andric     *ret_label = res ? base_label : 0;
223*06c3fb27SDimitry Andric   } else {
224*06c3fb27SDimitry Andric     size_t s_bytes_read = (res ? strlen(res) : strlen(base)) + 1;
225*06c3fb27SDimitry Andric     *ret_label = dfsan_union(
226*06c3fb27SDimitry Andric         dfsan_union(base_label, dfsan_read_label(base, sizeof(s_bytes_read))),
227*06c3fb27SDimitry Andric         dfsan_union(dfsan_read_label(delim, strlen(delim) + 1),
228*06c3fb27SDimitry Andric                     dfsan_union(s_label, delim_label)));
229*06c3fb27SDimitry Andric   }
230*06c3fb27SDimitry Andric 
231*06c3fb27SDimitry Andric   return res;
232*06c3fb27SDimitry Andric }
233*06c3fb27SDimitry Andric 
234*06c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strsep(
235*06c3fb27SDimitry Andric     char **s, const char *delim, dfsan_label s_label, dfsan_label delim_label,
236*06c3fb27SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin delim_origin,
237*06c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
238*06c3fb27SDimitry Andric   dfsan_origin base_origin = dfsan_read_origin_of_first_taint(s, sizeof(*s));
239*06c3fb27SDimitry Andric   char *res = __dfsw_strsep(s, delim, s_label, delim_label, ret_label);
240*06c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
241*06c3fb27SDimitry Andric     if (res)
242*06c3fb27SDimitry Andric       *ret_origin = base_origin;
243*06c3fb27SDimitry Andric   } else {
244*06c3fb27SDimitry Andric     if (*ret_label) {
245*06c3fb27SDimitry Andric       if (base_origin) {
246*06c3fb27SDimitry Andric         *ret_origin = base_origin;
247*06c3fb27SDimitry Andric       } else {
248*06c3fb27SDimitry Andric         dfsan_origin o =
249*06c3fb27SDimitry Andric             dfsan_read_origin_of_first_taint(delim, strlen(delim) + 1);
250*06c3fb27SDimitry Andric         *ret_origin = o ? o : (s_label ? s_origin : delim_origin);
251*06c3fb27SDimitry Andric       }
252*06c3fb27SDimitry Andric     }
253*06c3fb27SDimitry Andric   }
254*06c3fb27SDimitry Andric 
255*06c3fb27SDimitry Andric   return res;
256*06c3fb27SDimitry Andric }
257*06c3fb27SDimitry 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 
538*06c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strnlen(const char *s,
539*06c3fb27SDimitry Andric                                                     size_t maxlen,
540*06c3fb27SDimitry Andric                                                     dfsan_label s_label,
541*06c3fb27SDimitry Andric                                                     dfsan_label maxlen_label,
542*06c3fb27SDimitry Andric                                                     dfsan_label *ret_label) {
543*06c3fb27SDimitry Andric   size_t ret = strnlen(s, maxlen);
544*06c3fb27SDimitry Andric   if (flags().strict_data_dependencies) {
545*06c3fb27SDimitry Andric     *ret_label = 0;
546*06c3fb27SDimitry Andric   } else {
547*06c3fb27SDimitry Andric     size_t full_len = strlen(s);
548*06c3fb27SDimitry Andric     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
549*06c3fb27SDimitry Andric     *ret_label = dfsan_union(maxlen_label, dfsan_read_label(s, covered_len));
550*06c3fb27SDimitry Andric   }
551*06c3fb27SDimitry Andric   return ret;
552*06c3fb27SDimitry Andric }
553*06c3fb27SDimitry Andric 
554*06c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strnlen(
555*06c3fb27SDimitry Andric     const char *s, size_t maxlen, dfsan_label s_label, dfsan_label maxlen_label,
556*06c3fb27SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin maxlen_origin,
557*06c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
558*06c3fb27SDimitry Andric   size_t ret = __dfsw_strnlen(s, maxlen, s_label, maxlen_label, ret_label);
559*06c3fb27SDimitry Andric   if (!flags().strict_data_dependencies) {
560*06c3fb27SDimitry Andric     size_t full_len = strlen(s);
561*06c3fb27SDimitry Andric     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
562*06c3fb27SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, covered_len);
563*06c3fb27SDimitry Andric     *ret_origin = o ? o : maxlen_origin;
564*06c3fb27SDimitry Andric   }
565*06c3fb27SDimitry Andric   return ret;
566*06c3fb27SDimitry Andric }
567*06c3fb27SDimitry 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 
685*06c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strncat(
686*06c3fb27SDimitry Andric     char *dest, const char *src, size_t num, dfsan_label dest_label,
687*06c3fb27SDimitry Andric     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label) {
688*06c3fb27SDimitry Andric   size_t src_len = strlen(src);
689*06c3fb27SDimitry Andric   src_len = src_len < num ? src_len : num;
690*06c3fb27SDimitry Andric   size_t dest_len = strlen(dest);
691*06c3fb27SDimitry Andric 
692*06c3fb27SDimitry Andric   char *ret = strncat(dest, src, num);
693*06c3fb27SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
694*06c3fb27SDimitry Andric   *ret_label = dest_label;
695*06c3fb27SDimitry Andric   return ret;
696*06c3fb27SDimitry Andric }
697*06c3fb27SDimitry Andric 
698*06c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncat(
699*06c3fb27SDimitry Andric     char *dest, const char *src, size_t num, dfsan_label dest_label,
700*06c3fb27SDimitry Andric     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label,
701*06c3fb27SDimitry Andric     dfsan_origin dest_origin, dfsan_origin src_origin, dfsan_origin num_origin,
702*06c3fb27SDimitry Andric     dfsan_origin *ret_origin) {
703*06c3fb27SDimitry Andric   size_t src_len = strlen(src);
704*06c3fb27SDimitry Andric   src_len = src_len < num ? src_len : num;
705*06c3fb27SDimitry Andric   size_t dest_len = strlen(dest);
706*06c3fb27SDimitry Andric 
707*06c3fb27SDimitry Andric   char *ret = strncat(dest, src, num);
708*06c3fb27SDimitry Andric 
709*06c3fb27SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
710*06c3fb27SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
711*06c3fb27SDimitry Andric   *ret_label = dest_label;
712*06c3fb27SDimitry Andric   *ret_origin = dest_origin;
713*06c3fb27SDimitry Andric   return ret;
714*06c3fb27SDimitry Andric }
715*06c3fb27SDimitry 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_)
224368d75effSDimitry Andric       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
224468d75effSDimitry Andric         width(-1) {}
224568d75effSDimitry Andric 
224668d75effSDimitry Andric   int format() {
224768d75effSDimitry Andric     char *tmp_fmt = build_format_string();
224868d75effSDimitry Andric     int retval =
224968d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
225068d75effSDimitry Andric                  0 /* used only to avoid warnings */);
225168d75effSDimitry Andric     free(tmp_fmt);
225268d75effSDimitry Andric     return retval;
225368d75effSDimitry Andric   }
225468d75effSDimitry Andric 
225568d75effSDimitry Andric   template <typename T> int format(T arg) {
225668d75effSDimitry Andric     char *tmp_fmt = build_format_string();
225768d75effSDimitry Andric     int retval;
225868d75effSDimitry Andric     if (width >= 0) {
225968d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
226068d75effSDimitry Andric                         tmp_fmt, width, arg);
226168d75effSDimitry Andric     } else {
226268d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
226368d75effSDimitry Andric                         tmp_fmt, arg);
226468d75effSDimitry Andric     }
226568d75effSDimitry Andric     free(tmp_fmt);
226668d75effSDimitry Andric     return retval;
226768d75effSDimitry Andric   }
226868d75effSDimitry Andric 
226968d75effSDimitry Andric   char *build_format_string() {
227068d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
227168d75effSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1);
227268d75effSDimitry Andric     assert(new_fmt);
227368d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
227468d75effSDimitry Andric     new_fmt[fmt_size] = '\0';
227568d75effSDimitry Andric     return new_fmt;
227668d75effSDimitry Andric   }
227768d75effSDimitry Andric 
227868d75effSDimitry Andric   char *str_cur() { return str + str_off; }
227968d75effSDimitry Andric 
228068d75effSDimitry Andric   size_t num_written_bytes(int retval) {
228168d75effSDimitry Andric     if (retval < 0) {
228268d75effSDimitry Andric       return 0;
228368d75effSDimitry Andric     }
228468d75effSDimitry Andric 
228568d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
228668d75effSDimitry Andric     if (num_avail == 0) {
228768d75effSDimitry Andric       return 0;
228868d75effSDimitry Andric     }
228968d75effSDimitry Andric 
229068d75effSDimitry Andric     size_t num_written = retval;
229168d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
229268d75effSDimitry Andric     // truncated.
229368d75effSDimitry Andric     if (num_written >= num_avail) {
229468d75effSDimitry Andric       num_written -= num_avail;
229568d75effSDimitry Andric     }
229668d75effSDimitry Andric 
229768d75effSDimitry Andric     return num_written;
229868d75effSDimitry Andric   }
229968d75effSDimitry Andric 
230068d75effSDimitry Andric   char *str;
230168d75effSDimitry Andric   size_t str_off;
230268d75effSDimitry Andric   size_t size;
230368d75effSDimitry Andric   const char *fmt_start;
230468d75effSDimitry Andric   const char *fmt_cur;
230568d75effSDimitry Andric   int width;
230668d75effSDimitry Andric };
230768d75effSDimitry Andric 
230868d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
230968d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
231068d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
231168d75effSDimitry Andric // the return value vsnprintf would return.
231268d75effSDimitry Andric //
231368d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
231468d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
231568d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
231668d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
231768d75effSDimitry Andric // propagate labels more precisely.
231868d75effSDimitry Andric //
231968d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
232068d75effSDimitry Andric // positional arguments.
232168d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
232268d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
2323fe6060f1SDimitry Andric                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
232468d75effSDimitry Andric                          va_list ap) {
232568d75effSDimitry Andric   Formatter formatter(str, fmt, size);
232668d75effSDimitry Andric 
232768d75effSDimitry Andric   while (*formatter.fmt_cur) {
232868d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
232968d75effSDimitry Andric     formatter.width = -1;
233068d75effSDimitry Andric     int retval = 0;
233168d75effSDimitry Andric 
233268d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
233368d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
233468d75effSDimitry Andric       // of the string.
233568d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
233668d75effSDimitry Andric            ++formatter.fmt_cur) {}
233768d75effSDimitry Andric       retval = formatter.format();
233868d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
233968d75effSDimitry Andric                       formatter.num_written_bytes(retval));
234068d75effSDimitry Andric     } else {
234168d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
234268d75effSDimitry Andric       // specifier or the end of the string.
234368d75effSDimitry Andric       bool end_fmt = false;
234468d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
234568d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
234668d75effSDimitry Andric         case 'd':
234768d75effSDimitry Andric         case 'i':
234868d75effSDimitry Andric         case 'o':
234968d75effSDimitry Andric         case 'u':
235068d75effSDimitry Andric         case 'x':
235168d75effSDimitry Andric         case 'X':
235268d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
235368d75effSDimitry Andric           case 'h':
235468d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
235568d75effSDimitry Andric             // an int).
235668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
235768d75effSDimitry Andric             break;
235868d75effSDimitry Andric           case 'l':
235968d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
236068d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
236168d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
236268d75effSDimitry Andric             } else {
236368d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
236468d75effSDimitry Andric             }
236568d75effSDimitry Andric             break;
236668d75effSDimitry Andric           case 'q':
236768d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
236868d75effSDimitry Andric             break;
236968d75effSDimitry Andric           case 'j':
237068d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
237168d75effSDimitry Andric             break;
237268d75effSDimitry Andric           case 'z':
237368d75effSDimitry Andric           case 't':
237468d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
237568d75effSDimitry Andric             break;
237668d75effSDimitry Andric           default:
237768d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
237868d75effSDimitry Andric           }
2379fe6060f1SDimitry Andric           if (va_origins == nullptr)
238068d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
238168d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2382fe6060f1SDimitry Andric           else
2383fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2384fe6060f1SDimitry Andric                                    formatter.str_cur(),
2385fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
238668d75effSDimitry Andric           end_fmt = true;
238768d75effSDimitry Andric           break;
238868d75effSDimitry Andric 
238968d75effSDimitry Andric         case 'a':
239068d75effSDimitry Andric         case 'A':
239168d75effSDimitry Andric         case 'e':
239268d75effSDimitry Andric         case 'E':
239368d75effSDimitry Andric         case 'f':
239468d75effSDimitry Andric         case 'F':
239568d75effSDimitry Andric         case 'g':
239668d75effSDimitry Andric         case 'G':
239768d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
239868d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
239968d75effSDimitry Andric           } else {
240068d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
240168d75effSDimitry Andric           }
2402fe6060f1SDimitry Andric           if (va_origins == nullptr)
240368d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
240468d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2405fe6060f1SDimitry Andric           else
2406fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2407fe6060f1SDimitry Andric                                    formatter.str_cur(),
2408fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
240968d75effSDimitry Andric           end_fmt = true;
241068d75effSDimitry Andric           break;
241168d75effSDimitry Andric 
241268d75effSDimitry Andric         case 'c':
241368d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
2414fe6060f1SDimitry Andric           if (va_origins == nullptr)
241568d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
241668d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2417fe6060f1SDimitry Andric           else
2418fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2419fe6060f1SDimitry Andric                                    formatter.str_cur(),
2420fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
242168d75effSDimitry Andric           end_fmt = true;
242268d75effSDimitry Andric           break;
242368d75effSDimitry Andric 
242468d75effSDimitry Andric         case 's': {
242568d75effSDimitry Andric           char *arg = va_arg(ap, char *);
242668d75effSDimitry Andric           retval = formatter.format(arg);
2427fe6060f1SDimitry Andric           if (va_origins) {
2428fe6060f1SDimitry Andric             va_origins++;
2429fe6060f1SDimitry Andric             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
2430fe6060f1SDimitry Andric                                       formatter.num_written_bytes(retval));
2431fe6060f1SDimitry Andric           }
243268d75effSDimitry Andric           va_labels++;
243304eeddc0SDimitry Andric           dfsan_mem_shadow_transfer(formatter.str_cur(), arg,
243468d75effSDimitry Andric                                     formatter.num_written_bytes(retval));
243568d75effSDimitry Andric           end_fmt = true;
243668d75effSDimitry Andric           break;
243768d75effSDimitry Andric         }
243868d75effSDimitry Andric 
243968d75effSDimitry Andric         case 'p':
244068d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
2441fe6060f1SDimitry Andric           if (va_origins == nullptr)
244268d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
244368d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2444fe6060f1SDimitry Andric           else
2445fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2446fe6060f1SDimitry Andric                                    formatter.str_cur(),
2447fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
244868d75effSDimitry Andric           end_fmt = true;
244968d75effSDimitry Andric           break;
245068d75effSDimitry Andric 
245168d75effSDimitry Andric         case 'n': {
245268d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
245368d75effSDimitry Andric           *ptr = (int)formatter.str_off;
245468d75effSDimitry Andric           va_labels++;
2455fe6060f1SDimitry Andric           if (va_origins)
2456fe6060f1SDimitry Andric             va_origins++;
245768d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
245868d75effSDimitry Andric           end_fmt = true;
245968d75effSDimitry Andric           break;
246068d75effSDimitry Andric         }
246168d75effSDimitry Andric 
246268d75effSDimitry Andric         case '%':
246368d75effSDimitry Andric           retval = formatter.format();
246468d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
246568d75effSDimitry Andric                           formatter.num_written_bytes(retval));
246668d75effSDimitry Andric           end_fmt = true;
246768d75effSDimitry Andric           break;
246868d75effSDimitry Andric 
246968d75effSDimitry Andric         case '*':
247068d75effSDimitry Andric           formatter.width = va_arg(ap, int);
247168d75effSDimitry Andric           va_labels++;
2472fe6060f1SDimitry Andric           if (va_origins)
2473fe6060f1SDimitry Andric             va_origins++;
247468d75effSDimitry Andric           break;
247568d75effSDimitry Andric 
247668d75effSDimitry Andric         default:
247768d75effSDimitry Andric           break;
247868d75effSDimitry Andric         }
247968d75effSDimitry Andric       }
248068d75effSDimitry Andric     }
248168d75effSDimitry Andric 
248268d75effSDimitry Andric     if (retval < 0) {
248368d75effSDimitry Andric       return retval;
248468d75effSDimitry Andric     }
248568d75effSDimitry Andric 
248668d75effSDimitry Andric     formatter.fmt_cur++;
248768d75effSDimitry Andric     formatter.str_off += retval;
248868d75effSDimitry Andric   }
248968d75effSDimitry Andric 
249068d75effSDimitry Andric   *ret_label = 0;
2491fe6060f1SDimitry Andric   if (ret_origin)
2492fe6060f1SDimitry Andric     *ret_origin = 0;
249368d75effSDimitry Andric 
249468d75effSDimitry Andric   // Number of bytes written in total.
249568d75effSDimitry Andric   return formatter.str_off;
249668d75effSDimitry Andric }
249768d75effSDimitry Andric 
249868d75effSDimitry Andric extern "C" {
249968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
250068d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
250168d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
250268d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
250368d75effSDimitry Andric   va_list ap;
250468d75effSDimitry Andric   va_start(ap, ret_label);
2505fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
2506fe6060f1SDimitry Andric                           nullptr, ap);
2507fe6060f1SDimitry Andric   va_end(ap);
2508fe6060f1SDimitry Andric   return ret;
2509fe6060f1SDimitry Andric }
2510fe6060f1SDimitry Andric 
2511fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2512fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
2513fe6060f1SDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
2514fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin str_origin,
2515fe6060f1SDimitry Andric                    dfsan_origin format_origin, dfsan_origin *va_origins,
2516fe6060f1SDimitry Andric                    dfsan_origin *ret_origin, ...) {
2517fe6060f1SDimitry Andric   va_list ap;
2518fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2519fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, va_origins,
2520fe6060f1SDimitry Andric                           ret_origin, ap);
252168d75effSDimitry Andric   va_end(ap);
252268d75effSDimitry Andric   return ret;
252368d75effSDimitry Andric }
252468d75effSDimitry Andric 
252568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
252668d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
252768d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
252868d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
252968d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
253068d75effSDimitry Andric   va_list ap;
253168d75effSDimitry Andric   va_start(ap, ret_label);
2532fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
2533fe6060f1SDimitry Andric                           nullptr, ap);
253468d75effSDimitry Andric   va_end(ap);
253568d75effSDimitry Andric   return ret;
253668d75effSDimitry Andric }
253768d75effSDimitry Andric 
2538fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2539fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format,
2540fe6060f1SDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
2541fe6060f1SDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
2542fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin str_origin,
2543fe6060f1SDimitry Andric                     dfsan_origin size_origin, dfsan_origin format_origin,
2544fe6060f1SDimitry Andric                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
2545fe6060f1SDimitry Andric   va_list ap;
2546fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2547fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
2548fe6060f1SDimitry Andric                           ret_origin, ap);
2549fe6060f1SDimitry Andric   va_end(ap);
2550fe6060f1SDimitry Andric   return ret;
2551fe6060f1SDimitry Andric }
2552fe6060f1SDimitry Andric 
2553fe6060f1SDimitry Andric static void BeforeFork() {
2554fe6060f1SDimitry Andric   StackDepotLockAll();
2555fe6060f1SDimitry Andric   GetChainedOriginDepot()->LockAll();
2556fe6060f1SDimitry Andric }
2557fe6060f1SDimitry Andric 
2558fe6060f1SDimitry Andric static void AfterFork() {
2559fe6060f1SDimitry Andric   GetChainedOriginDepot()->UnlockAll();
2560fe6060f1SDimitry Andric   StackDepotUnlockAll();
2561fe6060f1SDimitry Andric }
2562fe6060f1SDimitry Andric 
2563fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2564fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) {
2565fe6060f1SDimitry Andric   pid_t pid = fork();
2566fe6060f1SDimitry Andric   *ret_label = 0;
2567fe6060f1SDimitry Andric   return pid;
2568fe6060f1SDimitry Andric }
2569fe6060f1SDimitry Andric 
2570fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2571fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
2572fe6060f1SDimitry Andric   BeforeFork();
2573fe6060f1SDimitry Andric   pid_t pid = __dfsw_fork(ret_label);
2574fe6060f1SDimitry Andric   AfterFork();
2575fe6060f1SDimitry Andric   return pid;
2576fe6060f1SDimitry Andric }
2577fe6060f1SDimitry Andric 
257868d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
257968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
258068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
258168d75effSDimitry Andric                              u32 *) {}
2582349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
2583349cc55cSDimitry Andric                              const uptr *end) {}
258468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
258568d75effSDimitry Andric 
258668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
258768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
258868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
258968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
259068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
259168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
259268d75effSDimitry Andric                              void) {}
259368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
259468d75effSDimitry Andric                              void) {}
259568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
259668d75effSDimitry Andric                              void) {}
259768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
259868d75effSDimitry Andric                              void) {}
259968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
260068d75effSDimitry Andric }  // extern "C"
2601