xref: /llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 36bd9aebc428413a94f77e8daa679d1937dc2b63)
1ec5ed66cSJianzhou Zhao //===-- dfsan_custom.cpp --------------------------------------------------===//
2a9aa8137SNico Weber //
3a9aa8137SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a9aa8137SNico Weber // See https://llvm.org/LICENSE.txt for license information.
5a9aa8137SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9aa8137SNico Weber //
7a9aa8137SNico Weber //===----------------------------------------------------------------------===//
8a9aa8137SNico Weber //
9a9aa8137SNico Weber // This file is a part of DataFlowSanitizer.
10a9aa8137SNico Weber //
11a9aa8137SNico Weber // This file defines the custom functions listed in done_abilist.txt.
12a9aa8137SNico Weber //===----------------------------------------------------------------------===//
13a9aa8137SNico Weber 
14a9aa8137SNico Weber #include <arpa/inet.h>
15a9aa8137SNico Weber #include <assert.h>
16a9aa8137SNico Weber #include <ctype.h>
17a9aa8137SNico Weber #include <dlfcn.h>
18a9aa8137SNico Weber #include <link.h>
19a9aa8137SNico Weber #include <poll.h>
20a9aa8137SNico Weber #include <pthread.h>
21a9aa8137SNico Weber #include <pwd.h>
22a9aa8137SNico Weber #include <sched.h>
23a9aa8137SNico Weber #include <signal.h>
24a9aa8137SNico Weber #include <stdarg.h>
25a9aa8137SNico Weber #include <stdint.h>
26a9aa8137SNico Weber #include <stdio.h>
27a9aa8137SNico Weber #include <stdlib.h>
28a9aa8137SNico Weber #include <string.h>
296f13445fSMatt Morehouse #include <sys/epoll.h>
30a9aa8137SNico Weber #include <sys/resource.h>
31a9aa8137SNico Weber #include <sys/select.h>
32a3eb2fb2SMatt Morehouse #include <sys/socket.h>
33a9aa8137SNico Weber #include <sys/stat.h>
34a9aa8137SNico Weber #include <sys/time.h>
35a9aa8137SNico Weber #include <sys/types.h>
36a9aa8137SNico Weber #include <time.h>
37a9aa8137SNico Weber #include <unistd.h>
38a9aa8137SNico Weber 
396f13445fSMatt Morehouse #include "dfsan/dfsan.h"
404e67ae7bSJianzhou Zhao #include "dfsan/dfsan_chained_origin_depot.h"
4136cec26bSJianzhou Zhao #include "dfsan/dfsan_flags.h"
420f3fd3b2SJianzhou Zhao #include "dfsan/dfsan_thread.h"
436f13445fSMatt Morehouse #include "sanitizer_common/sanitizer_common.h"
446f13445fSMatt Morehouse #include "sanitizer_common/sanitizer_internal_defs.h"
456f13445fSMatt Morehouse #include "sanitizer_common/sanitizer_linux.h"
464e67ae7bSJianzhou Zhao #include "sanitizer_common/sanitizer_stackdepot.h"
476f13445fSMatt Morehouse 
48a9aa8137SNico Weber using namespace __dfsan;
49a9aa8137SNico Weber 
50a9aa8137SNico Weber #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)                                     \
51a9aa8137SNico Weber   do {                                                                         \
52a9aa8137SNico Weber     if (f)                                                                     \
53a9aa8137SNico Weber       f(__VA_ARGS__);                                                          \
54a9aa8137SNico Weber   } while (false)
55a9aa8137SNico Weber #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
56a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
57a9aa8137SNico Weber 
5864856006SFangrui Song #define WRAPPER_ALIAS(fun, real)                                          \
5964856006SFangrui Song   SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_##fun() ALIAS(__dfsw_##real); \
6064856006SFangrui Song   SANITIZER_INTERFACE_ATTRIBUTE void __dfso_##fun() ALIAS(__dfso_##real);
6164856006SFangrui Song 
62e1a4322fSJianzhou Zhao // Async-safe, non-reentrant spin lock.
6380eea015SFangrui Song namespace {
64e1a4322fSJianzhou Zhao class SignalSpinLocker {
65e1a4322fSJianzhou Zhao  public:
66e1a4322fSJianzhou Zhao   SignalSpinLocker() {
67e1a4322fSJianzhou Zhao     sigset_t all_set;
68e1a4322fSJianzhou Zhao     sigfillset(&all_set);
69e1a4322fSJianzhou Zhao     pthread_sigmask(SIG_SETMASK, &all_set, &saved_thread_mask_);
70e1a4322fSJianzhou Zhao     sigactions_mu.Lock();
71e1a4322fSJianzhou Zhao   }
72e1a4322fSJianzhou Zhao   ~SignalSpinLocker() {
73e1a4322fSJianzhou Zhao     sigactions_mu.Unlock();
74e1a4322fSJianzhou Zhao     pthread_sigmask(SIG_SETMASK, &saved_thread_mask_, nullptr);
75e1a4322fSJianzhou Zhao   }
76e1a4322fSJianzhou Zhao 
77e1a4322fSJianzhou Zhao  private:
78e1a4322fSJianzhou Zhao   static StaticSpinMutex sigactions_mu;
79e1a4322fSJianzhou Zhao   sigset_t saved_thread_mask_;
80e1a4322fSJianzhou Zhao 
81e1a4322fSJianzhou Zhao   SignalSpinLocker(const SignalSpinLocker &) = delete;
82e1a4322fSJianzhou Zhao   SignalSpinLocker &operator=(const SignalSpinLocker &) = delete;
83e1a4322fSJianzhou Zhao };
8480eea015SFangrui Song }  // namespace
85e1a4322fSJianzhou Zhao 
86e1a4322fSJianzhou Zhao StaticSpinMutex SignalSpinLocker::sigactions_mu;
87e1a4322fSJianzhou Zhao 
88a9aa8137SNico Weber extern "C" {
89a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int
90a9aa8137SNico Weber __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
91a9aa8137SNico Weber             dfsan_label buf_label, dfsan_label *ret_label) {
92a9aa8137SNico Weber   int ret = stat(path, buf);
93a9aa8137SNico Weber   if (ret == 0)
94a9aa8137SNico Weber     dfsan_set_label(0, buf, sizeof(struct stat));
95a9aa8137SNico Weber   *ret_label = 0;
96a9aa8137SNico Weber   return ret;
97a9aa8137SNico Weber }
98a9aa8137SNico Weber 
99ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_stat(
100ec5ed66cSJianzhou Zhao     const char *path, struct stat *buf, dfsan_label path_label,
101ec5ed66cSJianzhou Zhao     dfsan_label buf_label, dfsan_label *ret_label, dfsan_origin path_origin,
102ec5ed66cSJianzhou Zhao     dfsan_origin buf_origin, dfsan_origin *ret_origin) {
103ec5ed66cSJianzhou Zhao   int ret = __dfsw_stat(path, buf, path_label, buf_label, ret_label);
104ec5ed66cSJianzhou Zhao   return ret;
105ec5ed66cSJianzhou Zhao }
106ec5ed66cSJianzhou Zhao 
107a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
108a9aa8137SNico Weber                                                dfsan_label fd_label,
109a9aa8137SNico Weber                                                dfsan_label buf_label,
110a9aa8137SNico Weber                                                dfsan_label *ret_label) {
111a9aa8137SNico Weber   int ret = fstat(fd, buf);
112a9aa8137SNico Weber   if (ret == 0)
113a9aa8137SNico Weber     dfsan_set_label(0, buf, sizeof(struct stat));
114a9aa8137SNico Weber   *ret_label = 0;
115a9aa8137SNico Weber   return ret;
116a9aa8137SNico Weber }
117a9aa8137SNico Weber 
118ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_fstat(
119ec5ed66cSJianzhou Zhao     int fd, struct stat *buf, dfsan_label fd_label, dfsan_label buf_label,
120ec5ed66cSJianzhou Zhao     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
121ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
122ec5ed66cSJianzhou Zhao   int ret = __dfsw_fstat(fd, buf, fd_label, buf_label, ret_label);
123ec5ed66cSJianzhou Zhao   return ret;
124ec5ed66cSJianzhou Zhao }
125ec5ed66cSJianzhou Zhao 
126ec5ed66cSJianzhou Zhao static char *dfsan_strchr_with_label(const char *s, int c, size_t *bytes_read,
127ec5ed66cSJianzhou Zhao                                      dfsan_label s_label, dfsan_label c_label,
128ec5ed66cSJianzhou Zhao                                      dfsan_label *ret_label) {
129ec5ed66cSJianzhou Zhao   char *match_pos = nullptr;
130ec5ed66cSJianzhou Zhao   for (size_t i = 0;; ++i) {
131ec5ed66cSJianzhou Zhao     if (s[i] == c || s[i] == 0) {
132ec5ed66cSJianzhou Zhao       // If s[i] is the \0 at the end of the string, and \0 is not the
133ec5ed66cSJianzhou Zhao       // character we are searching for, then return null.
134ec5ed66cSJianzhou Zhao       *bytes_read = i + 1;
135ec5ed66cSJianzhou Zhao       match_pos = s[i] == 0 && c != 0 ? nullptr : const_cast<char *>(s + i);
136ec5ed66cSJianzhou Zhao       break;
137ec5ed66cSJianzhou Zhao     }
138ec5ed66cSJianzhou Zhao   }
139ec5ed66cSJianzhou Zhao   if (flags().strict_data_dependencies)
140ec5ed66cSJianzhou Zhao     *ret_label = s_label;
141ec5ed66cSJianzhou Zhao   else
142ec5ed66cSJianzhou Zhao     *ret_label = dfsan_union(dfsan_read_label(s, *bytes_read),
143ec5ed66cSJianzhou Zhao                              dfsan_union(s_label, c_label));
144ec5ed66cSJianzhou Zhao   return match_pos;
145ec5ed66cSJianzhou Zhao }
146ec5ed66cSJianzhou Zhao 
147a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
148a9aa8137SNico Weber                                                   dfsan_label s_label,
149a9aa8137SNico Weber                                                   dfsan_label c_label,
150a9aa8137SNico Weber                                                   dfsan_label *ret_label) {
151ec5ed66cSJianzhou Zhao   size_t bytes_read;
152ec5ed66cSJianzhou Zhao   return dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label,
153ec5ed66cSJianzhou Zhao                                  ret_label);
154a9aa8137SNico Weber }
15510070e31SSam Kerner 
156ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strchr(
157ec5ed66cSJianzhou Zhao     const char *s, int c, dfsan_label s_label, dfsan_label c_label,
158ec5ed66cSJianzhou Zhao     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
159ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
160ec5ed66cSJianzhou Zhao   size_t bytes_read;
161ec5ed66cSJianzhou Zhao   char *r =
162ec5ed66cSJianzhou Zhao       dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label, ret_label);
163ec5ed66cSJianzhou Zhao   if (flags().strict_data_dependencies) {
164ec5ed66cSJianzhou Zhao     *ret_origin = s_origin;
165ec5ed66cSJianzhou Zhao   } else if (*ret_label) {
166ec5ed66cSJianzhou Zhao     dfsan_origin o = dfsan_read_origin_of_first_taint(s, bytes_read);
167ec5ed66cSJianzhou Zhao     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
16810070e31SSam Kerner   }
169ec5ed66cSJianzhou Zhao   return r;
170a9aa8137SNico Weber }
171a9aa8137SNico Weber 
17223bab1ebSMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strpbrk(const char *s,
17323bab1ebSMatt Morehouse                                                    const char *accept,
17423bab1ebSMatt Morehouse                                                    dfsan_label s_label,
17523bab1ebSMatt Morehouse                                                    dfsan_label accept_label,
17623bab1ebSMatt Morehouse                                                    dfsan_label *ret_label) {
17723bab1ebSMatt Morehouse   const char *ret = strpbrk(s, accept);
17823bab1ebSMatt Morehouse   if (flags().strict_data_dependencies) {
17923bab1ebSMatt Morehouse     *ret_label = ret ? s_label : 0;
18023bab1ebSMatt Morehouse   } else {
18123bab1ebSMatt Morehouse     size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
18223bab1ebSMatt Morehouse     *ret_label =
18323bab1ebSMatt Morehouse         dfsan_union(dfsan_read_label(s, s_bytes_read),
18423bab1ebSMatt Morehouse                     dfsan_union(dfsan_read_label(accept, strlen(accept) + 1),
18523bab1ebSMatt Morehouse                                 dfsan_union(s_label, accept_label)));
18623bab1ebSMatt Morehouse   }
18723bab1ebSMatt Morehouse   return const_cast<char *>(ret);
18823bab1ebSMatt Morehouse }
18923bab1ebSMatt Morehouse 
190ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strpbrk(
191ec5ed66cSJianzhou Zhao     const char *s, const char *accept, dfsan_label s_label,
192ec5ed66cSJianzhou Zhao     dfsan_label accept_label, dfsan_label *ret_label, dfsan_origin s_origin,
193ec5ed66cSJianzhou Zhao     dfsan_origin accept_origin, dfsan_origin *ret_origin) {
194ec5ed66cSJianzhou Zhao   const char *ret = __dfsw_strpbrk(s, accept, s_label, accept_label, ret_label);
195ec5ed66cSJianzhou Zhao   if (flags().strict_data_dependencies) {
196ec5ed66cSJianzhou Zhao     if (ret)
197ec5ed66cSJianzhou Zhao       *ret_origin = s_origin;
198ec5ed66cSJianzhou Zhao   } else {
199ec5ed66cSJianzhou Zhao     if (*ret_label) {
200ec5ed66cSJianzhou Zhao       size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
201ec5ed66cSJianzhou Zhao       dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_bytes_read);
202ec5ed66cSJianzhou Zhao       if (o) {
203ec5ed66cSJianzhou Zhao         *ret_origin = o;
204ec5ed66cSJianzhou Zhao       } else {
205ec5ed66cSJianzhou Zhao         o = dfsan_read_origin_of_first_taint(accept, strlen(accept) + 1);
206ec5ed66cSJianzhou Zhao         *ret_origin = o ? o : (s_label ? s_origin : accept_origin);
207ec5ed66cSJianzhou Zhao       }
208ec5ed66cSJianzhou Zhao     }
209ec5ed66cSJianzhou Zhao   }
210ec5ed66cSJianzhou Zhao   return const_cast<char *>(ret);
211ec5ed66cSJianzhou Zhao }
212ec5ed66cSJianzhou Zhao 
21374f00516STomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strsep(char **s, const char *delim,
21474f00516STomasz Kuchta                                                   dfsan_label s_label,
21574f00516STomasz Kuchta                                                   dfsan_label delim_label,
21674f00516STomasz Kuchta                                                   dfsan_label *ret_label) {
21774f00516STomasz Kuchta   dfsan_label base_label = dfsan_read_label(s, sizeof(*s));
21874f00516STomasz Kuchta   char *base = *s;
21974f00516STomasz Kuchta   char *res = strsep(s, delim);
22074f00516STomasz Kuchta   if (res != *s) {
22174f00516STomasz Kuchta     char *token_start = res;
22274f00516STomasz Kuchta     int token_length = strlen(res);
22374f00516STomasz Kuchta     // the delimiter byte has been set to NULL
22474f00516STomasz Kuchta     dfsan_set_label(0, token_start + token_length, 1);
22574f00516STomasz Kuchta   }
22674f00516STomasz Kuchta 
22774f00516STomasz Kuchta   if (flags().strict_data_dependencies) {
22874f00516STomasz Kuchta     *ret_label = res ? base_label : 0;
22974f00516STomasz Kuchta   } else {
23074f00516STomasz Kuchta     size_t s_bytes_read = (res ? strlen(res) : strlen(base)) + 1;
23174f00516STomasz Kuchta     *ret_label = dfsan_union(
23274f00516STomasz Kuchta         dfsan_union(base_label, dfsan_read_label(base, sizeof(s_bytes_read))),
23374f00516STomasz Kuchta         dfsan_union(dfsan_read_label(delim, strlen(delim) + 1),
23474f00516STomasz Kuchta                     dfsan_union(s_label, delim_label)));
23574f00516STomasz Kuchta   }
23674f00516STomasz Kuchta 
23774f00516STomasz Kuchta   return res;
23874f00516STomasz Kuchta }
23974f00516STomasz Kuchta 
24074f00516STomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strsep(
24174f00516STomasz Kuchta     char **s, const char *delim, dfsan_label s_label, dfsan_label delim_label,
24274f00516STomasz Kuchta     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin delim_origin,
24374f00516STomasz Kuchta     dfsan_origin *ret_origin) {
24474f00516STomasz Kuchta   dfsan_origin base_origin = dfsan_read_origin_of_first_taint(s, sizeof(*s));
24574f00516STomasz Kuchta   char *res = __dfsw_strsep(s, delim, s_label, delim_label, ret_label);
24674f00516STomasz Kuchta   if (flags().strict_data_dependencies) {
24774f00516STomasz Kuchta     if (res)
24874f00516STomasz Kuchta       *ret_origin = base_origin;
24974f00516STomasz Kuchta   } else {
25074f00516STomasz Kuchta     if (*ret_label) {
25174f00516STomasz Kuchta       if (base_origin) {
25274f00516STomasz Kuchta         *ret_origin = base_origin;
25374f00516STomasz Kuchta       } else {
25474f00516STomasz Kuchta         dfsan_origin o =
25574f00516STomasz Kuchta             dfsan_read_origin_of_first_taint(delim, strlen(delim) + 1);
25674f00516STomasz Kuchta         *ret_origin = o ? o : (s_label ? s_origin : delim_origin);
25774f00516STomasz Kuchta       }
25874f00516STomasz Kuchta     }
25974f00516STomasz Kuchta   }
26074f00516STomasz Kuchta 
26174f00516STomasz Kuchta   return res;
26274f00516STomasz Kuchta }
26374f00516STomasz Kuchta 
26450dd545bSMatt Morehouse static int dfsan_memcmp_bcmp(const void *s1, const void *s2, size_t n,
265ec5ed66cSJianzhou Zhao                              size_t *bytes_read) {
266a9aa8137SNico Weber   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
267a9aa8137SNico Weber   for (size_t i = 0; i != n; ++i) {
268a9aa8137SNico Weber     if (cs1[i] != cs2[i]) {
269ec5ed66cSJianzhou Zhao       *bytes_read = i + 1;
270a9aa8137SNico Weber       return cs1[i] - cs2[i];
271a9aa8137SNico Weber     }
272a9aa8137SNico Weber   }
273ec5ed66cSJianzhou Zhao   *bytes_read = n;
274a9aa8137SNico Weber   return 0;
275a9aa8137SNico Weber }
276a9aa8137SNico Weber 
277ec5ed66cSJianzhou Zhao static dfsan_label dfsan_get_memcmp_label(const void *s1, const void *s2,
278ec5ed66cSJianzhou Zhao                                           size_t pos) {
279ec5ed66cSJianzhou Zhao   if (flags().strict_data_dependencies)
280ec5ed66cSJianzhou Zhao     return 0;
281ec5ed66cSJianzhou Zhao   return dfsan_union(dfsan_read_label(s1, pos), dfsan_read_label(s2, pos));
282ec5ed66cSJianzhou Zhao }
283ec5ed66cSJianzhou Zhao 
284ec5ed66cSJianzhou Zhao static void dfsan_get_memcmp_origin(const void *s1, const void *s2, size_t pos,
285ec5ed66cSJianzhou Zhao                                     dfsan_label *ret_label,
286ec5ed66cSJianzhou Zhao                                     dfsan_origin *ret_origin) {
287ec5ed66cSJianzhou Zhao   *ret_label = dfsan_get_memcmp_label(s1, s2, pos);
288ec5ed66cSJianzhou Zhao   if (*ret_label == 0)
289ec5ed66cSJianzhou Zhao     return;
290ec5ed66cSJianzhou Zhao   dfsan_origin o = dfsan_read_origin_of_first_taint(s1, pos);
291ec5ed66cSJianzhou Zhao   *ret_origin = o ? o : dfsan_read_origin_of_first_taint(s2, pos);
292ec5ed66cSJianzhou Zhao }
293ec5ed66cSJianzhou Zhao 
294ec5ed66cSJianzhou Zhao static int dfsan_memcmp_bcmp_label(const void *s1, const void *s2, size_t n,
295ec5ed66cSJianzhou Zhao                                    dfsan_label *ret_label) {
296ec5ed66cSJianzhou Zhao   size_t bytes_read;
297ec5ed66cSJianzhou Zhao   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
298ec5ed66cSJianzhou Zhao   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
299ec5ed66cSJianzhou Zhao   return r;
300ec5ed66cSJianzhou Zhao }
301ec5ed66cSJianzhou Zhao 
302ec5ed66cSJianzhou Zhao static int dfsan_memcmp_bcmp_origin(const void *s1, const void *s2, size_t n,
303ec5ed66cSJianzhou Zhao                                     dfsan_label *ret_label,
304ec5ed66cSJianzhou Zhao                                     dfsan_origin *ret_origin) {
305ec5ed66cSJianzhou Zhao   size_t bytes_read;
306ec5ed66cSJianzhou Zhao   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
307ec5ed66cSJianzhou Zhao   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
308ec5ed66cSJianzhou Zhao   return r;
309ec5ed66cSJianzhou Zhao }
310ec5ed66cSJianzhou Zhao 
31150dd545bSMatt Morehouse DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
31250dd545bSMatt Morehouse                               const void *s1, const void *s2, size_t n,
31350dd545bSMatt Morehouse                               dfsan_label s1_label, dfsan_label s2_label,
31450dd545bSMatt Morehouse                               dfsan_label n_label)
31550dd545bSMatt Morehouse 
316ec5ed66cSJianzhou Zhao DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, uptr caller_pc,
317ec5ed66cSJianzhou Zhao                               const void *s1, const void *s2, size_t n,
318ec5ed66cSJianzhou Zhao                               dfsan_label s1_label, dfsan_label s2_label,
319ec5ed66cSJianzhou Zhao                               dfsan_label n_label, dfsan_origin s1_origin,
320ec5ed66cSJianzhou Zhao                               dfsan_origin s2_origin, dfsan_origin n_origin)
321ec5ed66cSJianzhou Zhao 
32250dd545bSMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
32350dd545bSMatt Morehouse                                                 size_t n, dfsan_label s1_label,
32450dd545bSMatt Morehouse                                                 dfsan_label s2_label,
32550dd545bSMatt Morehouse                                                 dfsan_label n_label,
32650dd545bSMatt Morehouse                                                 dfsan_label *ret_label) {
32750dd545bSMatt Morehouse   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
32850dd545bSMatt Morehouse                              s1_label, s2_label, n_label);
329ec5ed66cSJianzhou Zhao   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
330ec5ed66cSJianzhou Zhao }
331ec5ed66cSJianzhou Zhao 
332ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_memcmp(
333ec5ed66cSJianzhou Zhao     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
334ec5ed66cSJianzhou Zhao     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
335ec5ed66cSJianzhou Zhao     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
336ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
337ec5ed66cSJianzhou Zhao   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, GET_CALLER_PC(), s1,
338ec5ed66cSJianzhou Zhao                              s2, n, s1_label, s2_label, n_label, s1_origin,
339ec5ed66cSJianzhou Zhao                              s2_origin, n_origin);
340ec5ed66cSJianzhou Zhao   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
34150dd545bSMatt Morehouse }
34250dd545bSMatt Morehouse 
34350dd545bSMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_bcmp(const void *s1, const void *s2,
34450dd545bSMatt Morehouse                                               size_t n, dfsan_label s1_label,
34550dd545bSMatt Morehouse                                               dfsan_label s2_label,
34650dd545bSMatt Morehouse                                               dfsan_label n_label,
34750dd545bSMatt Morehouse                                               dfsan_label *ret_label) {
348ec5ed66cSJianzhou Zhao   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
349ec5ed66cSJianzhou Zhao }
350ec5ed66cSJianzhou Zhao 
351ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_bcmp(
352ec5ed66cSJianzhou Zhao     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
353ec5ed66cSJianzhou Zhao     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
354ec5ed66cSJianzhou Zhao     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
355ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
356ec5ed66cSJianzhou Zhao   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
357ec5ed66cSJianzhou Zhao }
358ec5ed66cSJianzhou Zhao 
359ec5ed66cSJianzhou Zhao // When n == 0, compare strings without byte limit.
360ec5ed66cSJianzhou Zhao // When n > 0, compare the first (at most) n bytes of s1 and s2.
361ec5ed66cSJianzhou Zhao static int dfsan_strncmp(const char *s1, const char *s2, size_t n,
362ec5ed66cSJianzhou Zhao                          size_t *bytes_read) {
363ec5ed66cSJianzhou Zhao   for (size_t i = 0;; ++i) {
364ec5ed66cSJianzhou Zhao     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || (n > 0 && i == n - 1)) {
365ec5ed66cSJianzhou Zhao       *bytes_read = i + 1;
366ec5ed66cSJianzhou Zhao       return s1[i] - s2[i];
367ec5ed66cSJianzhou Zhao     }
368ec5ed66cSJianzhou Zhao   }
36950dd545bSMatt Morehouse }
37050dd545bSMatt Morehouse 
371a9aa8137SNico Weber DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
372a9aa8137SNico Weber                               const char *s1, const char *s2,
373a9aa8137SNico Weber                               dfsan_label s1_label, dfsan_label s2_label)
374a9aa8137SNico Weber 
375ec5ed66cSJianzhou Zhao DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, uptr caller_pc,
376ec5ed66cSJianzhou Zhao                               const char *s1, const char *s2,
377ec5ed66cSJianzhou Zhao                               dfsan_label s1_label, dfsan_label s2_label,
378ec5ed66cSJianzhou Zhao                               dfsan_origin s1_origin, dfsan_origin s2_origin)
379ec5ed66cSJianzhou Zhao 
380a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
381a9aa8137SNico Weber                                                 dfsan_label s1_label,
382a9aa8137SNico Weber                                                 dfsan_label s2_label,
383a9aa8137SNico Weber                                                 dfsan_label *ret_label) {
384a9aa8137SNico Weber   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
385a9aa8137SNico Weber                              s1_label, s2_label);
386ec5ed66cSJianzhou Zhao   size_t bytes_read;
387ec5ed66cSJianzhou Zhao   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
388ec5ed66cSJianzhou Zhao   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
389ec5ed66cSJianzhou Zhao   return r;
390a9aa8137SNico Weber }
391a9aa8137SNico Weber 
392ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcmp(
393ec5ed66cSJianzhou Zhao     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
394ec5ed66cSJianzhou Zhao     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
395ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
396ec5ed66cSJianzhou Zhao   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, GET_CALLER_PC(), s1,
397ec5ed66cSJianzhou Zhao                              s2, s1_label, s2_label, s1_origin, s2_origin);
398ec5ed66cSJianzhou Zhao   size_t bytes_read;
399ec5ed66cSJianzhou Zhao   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
400ec5ed66cSJianzhou Zhao   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
401ec5ed66cSJianzhou Zhao   return r;
402ec5ed66cSJianzhou Zhao }
403ec5ed66cSJianzhou Zhao 
404ec5ed66cSJianzhou Zhao // When n == 0, compare strings without byte limit.
405ec5ed66cSJianzhou Zhao // When n > 0, compare the first (at most) n bytes of s1 and s2.
406ec5ed66cSJianzhou Zhao static int dfsan_strncasecmp(const char *s1, const char *s2, size_t n,
407ec5ed66cSJianzhou Zhao                              size_t *bytes_read) {
408a9aa8137SNico Weber   for (size_t i = 0;; ++i) {
409e5ce95c6SSam Kerner     char s1_lower = tolower(s1[i]);
410e5ce95c6SSam Kerner     char s2_lower = tolower(s2[i]);
411e5ce95c6SSam Kerner 
412ec5ed66cSJianzhou Zhao     if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0 ||
413ec5ed66cSJianzhou Zhao         (n > 0 && i == n - 1)) {
414ec5ed66cSJianzhou Zhao       *bytes_read = i + 1;
415e5ce95c6SSam Kerner       return s1_lower - s2_lower;
416a9aa8137SNico Weber     }
417a9aa8137SNico Weber   }
418ec5ed66cSJianzhou Zhao }
419ec5ed66cSJianzhou Zhao 
420ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcasecmp(const char *s1,
421ec5ed66cSJianzhou Zhao                                                     const char *s2,
422ec5ed66cSJianzhou Zhao                                                     dfsan_label s1_label,
423ec5ed66cSJianzhou Zhao                                                     dfsan_label s2_label,
424ec5ed66cSJianzhou Zhao                                                     dfsan_label *ret_label) {
425ec5ed66cSJianzhou Zhao   size_t bytes_read;
426ec5ed66cSJianzhou Zhao   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
427ec5ed66cSJianzhou Zhao   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
428ec5ed66cSJianzhou Zhao   return r;
429ec5ed66cSJianzhou Zhao }
430ec5ed66cSJianzhou Zhao 
431ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcasecmp(
432ec5ed66cSJianzhou Zhao     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
433ec5ed66cSJianzhou Zhao     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
434ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
435ec5ed66cSJianzhou Zhao   size_t bytes_read;
436ec5ed66cSJianzhou Zhao   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
437ec5ed66cSJianzhou Zhao   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
438ec5ed66cSJianzhou Zhao   return r;
439a9aa8137SNico Weber }
440a9aa8137SNico Weber 
441a9aa8137SNico Weber DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
442a9aa8137SNico Weber                               const char *s1, const char *s2, size_t n,
443a9aa8137SNico Weber                               dfsan_label s1_label, dfsan_label s2_label,
444a9aa8137SNico Weber                               dfsan_label n_label)
445a9aa8137SNico Weber 
446ec5ed66cSJianzhou Zhao DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, uptr caller_pc,
447ec5ed66cSJianzhou Zhao                               const char *s1, const char *s2, size_t n,
448ec5ed66cSJianzhou Zhao                               dfsan_label s1_label, dfsan_label s2_label,
449ec5ed66cSJianzhou Zhao                               dfsan_label n_label, dfsan_origin s1_origin,
450ec5ed66cSJianzhou Zhao                               dfsan_origin s2_origin, dfsan_origin n_origin)
451ec5ed66cSJianzhou Zhao 
452a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
453a9aa8137SNico Weber                                                  size_t n, dfsan_label s1_label,
454a9aa8137SNico Weber                                                  dfsan_label s2_label,
455a9aa8137SNico Weber                                                  dfsan_label n_label,
456a9aa8137SNico Weber                                                  dfsan_label *ret_label) {
457a9aa8137SNico Weber   if (n == 0) {
458a9aa8137SNico Weber     *ret_label = 0;
459a9aa8137SNico Weber     return 0;
460a9aa8137SNico Weber   }
461a9aa8137SNico Weber 
462a9aa8137SNico Weber   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
463a9aa8137SNico Weber                              n, s1_label, s2_label, n_label);
464a9aa8137SNico Weber 
465ec5ed66cSJianzhou Zhao   size_t bytes_read;
466ec5ed66cSJianzhou Zhao   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
467ec5ed66cSJianzhou Zhao   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
468ec5ed66cSJianzhou Zhao   return r;
469a9aa8137SNico Weber }
470a9aa8137SNico Weber 
471ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncmp(
472ec5ed66cSJianzhou Zhao     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
473ec5ed66cSJianzhou Zhao     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
474ec5ed66cSJianzhou Zhao     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
475ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
476a9aa8137SNico Weber   if (n == 0) {
477a9aa8137SNico Weber     *ret_label = 0;
478a9aa8137SNico Weber     return 0;
479a9aa8137SNico Weber   }
480a9aa8137SNico Weber 
481ec5ed66cSJianzhou Zhao   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, GET_CALLER_PC(),
482ec5ed66cSJianzhou Zhao                              s1, s2, n, s1_label, s2_label, n_label, s1_origin,
483ec5ed66cSJianzhou Zhao                              s2_origin, n_origin);
484e5ce95c6SSam Kerner 
485ec5ed66cSJianzhou Zhao   size_t bytes_read;
486ec5ed66cSJianzhou Zhao   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
487ec5ed66cSJianzhou Zhao   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
488ec5ed66cSJianzhou Zhao   return r;
489ec5ed66cSJianzhou Zhao }
490ec5ed66cSJianzhou Zhao 
491ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncasecmp(
492ec5ed66cSJianzhou Zhao     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
493ec5ed66cSJianzhou Zhao     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) {
494ec5ed66cSJianzhou Zhao   if (n == 0) {
495a9aa8137SNico Weber     *ret_label = 0;
496a9aa8137SNico Weber     return 0;
497a9aa8137SNico Weber   }
498a9aa8137SNico Weber 
499ec5ed66cSJianzhou Zhao   size_t bytes_read;
500ec5ed66cSJianzhou Zhao   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
501ec5ed66cSJianzhou Zhao   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
502ec5ed66cSJianzhou Zhao   return r;
503ec5ed66cSJianzhou Zhao }
504ec5ed66cSJianzhou Zhao 
505ec5ed66cSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncasecmp(
506ec5ed66cSJianzhou Zhao     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
507ec5ed66cSJianzhou Zhao     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
508ec5ed66cSJianzhou Zhao     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
509ec5ed66cSJianzhou Zhao     dfsan_origin *ret_origin) {
510ec5ed66cSJianzhou Zhao   if (n == 0) {
511ec5ed66cSJianzhou Zhao     *ret_label = 0;
512ec5ed66cSJianzhou Zhao     return 0;
513ec5ed66cSJianzhou Zhao   }
514ec5ed66cSJianzhou Zhao 
515ec5ed66cSJianzhou Zhao   size_t bytes_read;
516ec5ed66cSJianzhou Zhao   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
517ec5ed66cSJianzhou Zhao   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
518ec5ed66cSJianzhou Zhao   return r;
519ec5ed66cSJianzhou Zhao }
520ec5ed66cSJianzhou Zhao 
5211fe04204SJianzhou Zhao 
522a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE size_t
523a9aa8137SNico Weber __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
524a9aa8137SNico Weber   size_t ret = strlen(s);
525a9aa8137SNico Weber   if (flags().strict_data_dependencies) {
526a9aa8137SNico Weber     *ret_label = 0;
527a9aa8137SNico Weber   } else {
528a9aa8137SNico Weber     *ret_label = dfsan_read_label(s, ret + 1);
529a9aa8137SNico Weber   }
530a9aa8137SNico Weber   return ret;
531a9aa8137SNico Weber }
532a9aa8137SNico Weber 
5334e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s,
5344e67ae7bSJianzhou Zhao                                                    dfsan_label s_label,
5354e67ae7bSJianzhou Zhao                                                    dfsan_label *ret_label,
5364e67ae7bSJianzhou Zhao                                                    dfsan_origin s_origin,
5374e67ae7bSJianzhou Zhao                                                    dfsan_origin *ret_origin) {
5384e67ae7bSJianzhou Zhao   size_t ret = __dfsw_strlen(s, s_label, ret_label);
5394e67ae7bSJianzhou Zhao   if (!flags().strict_data_dependencies)
5404e67ae7bSJianzhou Zhao     *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1);
5414e67ae7bSJianzhou Zhao   return ret;
5424e67ae7bSJianzhou Zhao }
5434e67ae7bSJianzhou Zhao 
5445becf548STomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strnlen(const char *s,
5455becf548STomasz Kuchta                                                     size_t maxlen,
5465becf548STomasz Kuchta                                                     dfsan_label s_label,
5475becf548STomasz Kuchta                                                     dfsan_label maxlen_label,
5485becf548STomasz Kuchta                                                     dfsan_label *ret_label) {
5495becf548STomasz Kuchta   size_t ret = strnlen(s, maxlen);
5505becf548STomasz Kuchta   if (flags().strict_data_dependencies) {
5515becf548STomasz Kuchta     *ret_label = 0;
5525becf548STomasz Kuchta   } else {
5535becf548STomasz Kuchta     size_t full_len = strlen(s);
5545becf548STomasz Kuchta     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
5555becf548STomasz Kuchta     *ret_label = dfsan_union(maxlen_label, dfsan_read_label(s, covered_len));
5565becf548STomasz Kuchta   }
5575becf548STomasz Kuchta   return ret;
5585becf548STomasz Kuchta }
5595becf548STomasz Kuchta 
5605becf548STomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strnlen(
5615becf548STomasz Kuchta     const char *s, size_t maxlen, dfsan_label s_label, dfsan_label maxlen_label,
5625becf548STomasz Kuchta     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin maxlen_origin,
5635becf548STomasz Kuchta     dfsan_origin *ret_origin) {
5645becf548STomasz Kuchta   size_t ret = __dfsw_strnlen(s, maxlen, s_label, maxlen_label, ret_label);
5655becf548STomasz Kuchta   if (!flags().strict_data_dependencies) {
5665becf548STomasz Kuchta     size_t full_len = strlen(s);
5675becf548STomasz Kuchta     size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen;
5685becf548STomasz Kuchta     dfsan_origin o = dfsan_read_origin_of_first_taint(s, covered_len);
5695becf548STomasz Kuchta     *ret_origin = o ? o : maxlen_origin;
5705becf548STomasz Kuchta   }
5715becf548STomasz Kuchta   return ret;
5725becf548STomasz Kuchta }
5735becf548STomasz Kuchta 
5743f568e1fSJianzhou Zhao static void *dfsan_memmove(void *dest, const void *src, size_t n) {
5753f568e1fSJianzhou Zhao   dfsan_label *sdest = shadow_for(dest);
5763f568e1fSJianzhou Zhao   const dfsan_label *ssrc = shadow_for(src);
5773f568e1fSJianzhou Zhao   internal_memmove((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
5783f568e1fSJianzhou Zhao   return internal_memmove(dest, src, n);
5793f568e1fSJianzhou Zhao }
580a9aa8137SNico Weber 
5811fe04204SJianzhou Zhao static void *dfsan_memmove_with_origin(void *dest, const void *src, size_t n) {
5821fe04204SJianzhou Zhao   dfsan_mem_origin_transfer(dest, src, n);
5831fe04204SJianzhou Zhao   return dfsan_memmove(dest, src, n);
5841fe04204SJianzhou Zhao }
5851fe04204SJianzhou Zhao 
586a9aa8137SNico Weber static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
58732167bfeSAndrew Browne   dfsan_mem_shadow_transfer(dest, src, n);
588a9aa8137SNico Weber   return internal_memcpy(dest, src, n);
589a9aa8137SNico Weber }
590a9aa8137SNico Weber 
5911fe04204SJianzhou Zhao static void *dfsan_memcpy_with_origin(void *dest, const void *src, size_t n) {
5921fe04204SJianzhou Zhao   dfsan_mem_origin_transfer(dest, src, n);
5931fe04204SJianzhou Zhao   return dfsan_memcpy(dest, src, n);
5941fe04204SJianzhou Zhao }
5951fe04204SJianzhou Zhao 
596a9aa8137SNico Weber static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
597a9aa8137SNico Weber   internal_memset(s, c, n);
598a9aa8137SNico Weber   dfsan_set_label(c_label, s, n);
599a9aa8137SNico Weber }
600a9aa8137SNico Weber 
6011fe04204SJianzhou Zhao static void dfsan_memset_with_origin(void *s, int c, dfsan_label c_label,
6021fe04204SJianzhou Zhao                                      dfsan_origin c_origin, size_t n) {
6031fe04204SJianzhou Zhao   internal_memset(s, c, n);
6041fe04204SJianzhou Zhao   dfsan_set_label_origin(c_label, c_origin, s, n);
6051fe04204SJianzhou Zhao }
6061fe04204SJianzhou Zhao 
607a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
608a9aa8137SNico Weber void *__dfsw_memcpy(void *dest, const void *src, size_t n,
609a9aa8137SNico Weber                     dfsan_label dest_label, dfsan_label src_label,
610a9aa8137SNico Weber                     dfsan_label n_label, dfsan_label *ret_label) {
611a9aa8137SNico Weber   *ret_label = dest_label;
612a9aa8137SNico Weber   return dfsan_memcpy(dest, src, n);
613a9aa8137SNico Weber }
614a9aa8137SNico Weber 
615a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
6161fe04204SJianzhou Zhao void *__dfso_memcpy(void *dest, const void *src, size_t n,
6171fe04204SJianzhou Zhao                     dfsan_label dest_label, dfsan_label src_label,
6181fe04204SJianzhou Zhao                     dfsan_label n_label, dfsan_label *ret_label,
6191fe04204SJianzhou Zhao                     dfsan_origin dest_origin, dfsan_origin src_origin,
6201fe04204SJianzhou Zhao                     dfsan_origin n_origin, dfsan_origin *ret_origin) {
6211fe04204SJianzhou Zhao   *ret_label = dest_label;
6221fe04204SJianzhou Zhao   *ret_origin = dest_origin;
6231fe04204SJianzhou Zhao   return dfsan_memcpy_with_origin(dest, src, n);
6241fe04204SJianzhou Zhao }
6251fe04204SJianzhou Zhao 
6261fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
6273f568e1fSJianzhou Zhao void *__dfsw_memmove(void *dest, const void *src, size_t n,
6283f568e1fSJianzhou Zhao                      dfsan_label dest_label, dfsan_label src_label,
6293f568e1fSJianzhou Zhao                      dfsan_label n_label, dfsan_label *ret_label) {
6303f568e1fSJianzhou Zhao   *ret_label = dest_label;
6313f568e1fSJianzhou Zhao   return dfsan_memmove(dest, src, n);
6323f568e1fSJianzhou Zhao }
6333f568e1fSJianzhou Zhao 
6343f568e1fSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
6351fe04204SJianzhou Zhao void *__dfso_memmove(void *dest, const void *src, size_t n,
6361fe04204SJianzhou Zhao                      dfsan_label dest_label, dfsan_label src_label,
6371fe04204SJianzhou Zhao                      dfsan_label n_label, dfsan_label *ret_label,
6381fe04204SJianzhou Zhao                      dfsan_origin dest_origin, dfsan_origin src_origin,
6391fe04204SJianzhou Zhao                      dfsan_origin n_origin, dfsan_origin *ret_origin) {
6401fe04204SJianzhou Zhao   *ret_label = dest_label;
6411fe04204SJianzhou Zhao   *ret_origin = dest_origin;
6421fe04204SJianzhou Zhao   return dfsan_memmove_with_origin(dest, src, n);
6431fe04204SJianzhou Zhao }
6441fe04204SJianzhou Zhao 
6451fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
646a9aa8137SNico Weber void *__dfsw_memset(void *s, int c, size_t n,
647a9aa8137SNico Weber                     dfsan_label s_label, dfsan_label c_label,
648a9aa8137SNico Weber                     dfsan_label n_label, dfsan_label *ret_label) {
649a9aa8137SNico Weber   dfsan_memset(s, c, c_label, n);
650a9aa8137SNico Weber   *ret_label = s_label;
651a9aa8137SNico Weber   return s;
652a9aa8137SNico Weber }
653a9aa8137SNico Weber 
6541fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
6551fe04204SJianzhou Zhao void *__dfso_memset(void *s, int c, size_t n, dfsan_label s_label,
6561fe04204SJianzhou Zhao                     dfsan_label c_label, dfsan_label n_label,
6571fe04204SJianzhou Zhao                     dfsan_label *ret_label, dfsan_origin s_origin,
6581fe04204SJianzhou Zhao                     dfsan_origin c_origin, dfsan_origin n_origin,
6591fe04204SJianzhou Zhao                     dfsan_origin *ret_origin) {
6601fe04204SJianzhou Zhao   dfsan_memset_with_origin(s, c, c_label, c_origin, n);
6611fe04204SJianzhou Zhao   *ret_label = s_label;
6621fe04204SJianzhou Zhao   *ret_origin = s_origin;
6631fe04204SJianzhou Zhao   return s;
6641fe04204SJianzhou Zhao }
6651fe04204SJianzhou Zhao 
66615f26c5fSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src,
66715f26c5fSJianzhou Zhao                                                   dfsan_label dest_label,
66815f26c5fSJianzhou Zhao                                                   dfsan_label src_label,
66915f26c5fSJianzhou Zhao                                                   dfsan_label *ret_label) {
67015f26c5fSJianzhou Zhao   size_t dest_len = strlen(dest);
67144c83eccSVitaly Buka   char *ret = strcat(dest, src);
67232167bfeSAndrew Browne   dfsan_mem_shadow_transfer(dest + dest_len, src, strlen(src));
67315f26c5fSJianzhou Zhao   *ret_label = dest_label;
67415f26c5fSJianzhou Zhao   return ret;
67515f26c5fSJianzhou Zhao }
67615f26c5fSJianzhou Zhao 
6771fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat(
6781fe04204SJianzhou Zhao     char *dest, const char *src, dfsan_label dest_label, dfsan_label src_label,
6791fe04204SJianzhou Zhao     dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin,
6801fe04204SJianzhou Zhao     dfsan_origin *ret_origin) {
6811fe04204SJianzhou Zhao   size_t dest_len = strlen(dest);
68244c83eccSVitaly Buka   char *ret = strcat(dest, src);
6831fe04204SJianzhou Zhao   size_t src_len = strlen(src);
6841fe04204SJianzhou Zhao   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
68532167bfeSAndrew Browne   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
6861fe04204SJianzhou Zhao   *ret_label = dest_label;
6871fe04204SJianzhou Zhao   *ret_origin = dest_origin;
6881fe04204SJianzhou Zhao   return ret;
6891fe04204SJianzhou Zhao }
6901fe04204SJianzhou Zhao 
691d9b36911STomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strncat(
692d9b36911STomasz Kuchta     char *dest, const char *src, size_t num, dfsan_label dest_label,
693d9b36911STomasz Kuchta     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label) {
694d9b36911STomasz Kuchta   size_t src_len = strlen(src);
695d9b36911STomasz Kuchta   src_len = src_len < num ? src_len : num;
696d9b36911STomasz Kuchta   size_t dest_len = strlen(dest);
697d9b36911STomasz Kuchta 
698d9b36911STomasz Kuchta   char *ret = strncat(dest, src, num);
699d9b36911STomasz Kuchta   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
700d9b36911STomasz Kuchta   *ret_label = dest_label;
701d9b36911STomasz Kuchta   return ret;
702d9b36911STomasz Kuchta }
703d9b36911STomasz Kuchta 
704d9b36911STomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncat(
705d9b36911STomasz Kuchta     char *dest, const char *src, size_t num, dfsan_label dest_label,
706d9b36911STomasz Kuchta     dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label,
707d9b36911STomasz Kuchta     dfsan_origin dest_origin, dfsan_origin src_origin, dfsan_origin num_origin,
708d9b36911STomasz Kuchta     dfsan_origin *ret_origin) {
709d9b36911STomasz Kuchta   size_t src_len = strlen(src);
710d9b36911STomasz Kuchta   src_len = src_len < num ? src_len : num;
711d9b36911STomasz Kuchta   size_t dest_len = strlen(dest);
712d9b36911STomasz Kuchta 
713d9b36911STomasz Kuchta   char *ret = strncat(dest, src, num);
714d9b36911STomasz Kuchta 
715d9b36911STomasz Kuchta   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
716d9b36911STomasz Kuchta   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
717d9b36911STomasz Kuchta   *ret_label = dest_label;
718d9b36911STomasz Kuchta   *ret_origin = dest_origin;
719d9b36911STomasz Kuchta   return ret;
720d9b36911STomasz Kuchta }
721d9b36911STomasz Kuchta 
722a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE char *
723a9aa8137SNico Weber __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
724a9aa8137SNico Weber   size_t len = strlen(s);
725a9aa8137SNico Weber   void *p = malloc(len+1);
726a9aa8137SNico Weber   dfsan_memcpy(p, s, len+1);
727a9aa8137SNico Weber   *ret_label = 0;
728a9aa8137SNico Weber   return static_cast<char *>(p);
729a9aa8137SNico Weber }
730a9aa8137SNico Weber 
7311fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strdup(const char *s,
7321fe04204SJianzhou Zhao                                                   dfsan_label s_label,
7331fe04204SJianzhou Zhao                                                   dfsan_label *ret_label,
7341fe04204SJianzhou Zhao                                                   dfsan_origin s_origin,
7351fe04204SJianzhou Zhao                                                   dfsan_origin *ret_origin) {
7361fe04204SJianzhou Zhao   size_t len = strlen(s);
7371fe04204SJianzhou Zhao   void *p = malloc(len + 1);
7381fe04204SJianzhou Zhao   dfsan_memcpy_with_origin(p, s, len + 1);
7391fe04204SJianzhou Zhao   *ret_label = 0;
7401fe04204SJianzhou Zhao   return static_cast<char *>(p);
7411fe04204SJianzhou Zhao }
7421fe04204SJianzhou Zhao 
743a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE char *
744a9aa8137SNico Weber __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
745a9aa8137SNico Weber                dfsan_label s2_label, dfsan_label n_label,
746a9aa8137SNico Weber                dfsan_label *ret_label) {
747a9aa8137SNico Weber   size_t len = strlen(s2);
748a9aa8137SNico Weber   if (len < n) {
749a9aa8137SNico Weber     dfsan_memcpy(s1, s2, len+1);
750a9aa8137SNico Weber     dfsan_memset(s1+len+1, 0, 0, n-len-1);
751a9aa8137SNico Weber   } else {
752a9aa8137SNico Weber     dfsan_memcpy(s1, s2, n);
753a9aa8137SNico Weber   }
754a9aa8137SNico Weber 
755a9aa8137SNico Weber   *ret_label = s1_label;
756a9aa8137SNico Weber   return s1;
757a9aa8137SNico Weber }
758a9aa8137SNico Weber 
7591fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncpy(
7601fe04204SJianzhou Zhao     char *s1, const char *s2, size_t n, dfsan_label s1_label,
7611fe04204SJianzhou Zhao     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
7621fe04204SJianzhou Zhao     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
7631fe04204SJianzhou Zhao     dfsan_origin *ret_origin) {
7641fe04204SJianzhou Zhao   size_t len = strlen(s2);
7651fe04204SJianzhou Zhao   if (len < n) {
7661fe04204SJianzhou Zhao     dfsan_memcpy_with_origin(s1, s2, len + 1);
7671fe04204SJianzhou Zhao     dfsan_memset_with_origin(s1 + len + 1, 0, 0, 0, n - len - 1);
7681fe04204SJianzhou Zhao   } else {
7691fe04204SJianzhou Zhao     dfsan_memcpy_with_origin(s1, s2, n);
7701fe04204SJianzhou Zhao   }
7711fe04204SJianzhou Zhao 
7721fe04204SJianzhou Zhao   *ret_label = s1_label;
7731fe04204SJianzhou Zhao   *ret_origin = s1_origin;
7741fe04204SJianzhou Zhao   return s1;
7751fe04204SJianzhou Zhao }
7761fe04204SJianzhou Zhao 
777a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE ssize_t
778a9aa8137SNico Weber __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
779a9aa8137SNico Weber              dfsan_label fd_label, dfsan_label buf_label,
780a9aa8137SNico Weber              dfsan_label count_label, dfsan_label offset_label,
781a9aa8137SNico Weber              dfsan_label *ret_label) {
782a9aa8137SNico Weber   ssize_t ret = pread(fd, buf, count, offset);
783a9aa8137SNico Weber   if (ret > 0)
784a9aa8137SNico Weber     dfsan_set_label(0, buf, ret);
785a9aa8137SNico Weber   *ret_label = 0;
786a9aa8137SNico Weber   return ret;
787a9aa8137SNico Weber }
788a9aa8137SNico Weber 
7891fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_pread(
7901fe04204SJianzhou Zhao     int fd, void *buf, size_t count, off_t offset, dfsan_label fd_label,
7911fe04204SJianzhou Zhao     dfsan_label buf_label, dfsan_label count_label, dfsan_label offset_label,
7921fe04204SJianzhou Zhao     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
7931fe04204SJianzhou Zhao     dfsan_origin count_origin, dfsan_label offset_origin,
7941fe04204SJianzhou Zhao     dfsan_origin *ret_origin) {
7954950695eSJianzhou Zhao   return __dfsw_pread(fd, buf, count, offset, fd_label, buf_label, count_label,
7964950695eSJianzhou Zhao                       offset_label, ret_label);
7971fe04204SJianzhou Zhao }
7981fe04204SJianzhou Zhao 
799a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE ssize_t
800a9aa8137SNico Weber __dfsw_read(int fd, void *buf, size_t count,
801a9aa8137SNico Weber              dfsan_label fd_label, dfsan_label buf_label,
802a9aa8137SNico Weber              dfsan_label count_label,
803a9aa8137SNico Weber              dfsan_label *ret_label) {
804a9aa8137SNico Weber   ssize_t ret = read(fd, buf, count);
805a9aa8137SNico Weber   if (ret > 0)
806a9aa8137SNico Weber     dfsan_set_label(0, buf, ret);
807a9aa8137SNico Weber   *ret_label = 0;
808a9aa8137SNico Weber   return ret;
809a9aa8137SNico Weber }
810a9aa8137SNico Weber 
8111fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_read(
8121fe04204SJianzhou Zhao     int fd, void *buf, size_t count, dfsan_label fd_label,
8131fe04204SJianzhou Zhao     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
8141fe04204SJianzhou Zhao     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
8151fe04204SJianzhou Zhao     dfsan_origin *ret_origin) {
8164950695eSJianzhou Zhao   return __dfsw_read(fd, buf, count, fd_label, buf_label, count_label,
8174950695eSJianzhou Zhao                      ret_label);
8181fe04204SJianzhou Zhao }
8191fe04204SJianzhou Zhao 
820a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
821a9aa8137SNico Weber                                                        struct timespec *tp,
822a9aa8137SNico Weber                                                        dfsan_label clk_id_label,
823a9aa8137SNico Weber                                                        dfsan_label tp_label,
824a9aa8137SNico Weber                                                        dfsan_label *ret_label) {
825a9aa8137SNico Weber   int ret = clock_gettime(clk_id, tp);
826a9aa8137SNico Weber   if (ret == 0)
827a9aa8137SNico Weber     dfsan_set_label(0, tp, sizeof(struct timespec));
828a9aa8137SNico Weber   *ret_label = 0;
829a9aa8137SNico Weber   return ret;
830a9aa8137SNico Weber }
831a9aa8137SNico Weber 
8321fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_clock_gettime(
8331fe04204SJianzhou Zhao     clockid_t clk_id, struct timespec *tp, dfsan_label clk_id_label,
8341fe04204SJianzhou Zhao     dfsan_label tp_label, dfsan_label *ret_label, dfsan_origin clk_id_origin,
8351fe04204SJianzhou Zhao     dfsan_origin tp_origin, dfsan_origin *ret_origin) {
8364950695eSJianzhou Zhao   return __dfsw_clock_gettime(clk_id, tp, clk_id_label, tp_label, ret_label);
8371fe04204SJianzhou Zhao }
8381fe04204SJianzhou Zhao 
8391fe04204SJianzhou Zhao static void dfsan_set_zero_label(const void *ptr, uptr size) {
840a9aa8137SNico Weber   dfsan_set_label(0, const_cast<void *>(ptr), size);
841a9aa8137SNico Weber }
842a9aa8137SNico Weber 
843a9aa8137SNico Weber // dlopen() ultimately calls mmap() down inside the loader, which generally
844a9aa8137SNico Weber // doesn't participate in dynamic symbol resolution.  Therefore we won't
845a9aa8137SNico Weber // intercept its calls to mmap, and we have to hook it here.
846a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE void *
847a9aa8137SNico Weber __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
848a9aa8137SNico Weber               dfsan_label flag_label, dfsan_label *ret_label) {
849a9aa8137SNico Weber   void *handle = dlopen(filename, flag);
850a9aa8137SNico Weber   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
8518434e5d0SFangrui Song   if (filename && map)
8521fe04204SJianzhou Zhao     ForEachMappedRegion(map, dfsan_set_zero_label);
853a9aa8137SNico Weber   *ret_label = 0;
854a9aa8137SNico Weber   return handle;
855a9aa8137SNico Weber }
856a9aa8137SNico Weber 
8571fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen(
8581fe04204SJianzhou Zhao     const char *filename, int flag, dfsan_label filename_label,
8591fe04204SJianzhou Zhao     dfsan_label flag_label, dfsan_label *ret_label,
8601fe04204SJianzhou Zhao     dfsan_origin filename_origin, dfsan_origin flag_origin,
8611fe04204SJianzhou Zhao     dfsan_origin *ret_origin) {
8624950695eSJianzhou Zhao   return __dfsw_dlopen(filename, flag, filename_label, flag_label, ret_label);
8631fe04204SJianzhou Zhao }
8641fe04204SJianzhou Zhao 
8650f3fd3b2SJianzhou Zhao static void *DFsanThreadStartFunc(void *arg) {
8660f3fd3b2SJianzhou Zhao   DFsanThread *t = (DFsanThread *)arg;
8670f3fd3b2SJianzhou Zhao   SetCurrentThread(t);
86863886c21SVitaly Buka   t->Init();
869ffd9c123SVitaly Buka   SetSigProcMask(&t->starting_sigset_, nullptr);
8700f3fd3b2SJianzhou Zhao   return t->ThreadStart();
8710f3fd3b2SJianzhou Zhao }
872a9aa8137SNico Weber 
8730f3fd3b2SJianzhou Zhao static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
8740f3fd3b2SJianzhou Zhao                                 void *start_routine, void *arg,
8754e67ae7bSJianzhou Zhao                                 dfsan_label *ret_label,
8764e67ae7bSJianzhou Zhao                                 bool track_origins = false) {
8770f3fd3b2SJianzhou Zhao   pthread_attr_t myattr;
8780f3fd3b2SJianzhou Zhao   if (!attr) {
8790f3fd3b2SJianzhou Zhao     pthread_attr_init(&myattr);
8800f3fd3b2SJianzhou Zhao     attr = &myattr;
8810f3fd3b2SJianzhou Zhao   }
8820f3fd3b2SJianzhou Zhao 
8830f3fd3b2SJianzhou Zhao   // Ensure that the thread stack is large enough to hold all TLS data.
8840f3fd3b2SJianzhou Zhao   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
8850f3fd3b2SJianzhou Zhao 
8864e67ae7bSJianzhou Zhao   DFsanThread *t =
887dbf8c00bSAndrew Browne       DFsanThread::Create((thread_callback_t)start_routine, arg, track_origins);
888ffd9c123SVitaly Buka   ScopedBlockSignals block(&t->starting_sigset_);
8890f3fd3b2SJianzhou Zhao   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
8900f3fd3b2SJianzhou Zhao 
8910f3fd3b2SJianzhou Zhao   if (attr == &myattr)
8920f3fd3b2SJianzhou Zhao     pthread_attr_destroy(&myattr);
8930f3fd3b2SJianzhou Zhao   *ret_label = 0;
8940f3fd3b2SJianzhou Zhao   return res;
895a9aa8137SNico Weber }
896a9aa8137SNico Weber 
897a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
898dbf8c00bSAndrew Browne     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
899dbf8c00bSAndrew Browne     void *arg, dfsan_label thread_label, dfsan_label attr_label,
900dbf8c00bSAndrew Browne     dfsan_label start_routine_label, dfsan_label arg_label,
901dbf8c00bSAndrew Browne     dfsan_label *ret_label) {
902dbf8c00bSAndrew Browne   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label);
903a9aa8137SNico Weber }
904a9aa8137SNico Weber 
9054e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
906dbf8c00bSAndrew Browne     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
907dbf8c00bSAndrew Browne     void *arg, dfsan_label thread_label, dfsan_label attr_label,
908dbf8c00bSAndrew Browne     dfsan_label start_routine_label, dfsan_label arg_label,
909dbf8c00bSAndrew Browne     dfsan_label *ret_label, dfsan_origin thread_origin,
9104e67ae7bSJianzhou Zhao     dfsan_origin attr_origin, dfsan_origin start_routine_origin,
9114e67ae7bSJianzhou Zhao     dfsan_origin arg_origin, dfsan_origin *ret_origin) {
912dbf8c00bSAndrew Browne   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label,
913dbf8c00bSAndrew Browne                               true);
9144e67ae7bSJianzhou Zhao }
9154e67ae7bSJianzhou Zhao 
91600993164SMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
91700993164SMatt Morehouse                                                       void **retval,
91800993164SMatt Morehouse                                                       dfsan_label thread_label,
91900993164SMatt Morehouse                                                       dfsan_label retval_label,
92000993164SMatt Morehouse                                                       dfsan_label *ret_label) {
92100993164SMatt Morehouse   int ret = pthread_join(thread, retval);
92200993164SMatt Morehouse   if (ret == 0 && retval)
92300993164SMatt Morehouse     dfsan_set_label(0, retval, sizeof(*retval));
92400993164SMatt Morehouse   *ret_label = 0;
92500993164SMatt Morehouse   return ret;
92600993164SMatt Morehouse }
92700993164SMatt Morehouse 
9284e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
9294e67ae7bSJianzhou Zhao     pthread_t thread, void **retval, dfsan_label thread_label,
9304e67ae7bSJianzhou Zhao     dfsan_label retval_label, dfsan_label *ret_label,
9314e67ae7bSJianzhou Zhao     dfsan_origin thread_origin, dfsan_origin retval_origin,
9324e67ae7bSJianzhou Zhao     dfsan_origin *ret_origin) {
9334e67ae7bSJianzhou Zhao   return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
9344e67ae7bSJianzhou Zhao                              ret_label);
9354e67ae7bSJianzhou Zhao }
9364e67ae7bSJianzhou Zhao 
937a9aa8137SNico Weber struct dl_iterate_phdr_info {
938dbf8c00bSAndrew Browne   int (*callback)(struct dl_phdr_info *info, size_t size, void *data);
9391fe04204SJianzhou Zhao   void *data;
9401fe04204SJianzhou Zhao };
9411fe04204SJianzhou Zhao 
942fe31363aSFangrui Song static int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size,
943fe31363aSFangrui Song                               void *data) {
944a9aa8137SNico Weber   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
945a9aa8137SNico Weber   dfsan_set_label(0, *info);
946a9aa8137SNico Weber   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
947a9aa8137SNico Weber                   strlen(info->dlpi_name) + 1);
948a9aa8137SNico Weber   dfsan_set_label(
949a9aa8137SNico Weber       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
950a9aa8137SNico Weber       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
951a9aa8137SNico Weber 
952dbf8c00bSAndrew Browne   dfsan_clear_thread_local_state();
953dbf8c00bSAndrew Browne   return dipi->callback(info, size, dipi->data);
9541fe04204SJianzhou Zhao }
9551fe04204SJianzhou Zhao 
956a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
957dbf8c00bSAndrew Browne     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
958dbf8c00bSAndrew Browne     void *data, dfsan_label callback_label, dfsan_label data_label,
959dbf8c00bSAndrew Browne     dfsan_label *ret_label) {
960dbf8c00bSAndrew Browne   dl_iterate_phdr_info dipi = {callback, data};
961a9aa8137SNico Weber   *ret_label = 0;
962a9aa8137SNico Weber   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
963a9aa8137SNico Weber }
964a9aa8137SNico Weber 
9651fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr(
966dbf8c00bSAndrew Browne     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
967dbf8c00bSAndrew Browne     void *data, dfsan_label callback_label, dfsan_label data_label,
968dbf8c00bSAndrew Browne     dfsan_label *ret_label, dfsan_origin callback_origin,
969dbf8c00bSAndrew Browne     dfsan_origin data_origin, dfsan_origin *ret_origin) {
970dbf8c00bSAndrew Browne   dl_iterate_phdr_info dipi = {callback, data};
9711fe04204SJianzhou Zhao   *ret_label = 0;
972dbf8c00bSAndrew Browne   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
9731fe04204SJianzhou Zhao }
9741fe04204SJianzhou Zhao 
97572fd47b9SMatt Morehouse // This function is only available for glibc 2.27 or newer.  Mark it weak so
97672fd47b9SMatt Morehouse // linking succeeds with older glibcs.
97772fd47b9SMatt Morehouse SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep,
97872fd47b9SMatt Morehouse                                                       size_t *alignp);
97972fd47b9SMatt Morehouse 
98072fd47b9SMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info(
98172fd47b9SMatt Morehouse     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
98272fd47b9SMatt Morehouse     dfsan_label alignp_label) {
98372fd47b9SMatt Morehouse   assert(_dl_get_tls_static_info);
98472fd47b9SMatt Morehouse   _dl_get_tls_static_info(sizep, alignp);
98572fd47b9SMatt Morehouse   dfsan_set_label(0, sizep, sizeof(*sizep));
98672fd47b9SMatt Morehouse   dfsan_set_label(0, alignp, sizeof(*alignp));
98772fd47b9SMatt Morehouse }
98872fd47b9SMatt Morehouse 
9891fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info(
9901fe04204SJianzhou Zhao     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
9911fe04204SJianzhou Zhao     dfsan_label alignp_label, dfsan_origin sizep_origin,
9921fe04204SJianzhou Zhao     dfsan_origin alignp_origin) {
9931fe04204SJianzhou Zhao   __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label);
9941fe04204SJianzhou Zhao }
9951fe04204SJianzhou Zhao 
996a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
997a9aa8137SNico Weber char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
998a9aa8137SNico Weber                      dfsan_label buf_label, dfsan_label *ret_label) {
999a9aa8137SNico Weber   char *ret = ctime_r(timep, buf);
1000a9aa8137SNico Weber   if (ret) {
1001a9aa8137SNico Weber     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
1002a9aa8137SNico Weber                     strlen(buf) + 1);
1003a9aa8137SNico Weber     *ret_label = buf_label;
1004a9aa8137SNico Weber   } else {
1005a9aa8137SNico Weber     *ret_label = 0;
1006a9aa8137SNico Weber   }
1007a9aa8137SNico Weber   return ret;
1008a9aa8137SNico Weber }
1009a9aa8137SNico Weber 
1010a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
10114950695eSJianzhou Zhao char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
10124950695eSJianzhou Zhao                      dfsan_label buf_label, dfsan_label *ret_label,
10134950695eSJianzhou Zhao                      dfsan_origin timep_origin, dfsan_origin buf_origin,
10144950695eSJianzhou Zhao                      dfsan_origin *ret_origin) {
10154950695eSJianzhou Zhao   char *ret = ctime_r(timep, buf);
10164950695eSJianzhou Zhao   if (ret) {
10174950695eSJianzhou Zhao     dfsan_set_label_origin(
10184950695eSJianzhou Zhao         dfsan_read_label(timep, sizeof(time_t)),
10194950695eSJianzhou Zhao         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf,
10204950695eSJianzhou Zhao         strlen(buf) + 1);
10214950695eSJianzhou Zhao     *ret_label = buf_label;
10224950695eSJianzhou Zhao     *ret_origin = buf_origin;
10234950695eSJianzhou Zhao   } else {
10244950695eSJianzhou Zhao     *ret_label = 0;
10254950695eSJianzhou Zhao   }
10264950695eSJianzhou Zhao   return ret;
10274950695eSJianzhou Zhao }
10284950695eSJianzhou Zhao 
10294950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1030a9aa8137SNico Weber char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
1031a9aa8137SNico Weber                    dfsan_label size_label, dfsan_label stream_label,
1032a9aa8137SNico Weber                    dfsan_label *ret_label) {
1033a9aa8137SNico Weber   char *ret = fgets(s, size, stream);
1034a9aa8137SNico Weber   if (ret) {
1035a9aa8137SNico Weber     dfsan_set_label(0, ret, strlen(ret) + 1);
1036a9aa8137SNico Weber     *ret_label = s_label;
1037a9aa8137SNico Weber   } else {
1038a9aa8137SNico Weber     *ret_label = 0;
1039a9aa8137SNico Weber   }
1040a9aa8137SNico Weber   return ret;
1041a9aa8137SNico Weber }
1042a9aa8137SNico Weber 
1043a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
10444950695eSJianzhou Zhao char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
10454950695eSJianzhou Zhao                    dfsan_label size_label, dfsan_label stream_label,
10464950695eSJianzhou Zhao                    dfsan_label *ret_label, dfsan_origin s_origin,
10474950695eSJianzhou Zhao                    dfsan_origin size_origin, dfsan_origin stream_origin,
10484950695eSJianzhou Zhao                    dfsan_origin *ret_origin) {
10494950695eSJianzhou Zhao   char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label,
10504950695eSJianzhou Zhao                            ret_label);
10514950695eSJianzhou Zhao   if (ret)
10524950695eSJianzhou Zhao     *ret_origin = s_origin;
10534950695eSJianzhou Zhao   return ret;
10544950695eSJianzhou Zhao }
10554950695eSJianzhou Zhao 
10564950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1057a9aa8137SNico Weber char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
1058a9aa8137SNico Weber                     dfsan_label size_label, dfsan_label *ret_label) {
1059a9aa8137SNico Weber   char *ret = getcwd(buf, size);
1060a9aa8137SNico Weber   if (ret) {
1061a9aa8137SNico Weber     dfsan_set_label(0, ret, strlen(ret) + 1);
1062a9aa8137SNico Weber     *ret_label = buf_label;
1063a9aa8137SNico Weber   } else {
1064a9aa8137SNico Weber     *ret_label = 0;
1065a9aa8137SNico Weber   }
1066a9aa8137SNico Weber   return ret;
1067a9aa8137SNico Weber }
1068a9aa8137SNico Weber 
1069a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
10704950695eSJianzhou Zhao char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label,
10714950695eSJianzhou Zhao                     dfsan_label size_label, dfsan_label *ret_label,
10724950695eSJianzhou Zhao                     dfsan_origin buf_origin, dfsan_origin size_origin,
10734950695eSJianzhou Zhao                     dfsan_origin *ret_origin) {
10744950695eSJianzhou Zhao   char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label);
10754950695eSJianzhou Zhao   if (ret)
10764950695eSJianzhou Zhao     *ret_origin = buf_origin;
10774950695eSJianzhou Zhao   return ret;
10784950695eSJianzhou Zhao }
10794950695eSJianzhou Zhao 
10804950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1081a9aa8137SNico Weber char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
1082a9aa8137SNico Weber   char *ret = get_current_dir_name();
10834950695eSJianzhou Zhao   if (ret)
1084a9aa8137SNico Weber     dfsan_set_label(0, ret, strlen(ret) + 1);
1085a9aa8137SNico Weber   *ret_label = 0;
1086a9aa8137SNico Weber   return ret;
1087a9aa8137SNico Weber }
1088a9aa8137SNico Weber 
1089a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
10904950695eSJianzhou Zhao char *__dfso_get_current_dir_name(dfsan_label *ret_label,
10914950695eSJianzhou Zhao                                   dfsan_origin *ret_origin) {
10924950695eSJianzhou Zhao   return __dfsw_get_current_dir_name(ret_label);
10934950695eSJianzhou Zhao }
10944950695eSJianzhou Zhao 
109576777b21SAndrew Browne // This function is only available for glibc 2.25 or newer.  Mark it weak so
109676777b21SAndrew Browne // linking succeeds with older glibcs.
109776777b21SAndrew Browne SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length);
109876777b21SAndrew Browne 
109976777b21SAndrew Browne SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length,
110076777b21SAndrew Browne                                                     dfsan_label buffer_label,
110176777b21SAndrew Browne                                                     dfsan_label length_label,
110276777b21SAndrew Browne                                                     dfsan_label *ret_label) {
110376777b21SAndrew Browne   int ret = getentropy(buffer, length);
110476777b21SAndrew Browne   if (ret == 0) {
110576777b21SAndrew Browne     dfsan_set_label(0, buffer, length);
110676777b21SAndrew Browne   }
110776777b21SAndrew Browne   *ret_label = 0;
110876777b21SAndrew Browne   return ret;
110976777b21SAndrew Browne }
111076777b21SAndrew Browne 
111176777b21SAndrew Browne SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length,
111276777b21SAndrew Browne                                                     dfsan_label buffer_label,
111376777b21SAndrew Browne                                                     dfsan_label length_label,
111476777b21SAndrew Browne                                                     dfsan_label *ret_label,
111576777b21SAndrew Browne                                                     dfsan_origin buffer_origin,
111676777b21SAndrew Browne                                                     dfsan_origin length_origin,
111776777b21SAndrew Browne                                                     dfsan_origin *ret_origin) {
111876777b21SAndrew Browne   return __dfsw_getentropy(buffer, length, buffer_label, length_label,
111976777b21SAndrew Browne                            ret_label);
112076777b21SAndrew Browne }
112176777b21SAndrew Browne 
11224950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1123a9aa8137SNico Weber int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
1124a9aa8137SNico Weber                        dfsan_label len_label, dfsan_label *ret_label) {
1125a9aa8137SNico Weber   int ret = gethostname(name, len);
1126a9aa8137SNico Weber   if (ret == 0) {
1127a9aa8137SNico Weber     dfsan_set_label(0, name, strlen(name) + 1);
1128a9aa8137SNico Weber   }
1129a9aa8137SNico Weber   *ret_label = 0;
1130a9aa8137SNico Weber   return ret;
1131a9aa8137SNico Weber }
1132a9aa8137SNico Weber 
1133a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
11344950695eSJianzhou Zhao int __dfso_gethostname(char *name, size_t len, dfsan_label name_label,
11354950695eSJianzhou Zhao                        dfsan_label len_label, dfsan_label *ret_label,
11364950695eSJianzhou Zhao                        dfsan_origin name_origin, dfsan_origin len_origin,
11374950695eSJianzhou Zhao                        dfsan_label *ret_origin) {
11384950695eSJianzhou Zhao   return __dfsw_gethostname(name, len, name_label, len_label, ret_label);
11394950695eSJianzhou Zhao }
11404950695eSJianzhou Zhao 
11414950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1142a9aa8137SNico Weber int __dfsw_getrlimit(int resource, struct rlimit *rlim,
1143a9aa8137SNico Weber                      dfsan_label resource_label, dfsan_label rlim_label,
1144a9aa8137SNico Weber                      dfsan_label *ret_label) {
1145a9aa8137SNico Weber   int ret = getrlimit(resource, rlim);
1146a9aa8137SNico Weber   if (ret == 0) {
1147a9aa8137SNico Weber     dfsan_set_label(0, rlim, sizeof(struct rlimit));
1148a9aa8137SNico Weber   }
1149a9aa8137SNico Weber   *ret_label = 0;
1150a9aa8137SNico Weber   return ret;
1151a9aa8137SNico Weber }
1152a9aa8137SNico Weber 
1153a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
11544950695eSJianzhou Zhao int __dfso_getrlimit(int resource, struct rlimit *rlim,
11554950695eSJianzhou Zhao                      dfsan_label resource_label, dfsan_label rlim_label,
11564950695eSJianzhou Zhao                      dfsan_label *ret_label, dfsan_origin resource_origin,
11574950695eSJianzhou Zhao                      dfsan_origin rlim_origin, dfsan_origin *ret_origin) {
11584950695eSJianzhou Zhao   return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label,
11594950695eSJianzhou Zhao                           ret_label);
11604950695eSJianzhou Zhao }
11614950695eSJianzhou Zhao 
11624950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1163a9aa8137SNico Weber int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
1164a9aa8137SNico Weber                      dfsan_label usage_label, dfsan_label *ret_label) {
1165a9aa8137SNico Weber   int ret = getrusage(who, usage);
1166a9aa8137SNico Weber   if (ret == 0) {
1167a9aa8137SNico Weber     dfsan_set_label(0, usage, sizeof(struct rusage));
1168a9aa8137SNico Weber   }
1169a9aa8137SNico Weber   *ret_label = 0;
1170a9aa8137SNico Weber   return ret;
1171a9aa8137SNico Weber }
1172a9aa8137SNico Weber 
1173a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
11744950695eSJianzhou Zhao int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label,
11754950695eSJianzhou Zhao                      dfsan_label usage_label, dfsan_label *ret_label,
11764950695eSJianzhou Zhao                      dfsan_origin who_origin, dfsan_origin usage_origin,
11774950695eSJianzhou Zhao                      dfsan_label *ret_origin) {
11784950695eSJianzhou Zhao   return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label);
11794950695eSJianzhou Zhao }
11804950695eSJianzhou Zhao 
11814950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1182a9aa8137SNico Weber char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
1183a9aa8137SNico Weber                     dfsan_label src_label, dfsan_label *ret_label) {
118444c83eccSVitaly Buka   char *ret = strcpy(dest, src);
1185a9aa8137SNico Weber   if (ret) {
118632167bfeSAndrew Browne     dfsan_mem_shadow_transfer(dest, src, strlen(src) + 1);
1187a9aa8137SNico Weber   }
1188a9aa8137SNico Weber   *ret_label = dst_label;
1189a9aa8137SNico Weber   return ret;
1190a9aa8137SNico Weber }
1191a9aa8137SNico Weber 
1192a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
119391516925SJianzhou Zhao char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label,
119491516925SJianzhou Zhao                     dfsan_label src_label, dfsan_label *ret_label,
119591516925SJianzhou Zhao                     dfsan_origin dst_origin, dfsan_origin src_origin,
119691516925SJianzhou Zhao                     dfsan_origin *ret_origin) {
119744c83eccSVitaly Buka   char *ret = strcpy(dest, src);
119891516925SJianzhou Zhao   if (ret) {
119991516925SJianzhou Zhao     size_t str_len = strlen(src) + 1;
120091516925SJianzhou Zhao     dfsan_mem_origin_transfer(dest, src, str_len);
120132167bfeSAndrew Browne     dfsan_mem_shadow_transfer(dest, src, str_len);
1202a9aa8137SNico Weber   }
120391516925SJianzhou Zhao   *ret_label = dst_label;
120491516925SJianzhou Zhao   *ret_origin = dst_origin;
120591516925SJianzhou Zhao   return ret;
120691516925SJianzhou Zhao }
120764856006SFangrui Song }
120891516925SJianzhou Zhao 
120964856006SFangrui Song template <typename Fn>
121064856006SFangrui Song static ALWAYS_INLINE auto dfsan_strtol_impl(
121164856006SFangrui Song     Fn real, const char *nptr, char **endptr, int base,
121264856006SFangrui Song     char **tmp_endptr) -> decltype(real(nullptr, nullptr, 0)) {
121391516925SJianzhou Zhao   assert(tmp_endptr);
121464856006SFangrui Song   auto ret = real(nptr, tmp_endptr, base);
121591516925SJianzhou Zhao   if (endptr)
121691516925SJianzhou Zhao     *endptr = *tmp_endptr;
121791516925SJianzhou Zhao   return ret;
121891516925SJianzhou Zhao }
121991516925SJianzhou Zhao 
122064856006SFangrui Song extern "C" {
122191516925SJianzhou Zhao static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr,
122291516925SJianzhou Zhao                                   dfsan_label base_label,
122391516925SJianzhou Zhao                                   dfsan_label *ret_label) {
1224a9aa8137SNico Weber   if (tmp_endptr > nptr) {
1225a9aa8137SNico Weber     // If *tmp_endptr is '\0' include its label as well.
1226a9aa8137SNico Weber     *ret_label = dfsan_union(
1227a9aa8137SNico Weber         base_label,
1228a9aa8137SNico Weber         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
1229a9aa8137SNico Weber   } else {
1230a9aa8137SNico Weber     *ret_label = 0;
1231a9aa8137SNico Weber   }
123291516925SJianzhou Zhao }
123391516925SJianzhou Zhao 
123491516925SJianzhou Zhao static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr,
123591516925SJianzhou Zhao                                    dfsan_label base_label,
123691516925SJianzhou Zhao                                    dfsan_label *ret_label,
123791516925SJianzhou Zhao                                    dfsan_origin base_origin,
123891516925SJianzhou Zhao                                    dfsan_origin *ret_origin) {
123991516925SJianzhou Zhao   if (tmp_endptr > nptr) {
124091516925SJianzhou Zhao     // When multiple inputs are tainted, we propagate one of its origins.
124191516925SJianzhou Zhao     // Because checking if base_label is tainted does not need additional
124291516925SJianzhou Zhao     // computation, we prefer to propagating base_origin.
124391516925SJianzhou Zhao     *ret_origin = base_label
124491516925SJianzhou Zhao                       ? base_origin
124591516925SJianzhou Zhao                       : dfsan_read_origin_of_first_taint(
124691516925SJianzhou Zhao                             nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
124791516925SJianzhou Zhao   }
124891516925SJianzhou Zhao }
124991516925SJianzhou Zhao 
125091516925SJianzhou Zhao static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) {
125191516925SJianzhou Zhao   assert(tmp_endptr);
125291516925SJianzhou Zhao   double ret = strtod(nptr, tmp_endptr);
125391516925SJianzhou Zhao   if (endptr)
125491516925SJianzhou Zhao     *endptr = *tmp_endptr;
125591516925SJianzhou Zhao   return ret;
125691516925SJianzhou Zhao }
125791516925SJianzhou Zhao 
125891516925SJianzhou Zhao static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr,
125991516925SJianzhou Zhao                                dfsan_label *ret_label) {
1260a9aa8137SNico Weber   if (tmp_endptr > nptr) {
1261a9aa8137SNico Weber     // If *tmp_endptr is '\0' include its label as well.
1262a9aa8137SNico Weber     *ret_label = dfsan_read_label(
1263a9aa8137SNico Weber         nptr,
1264a9aa8137SNico Weber         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1265a9aa8137SNico Weber   } else {
1266a9aa8137SNico Weber     *ret_label = 0;
1267a9aa8137SNico Weber   }
126891516925SJianzhou Zhao }
126991516925SJianzhou Zhao 
127091516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
127191516925SJianzhou Zhao double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
127291516925SJianzhou Zhao                      dfsan_label endptr_label, dfsan_label *ret_label) {
127391516925SJianzhou Zhao   char *tmp_endptr;
127491516925SJianzhou Zhao   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
127591516925SJianzhou Zhao   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
127691516925SJianzhou Zhao   return ret;
127791516925SJianzhou Zhao }
127891516925SJianzhou Zhao 
127991516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
128091516925SJianzhou Zhao double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
128191516925SJianzhou Zhao                      dfsan_label endptr_label, dfsan_label *ret_label,
128291516925SJianzhou Zhao                      dfsan_origin nptr_origin, dfsan_origin endptr_origin,
128391516925SJianzhou Zhao                      dfsan_origin *ret_origin) {
128491516925SJianzhou Zhao   char *tmp_endptr;
128591516925SJianzhou Zhao   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
128691516925SJianzhou Zhao   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
128791516925SJianzhou Zhao   if (tmp_endptr > nptr) {
128891516925SJianzhou Zhao     // If *tmp_endptr is '\0' include its label as well.
128991516925SJianzhou Zhao     *ret_origin = dfsan_read_origin_of_first_taint(
129091516925SJianzhou Zhao         nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
129191516925SJianzhou Zhao   } else {
129291516925SJianzhou Zhao     *ret_origin = 0;
129391516925SJianzhou Zhao   }
129491516925SJianzhou Zhao   return ret;
129591516925SJianzhou Zhao }
129691516925SJianzhou Zhao 
129764856006SFangrui Song WRAPPER_ALIAS(__isoc23_strtod, strtod)
129864856006SFangrui Song 
129964856006SFangrui Song #define WRAPPER_STRTO(ret_type, fun)                                     \
130064856006SFangrui Song   SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfsw_##fun(                   \
130164856006SFangrui Song       const char *nptr, char **endptr, int base, dfsan_label nptr_label, \
130264856006SFangrui Song       dfsan_label endptr_label, dfsan_label base_label,                  \
130364856006SFangrui Song       dfsan_label *ret_label) {                                          \
130464856006SFangrui Song     char *tmp_endptr;                                                    \
130564856006SFangrui Song     auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr);  \
130664856006SFangrui Song     dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);      \
130764856006SFangrui Song     return ret;                                                          \
130864856006SFangrui Song   }                                                                      \
130964856006SFangrui Song   SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfso_##fun(                   \
131064856006SFangrui Song       const char *nptr, char **endptr, int base, dfsan_label nptr_label, \
131164856006SFangrui Song       dfsan_label endptr_label, dfsan_label base_label,                  \
131264856006SFangrui Song       dfsan_label *ret_label, dfsan_origin nptr_origin,                  \
131364856006SFangrui Song       dfsan_origin endptr_origin, dfsan_origin base_origin,              \
131464856006SFangrui Song       dfsan_origin *ret_origin) {                                        \
131564856006SFangrui Song     char *tmp_endptr;                                                    \
131664856006SFangrui Song     auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr);  \
131764856006SFangrui Song     dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);      \
131864856006SFangrui Song     dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label,      \
131964856006SFangrui Song                            base_origin, ret_origin);                     \
132064856006SFangrui Song     return ret;                                                          \
1321a9aa8137SNico Weber   }
1322a9aa8137SNico Weber 
132364856006SFangrui Song WRAPPER_STRTO(long, strtol)
132464856006SFangrui Song WRAPPER_STRTO(long long, strtoll)
132564856006SFangrui Song WRAPPER_STRTO(unsigned long, strtoul)
132664856006SFangrui Song WRAPPER_STRTO(unsigned long long, strtoull)
132764856006SFangrui Song WRAPPER_ALIAS(__isoc23_strtol, strtol)
132864856006SFangrui Song WRAPPER_ALIAS(__isoc23_strtoll, strtoll)
132964856006SFangrui Song WRAPPER_ALIAS(__isoc23_strtoul, strtoul)
133064856006SFangrui Song WRAPPER_ALIAS(__isoc23_strtoull, strtoull)
1331a9aa8137SNico Weber 
1332a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
1333a9aa8137SNico Weber time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
1334a9aa8137SNico Weber   time_t ret = time(t);
1335a9aa8137SNico Weber   if (ret != (time_t) -1 && t) {
1336a9aa8137SNico Weber     dfsan_set_label(0, t, sizeof(time_t));
1337a9aa8137SNico Weber   }
1338a9aa8137SNico Weber   *ret_label = 0;
1339a9aa8137SNico Weber   return ret;
1340a9aa8137SNico Weber }
1341a9aa8137SNico Weber 
1342a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
13434950695eSJianzhou Zhao time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label,
13444950695eSJianzhou Zhao                    dfsan_origin t_origin, dfsan_origin *ret_origin) {
13454950695eSJianzhou Zhao   return __dfsw_time(t, t_label, ret_label);
13464950695eSJianzhou Zhao }
13474950695eSJianzhou Zhao 
13484950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1349a9aa8137SNico Weber int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
1350a9aa8137SNico Weber                      dfsan_label src_label, dfsan_label dst_label,
1351a9aa8137SNico Weber                      dfsan_label *ret_label) {
1352a9aa8137SNico Weber   int ret = inet_pton(af, src, dst);
1353a9aa8137SNico Weber   if (ret == 1) {
1354a9aa8137SNico Weber     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
1355a9aa8137SNico Weber                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
1356a9aa8137SNico Weber   }
1357a9aa8137SNico Weber   *ret_label = 0;
1358a9aa8137SNico Weber   return ret;
1359a9aa8137SNico Weber }
1360a9aa8137SNico Weber 
1361a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
13624950695eSJianzhou Zhao int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
13634950695eSJianzhou Zhao                      dfsan_label src_label, dfsan_label dst_label,
13644950695eSJianzhou Zhao                      dfsan_label *ret_label, dfsan_origin af_origin,
13654950695eSJianzhou Zhao                      dfsan_origin src_origin, dfsan_origin dst_origin,
13664950695eSJianzhou Zhao                      dfsan_origin *ret_origin) {
13674950695eSJianzhou Zhao   int ret = inet_pton(af, src, dst);
13684950695eSJianzhou Zhao   if (ret == 1) {
13694950695eSJianzhou Zhao     int src_len = strlen(src) + 1;
13704950695eSJianzhou Zhao     dfsan_set_label_origin(
13714950695eSJianzhou Zhao         dfsan_read_label(src, src_len),
13724950695eSJianzhou Zhao         dfsan_read_origin_of_first_taint(src, src_len), dst,
13734950695eSJianzhou Zhao         af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
13744950695eSJianzhou Zhao   }
13754950695eSJianzhou Zhao   *ret_label = 0;
13764950695eSJianzhou Zhao   return ret;
13774950695eSJianzhou Zhao }
13784950695eSJianzhou Zhao 
13794950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1380a9aa8137SNico Weber struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
1381a9aa8137SNico Weber                               dfsan_label timep_label, dfsan_label result_label,
1382a9aa8137SNico Weber                               dfsan_label *ret_label) {
1383a9aa8137SNico Weber   struct tm *ret = localtime_r(timep, result);
1384a9aa8137SNico Weber   if (ret) {
1385a9aa8137SNico Weber     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
1386a9aa8137SNico Weber                     sizeof(struct tm));
1387a9aa8137SNico Weber     *ret_label = result_label;
1388a9aa8137SNico Weber   } else {
1389a9aa8137SNico Weber     *ret_label = 0;
1390a9aa8137SNico Weber   }
1391a9aa8137SNico Weber   return ret;
1392a9aa8137SNico Weber }
1393a9aa8137SNico Weber 
1394a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
13954950695eSJianzhou Zhao struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result,
13964950695eSJianzhou Zhao                               dfsan_label timep_label, dfsan_label result_label,
13974950695eSJianzhou Zhao                               dfsan_label *ret_label, dfsan_origin timep_origin,
13984950695eSJianzhou Zhao                               dfsan_origin result_origin,
13994950695eSJianzhou Zhao                               dfsan_origin *ret_origin) {
14004950695eSJianzhou Zhao   struct tm *ret = localtime_r(timep, result);
14014950695eSJianzhou Zhao   if (ret) {
14024950695eSJianzhou Zhao     dfsan_set_label_origin(
14034950695eSJianzhou Zhao         dfsan_read_label(timep, sizeof(time_t)),
14044950695eSJianzhou Zhao         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result,
14054950695eSJianzhou Zhao         sizeof(struct tm));
14064950695eSJianzhou Zhao     *ret_label = result_label;
14074950695eSJianzhou Zhao     *ret_origin = result_origin;
14084950695eSJianzhou Zhao   } else {
14094950695eSJianzhou Zhao     *ret_label = 0;
14104950695eSJianzhou Zhao   }
14114950695eSJianzhou Zhao   return ret;
14124950695eSJianzhou Zhao }
14134950695eSJianzhou Zhao 
14144950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1415a9aa8137SNico Weber int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
1416a9aa8137SNico Weber                       char *buf, size_t buflen, struct passwd **result,
1417a9aa8137SNico Weber                       dfsan_label uid_label, dfsan_label pwd_label,
1418a9aa8137SNico Weber                       dfsan_label buf_label, dfsan_label buflen_label,
1419a9aa8137SNico Weber                       dfsan_label result_label, dfsan_label *ret_label) {
1420a9aa8137SNico Weber   // Store the data in pwd, the strings referenced from pwd in buf, and the
1421a9aa8137SNico Weber   // address of pwd in *result.  On failure, NULL is stored in *result.
1422a9aa8137SNico Weber   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
1423a9aa8137SNico Weber   if (ret == 0) {
1424a9aa8137SNico Weber     dfsan_set_label(0, pwd, sizeof(struct passwd));
1425a9aa8137SNico Weber     dfsan_set_label(0, buf, strlen(buf) + 1);
1426a9aa8137SNico Weber   }
1427a9aa8137SNico Weber   *ret_label = 0;
1428a9aa8137SNico Weber   dfsan_set_label(0, result, sizeof(struct passwd*));
1429a9aa8137SNico Weber   return ret;
1430a9aa8137SNico Weber }
1431a9aa8137SNico Weber 
1432a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
14334950695eSJianzhou Zhao int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen,
14344950695eSJianzhou Zhao                       struct passwd **result, dfsan_label uid_label,
14354950695eSJianzhou Zhao                       dfsan_label pwd_label, dfsan_label buf_label,
14364950695eSJianzhou Zhao                       dfsan_label buflen_label, dfsan_label result_label,
14374950695eSJianzhou Zhao                       dfsan_label *ret_label, dfsan_origin uid_origin,
14384950695eSJianzhou Zhao                       dfsan_origin pwd_origin, dfsan_origin buf_origin,
14394950695eSJianzhou Zhao                       dfsan_origin buflen_origin, dfsan_origin result_origin,
14404950695eSJianzhou Zhao                       dfsan_origin *ret_origin) {
14414950695eSJianzhou Zhao   return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label,
14424950695eSJianzhou Zhao                            buf_label, buflen_label, result_label, ret_label);
14434950695eSJianzhou Zhao }
14444950695eSJianzhou Zhao 
14454950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
14466f13445fSMatt Morehouse int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
14476f13445fSMatt Morehouse                       int timeout, dfsan_label epfd_label,
14486f13445fSMatt Morehouse                       dfsan_label events_label, dfsan_label maxevents_label,
14496f13445fSMatt Morehouse                       dfsan_label timeout_label, dfsan_label *ret_label) {
14506f13445fSMatt Morehouse   int ret = epoll_wait(epfd, events, maxevents, timeout);
14516f13445fSMatt Morehouse   if (ret > 0)
14526f13445fSMatt Morehouse     dfsan_set_label(0, events, ret * sizeof(*events));
14536f13445fSMatt Morehouse   *ret_label = 0;
14546f13445fSMatt Morehouse   return ret;
14556f13445fSMatt Morehouse }
14566f13445fSMatt Morehouse 
14576f13445fSMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE
14584950695eSJianzhou Zhao int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
14594950695eSJianzhou Zhao                       int timeout, dfsan_label epfd_label,
14604950695eSJianzhou Zhao                       dfsan_label events_label, dfsan_label maxevents_label,
14614950695eSJianzhou Zhao                       dfsan_label timeout_label, dfsan_label *ret_label,
14624950695eSJianzhou Zhao                       dfsan_origin epfd_origin, dfsan_origin events_origin,
14634950695eSJianzhou Zhao                       dfsan_origin maxevents_origin,
14644950695eSJianzhou Zhao                       dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
14654950695eSJianzhou Zhao   return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label,
14664950695eSJianzhou Zhao                            events_label, maxevents_label, timeout_label,
14674950695eSJianzhou Zhao                            ret_label);
14684950695eSJianzhou Zhao }
14694950695eSJianzhou Zhao 
14704950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1471a9aa8137SNico Weber int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
1472a9aa8137SNico Weber                 dfsan_label dfs_label, dfsan_label nfds_label,
1473a9aa8137SNico Weber                 dfsan_label timeout_label, dfsan_label *ret_label) {
1474a9aa8137SNico Weber   int ret = poll(fds, nfds, timeout);
1475a9aa8137SNico Weber   if (ret >= 0) {
1476a9aa8137SNico Weber     for (; nfds > 0; --nfds) {
1477a9aa8137SNico Weber       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
1478a9aa8137SNico Weber     }
1479a9aa8137SNico Weber   }
1480a9aa8137SNico Weber   *ret_label = 0;
1481a9aa8137SNico Weber   return ret;
1482a9aa8137SNico Weber }
1483a9aa8137SNico Weber 
1484a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
14854950695eSJianzhou Zhao int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout,
14864950695eSJianzhou Zhao                 dfsan_label dfs_label, dfsan_label nfds_label,
14874950695eSJianzhou Zhao                 dfsan_label timeout_label, dfsan_label *ret_label,
14884950695eSJianzhou Zhao                 dfsan_origin dfs_origin, dfsan_origin nfds_origin,
14894950695eSJianzhou Zhao                 dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
14904950695eSJianzhou Zhao   return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label,
14914950695eSJianzhou Zhao                      ret_label);
14924950695eSJianzhou Zhao }
14934950695eSJianzhou Zhao 
14944950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1495a9aa8137SNico Weber int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
1496a9aa8137SNico Weber                   fd_set *exceptfds, struct timeval *timeout,
1497a9aa8137SNico Weber                   dfsan_label nfds_label, dfsan_label readfds_label,
1498a9aa8137SNico Weber                   dfsan_label writefds_label, dfsan_label exceptfds_label,
1499a9aa8137SNico Weber                   dfsan_label timeout_label, dfsan_label *ret_label) {
1500a9aa8137SNico Weber   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
1501a9aa8137SNico Weber   // Clear everything (also on error) since their content is either set or
1502a9aa8137SNico Weber   // undefined.
1503a9aa8137SNico Weber   if (readfds) {
1504a9aa8137SNico Weber     dfsan_set_label(0, readfds, sizeof(fd_set));
1505a9aa8137SNico Weber   }
1506a9aa8137SNico Weber   if (writefds) {
1507a9aa8137SNico Weber     dfsan_set_label(0, writefds, sizeof(fd_set));
1508a9aa8137SNico Weber   }
1509a9aa8137SNico Weber   if (exceptfds) {
1510a9aa8137SNico Weber     dfsan_set_label(0, exceptfds, sizeof(fd_set));
1511a9aa8137SNico Weber   }
1512a9aa8137SNico Weber   dfsan_set_label(0, timeout, sizeof(struct timeval));
1513a9aa8137SNico Weber   *ret_label = 0;
1514a9aa8137SNico Weber   return ret;
1515a9aa8137SNico Weber }
1516a9aa8137SNico Weber 
1517a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
15184950695eSJianzhou Zhao int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds,
15194950695eSJianzhou Zhao                   fd_set *exceptfds, struct timeval *timeout,
15204950695eSJianzhou Zhao                   dfsan_label nfds_label, dfsan_label readfds_label,
15214950695eSJianzhou Zhao                   dfsan_label writefds_label, dfsan_label exceptfds_label,
15224950695eSJianzhou Zhao                   dfsan_label timeout_label, dfsan_label *ret_label,
15234950695eSJianzhou Zhao                   dfsan_origin nfds_origin, dfsan_origin readfds_origin,
15244950695eSJianzhou Zhao                   dfsan_origin writefds_origin, dfsan_origin exceptfds_origin,
15254950695eSJianzhou Zhao                   dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
15264950695eSJianzhou Zhao   return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label,
15274950695eSJianzhou Zhao                        readfds_label, writefds_label, exceptfds_label,
15284950695eSJianzhou Zhao                        timeout_label, ret_label);
15294950695eSJianzhou Zhao }
15304950695eSJianzhou Zhao 
15314950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1532a9aa8137SNico Weber int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
1533a9aa8137SNico Weber                              dfsan_label pid_label,
1534a9aa8137SNico Weber                              dfsan_label cpusetsize_label,
1535a9aa8137SNico Weber                              dfsan_label mask_label, dfsan_label *ret_label) {
1536a9aa8137SNico Weber   int ret = sched_getaffinity(pid, cpusetsize, mask);
1537a9aa8137SNico Weber   if (ret == 0) {
1538a9aa8137SNico Weber     dfsan_set_label(0, mask, cpusetsize);
1539a9aa8137SNico Weber   }
1540a9aa8137SNico Weber   *ret_label = 0;
1541a9aa8137SNico Weber   return ret;
1542a9aa8137SNico Weber }
1543a9aa8137SNico Weber 
1544a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
15454950695eSJianzhou Zhao int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
15464950695eSJianzhou Zhao                              dfsan_label pid_label,
15474950695eSJianzhou Zhao                              dfsan_label cpusetsize_label,
15484950695eSJianzhou Zhao                              dfsan_label mask_label, dfsan_label *ret_label,
15494950695eSJianzhou Zhao                              dfsan_origin pid_origin,
15504950695eSJianzhou Zhao                              dfsan_origin cpusetsize_origin,
15514950695eSJianzhou Zhao                              dfsan_origin mask_origin,
15524950695eSJianzhou Zhao                              dfsan_origin *ret_origin) {
15534950695eSJianzhou Zhao   return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label,
15544950695eSJianzhou Zhao                                   cpusetsize_label, mask_label, ret_label);
15554950695eSJianzhou Zhao }
15564950695eSJianzhou Zhao 
15574950695eSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1558a9aa8137SNico Weber int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
1559a9aa8137SNico Weber                        dfsan_label *ret_label) {
1560a9aa8137SNico Weber   int ret = sigemptyset(set);
1561a9aa8137SNico Weber   dfsan_set_label(0, set, sizeof(sigset_t));
1562e4701471SJianzhou Zhao   *ret_label = 0;
1563a9aa8137SNico Weber   return ret;
1564a9aa8137SNico Weber }
1565a9aa8137SNico Weber 
15664e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
15674e67ae7bSJianzhou Zhao int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
15684e67ae7bSJianzhou Zhao                        dfsan_label *ret_label, dfsan_origin set_origin,
15694e67ae7bSJianzhou Zhao                        dfsan_origin *ret_origin) {
15704e67ae7bSJianzhou Zhao   return __dfsw_sigemptyset(set, set_label, ret_label);
15714e67ae7bSJianzhou Zhao }
15724e67ae7bSJianzhou Zhao 
15730f3fd3b2SJianzhou Zhao class SignalHandlerScope {
15740f3fd3b2SJianzhou Zhao  public:
15750f3fd3b2SJianzhou Zhao   SignalHandlerScope() {
15760f3fd3b2SJianzhou Zhao     if (DFsanThread *t = GetCurrentThread())
15770f3fd3b2SJianzhou Zhao       t->EnterSignalHandler();
15780f3fd3b2SJianzhou Zhao   }
15790f3fd3b2SJianzhou Zhao   ~SignalHandlerScope() {
15800f3fd3b2SJianzhou Zhao     if (DFsanThread *t = GetCurrentThread())
15810f3fd3b2SJianzhou Zhao       t->LeaveSignalHandler();
15820f3fd3b2SJianzhou Zhao   }
15830f3fd3b2SJianzhou Zhao };
15840f3fd3b2SJianzhou Zhao 
1585e1a4322fSJianzhou Zhao // Clear DFSan runtime TLS state at the end of a scope.
1586e1a4322fSJianzhou Zhao //
1587e1a4322fSJianzhou Zhao // Implementation must be async-signal-safe and use small data size, because
1588e1a4322fSJianzhou Zhao // instances of this class may live on the signal handler stack.
1589e1a4322fSJianzhou Zhao //
1590e1a4322fSJianzhou Zhao // DFSan uses TLS to pass metadata of arguments and return values. When an
1591e1a4322fSJianzhou Zhao // instrumented function accesses the TLS, if a signal callback happens, and the
1592e1a4322fSJianzhou Zhao // callback calls other instrumented functions with updating the same TLS, the
1593e1a4322fSJianzhou Zhao // TLS is in an inconsistent state after the callback ends. This may cause
1594e1a4322fSJianzhou Zhao // either under-tainting or over-tainting.
1595e1a4322fSJianzhou Zhao //
1596e1a4322fSJianzhou Zhao // The current implementation simply resets TLS at restore. This prevents from
1597e1a4322fSJianzhou Zhao // over-tainting. Although under-tainting may still happen, a taint flow can be
1598e1a4322fSJianzhou Zhao // found eventually if we run a DFSan-instrumented program multiple times. The
1599e1a4322fSJianzhou Zhao // alternative option is saving the entire TLS. However the TLS storage takes
1600e1a4322fSJianzhou Zhao // 2k bytes, and signal calls could be nested. So it does not seem worth.
1601e1a4322fSJianzhou Zhao class ScopedClearThreadLocalState {
1602e1a4322fSJianzhou Zhao  public:
1603e1a4322fSJianzhou Zhao   ScopedClearThreadLocalState() {}
1604e1a4322fSJianzhou Zhao   ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); }
1605e1a4322fSJianzhou Zhao };
1606e1a4322fSJianzhou Zhao 
1607e1a4322fSJianzhou Zhao // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls.
1608e1a4322fSJianzhou Zhao const int kMaxSignals = 1024;
1609e1a4322fSJianzhou Zhao static atomic_uintptr_t sigactions[kMaxSignals];
1610e1a4322fSJianzhou Zhao 
1611e1a4322fSJianzhou Zhao static void SignalHandler(int signo) {
16120f3fd3b2SJianzhou Zhao   SignalHandlerScope signal_handler_scope;
16130f3fd3b2SJianzhou Zhao   ScopedClearThreadLocalState scoped_clear_tls;
1614e1a4322fSJianzhou Zhao 
1615dbf8c00bSAndrew Browne   // Clear shadows for all inputs provided by system.
1616e1a4322fSJianzhou Zhao   dfsan_clear_arg_tls(0, sizeof(dfsan_label));
1617e1a4322fSJianzhou Zhao 
1618e1a4322fSJianzhou Zhao   typedef void (*signal_cb)(int x);
1619e1a4322fSJianzhou Zhao   signal_cb cb =
1620e1a4322fSJianzhou Zhao       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1621e1a4322fSJianzhou Zhao   cb(signo);
1622e1a4322fSJianzhou Zhao }
1623e1a4322fSJianzhou Zhao 
1624e1a4322fSJianzhou Zhao static void SignalAction(int signo, siginfo_t *si, void *uc) {
16250f3fd3b2SJianzhou Zhao   SignalHandlerScope signal_handler_scope;
16260f3fd3b2SJianzhou Zhao   ScopedClearThreadLocalState scoped_clear_tls;
1627e1a4322fSJianzhou Zhao 
1628e1a4322fSJianzhou Zhao   // Clear shadows for all inputs provided by system. Similar to SignalHandler.
1629e1a4322fSJianzhou Zhao   dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label));
1630e1a4322fSJianzhou Zhao   dfsan_set_label(0, si, sizeof(*si));
1631e1a4322fSJianzhou Zhao   dfsan_set_label(0, uc, sizeof(ucontext_t));
1632e1a4322fSJianzhou Zhao 
1633e1a4322fSJianzhou Zhao   typedef void (*sigaction_cb)(int, siginfo_t *, void *);
1634e1a4322fSJianzhou Zhao   sigaction_cb cb =
1635e1a4322fSJianzhou Zhao       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1636e1a4322fSJianzhou Zhao   cb(signo, si, uc);
1637e1a4322fSJianzhou Zhao }
1638e1a4322fSJianzhou Zhao 
1639a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
1640a9aa8137SNico Weber int __dfsw_sigaction(int signum, const struct sigaction *act,
1641a9aa8137SNico Weber                      struct sigaction *oldact, dfsan_label signum_label,
1642a9aa8137SNico Weber                      dfsan_label act_label, dfsan_label oldact_label,
1643a9aa8137SNico Weber                      dfsan_label *ret_label) {
1644e1a4322fSJianzhou Zhao   CHECK_LT(signum, kMaxSignals);
1645e1a4322fSJianzhou Zhao   SignalSpinLocker lock;
1646e1a4322fSJianzhou Zhao   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1647e1a4322fSJianzhou Zhao   struct sigaction new_act;
1648e1a4322fSJianzhou Zhao   struct sigaction *pnew_act = act ? &new_act : nullptr;
1649e1a4322fSJianzhou Zhao   if (act) {
1650e1a4322fSJianzhou Zhao     internal_memcpy(pnew_act, act, sizeof(struct sigaction));
1651e1a4322fSJianzhou Zhao     if (pnew_act->sa_flags & SA_SIGINFO) {
1652e1a4322fSJianzhou Zhao       uptr cb = (uptr)(pnew_act->sa_sigaction);
1653e1a4322fSJianzhou Zhao       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1654e1a4322fSJianzhou Zhao         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1655e1a4322fSJianzhou Zhao         pnew_act->sa_sigaction = SignalAction;
1656e1a4322fSJianzhou Zhao       }
1657e1a4322fSJianzhou Zhao     } else {
1658e1a4322fSJianzhou Zhao       uptr cb = (uptr)(pnew_act->sa_handler);
1659e1a4322fSJianzhou Zhao       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1660e1a4322fSJianzhou Zhao         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1661e1a4322fSJianzhou Zhao         pnew_act->sa_handler = SignalHandler;
1662e1a4322fSJianzhou Zhao       }
1663e1a4322fSJianzhou Zhao     }
1664e1a4322fSJianzhou Zhao   }
1665e1a4322fSJianzhou Zhao 
1666e1a4322fSJianzhou Zhao   int ret = sigaction(signum, pnew_act, oldact);
1667e1a4322fSJianzhou Zhao 
1668e1a4322fSJianzhou Zhao   if (ret == 0 && oldact) {
1669e1a4322fSJianzhou Zhao     if (oldact->sa_flags & SA_SIGINFO) {
1670e1a4322fSJianzhou Zhao       if (oldact->sa_sigaction == SignalAction)
1671e1a4322fSJianzhou Zhao         oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb;
1672e1a4322fSJianzhou Zhao     } else {
1673e1a4322fSJianzhou Zhao       if (oldact->sa_handler == SignalHandler)
1674e1a4322fSJianzhou Zhao         oldact->sa_handler = (decltype(oldact->sa_handler))old_cb;
1675e1a4322fSJianzhou Zhao     }
1676e1a4322fSJianzhou Zhao   }
1677e1a4322fSJianzhou Zhao 
1678a9aa8137SNico Weber   if (oldact) {
1679a9aa8137SNico Weber     dfsan_set_label(0, oldact, sizeof(struct sigaction));
1680a9aa8137SNico Weber   }
1681a9aa8137SNico Weber   *ret_label = 0;
1682a9aa8137SNico Weber   return ret;
1683a9aa8137SNico Weber }
1684a9aa8137SNico Weber 
1685a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
16864e67ae7bSJianzhou Zhao int __dfso_sigaction(int signum, const struct sigaction *act,
16874e67ae7bSJianzhou Zhao                      struct sigaction *oldact, dfsan_label signum_label,
16884e67ae7bSJianzhou Zhao                      dfsan_label act_label, dfsan_label oldact_label,
16894e67ae7bSJianzhou Zhao                      dfsan_label *ret_label, dfsan_origin signum_origin,
16904e67ae7bSJianzhou Zhao                      dfsan_origin act_origin, dfsan_origin oldact_origin,
16914e67ae7bSJianzhou Zhao                      dfsan_origin *ret_origin) {
16924e67ae7bSJianzhou Zhao   return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
16934e67ae7bSJianzhou Zhao                           oldact_label, ret_label);
16944e67ae7bSJianzhou Zhao }
16954e67ae7bSJianzhou Zhao 
16964e67ae7bSJianzhou Zhao static sighandler_t dfsan_signal(int signum, sighandler_t handler,
16974e67ae7bSJianzhou Zhao                                  dfsan_label *ret_label) {
169893afc345SJianzhou Zhao   CHECK_LT(signum, kMaxSignals);
169993afc345SJianzhou Zhao   SignalSpinLocker lock;
170093afc345SJianzhou Zhao   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
170193afc345SJianzhou Zhao   if (handler != SIG_IGN && handler != SIG_DFL) {
170293afc345SJianzhou Zhao     atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
170393afc345SJianzhou Zhao     handler = &SignalHandler;
170493afc345SJianzhou Zhao   }
170593afc345SJianzhou Zhao 
170693afc345SJianzhou Zhao   sighandler_t ret = signal(signum, handler);
170793afc345SJianzhou Zhao 
170893afc345SJianzhou Zhao   if (ret == SignalHandler)
170993afc345SJianzhou Zhao     ret = (sighandler_t)old_cb;
171093afc345SJianzhou Zhao 
171193afc345SJianzhou Zhao   *ret_label = 0;
171293afc345SJianzhou Zhao   return ret;
171393afc345SJianzhou Zhao }
171493afc345SJianzhou Zhao 
171593afc345SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1716dbf8c00bSAndrew Browne sighandler_t __dfsw_signal(int signum, sighandler_t handler,
1717dbf8c00bSAndrew Browne                            dfsan_label signum_label, dfsan_label handler_label,
1718dbf8c00bSAndrew Browne                            dfsan_label *ret_label) {
17194e67ae7bSJianzhou Zhao   return dfsan_signal(signum, handler, ret_label);
17204e67ae7bSJianzhou Zhao }
17214e67ae7bSJianzhou Zhao 
17224e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1723dbf8c00bSAndrew Browne sighandler_t __dfso_signal(int signum, sighandler_t handler,
1724dbf8c00bSAndrew Browne                            dfsan_label signum_label, dfsan_label handler_label,
17254e67ae7bSJianzhou Zhao                            dfsan_label *ret_label, dfsan_origin signum_origin,
1726dbf8c00bSAndrew Browne                            dfsan_origin handler_origin,
1727dbf8c00bSAndrew Browne                            dfsan_origin *ret_origin) {
17284e67ae7bSJianzhou Zhao   return dfsan_signal(signum, handler, ret_label);
17294e67ae7bSJianzhou Zhao }
17304e67ae7bSJianzhou Zhao 
17314e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1732bdaeb82aSMatt Morehouse int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1733bdaeb82aSMatt Morehouse                        dfsan_label old_ss_label, dfsan_label *ret_label) {
1734bdaeb82aSMatt Morehouse   int ret = sigaltstack(ss, old_ss);
1735bdaeb82aSMatt Morehouse   if (ret != -1 && old_ss)
1736bdaeb82aSMatt Morehouse     dfsan_set_label(0, old_ss, sizeof(*old_ss));
1737bdaeb82aSMatt Morehouse   *ret_label = 0;
1738bdaeb82aSMatt Morehouse   return ret;
1739bdaeb82aSMatt Morehouse }
1740bdaeb82aSMatt Morehouse 
1741bdaeb82aSMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE
17424e67ae7bSJianzhou Zhao int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
17434e67ae7bSJianzhou Zhao                        dfsan_label old_ss_label, dfsan_label *ret_label,
17444e67ae7bSJianzhou Zhao                        dfsan_origin ss_origin, dfsan_origin old_ss_origin,
17454e67ae7bSJianzhou Zhao                        dfsan_origin *ret_origin) {
17464e67ae7bSJianzhou Zhao   return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
17474e67ae7bSJianzhou Zhao }
17484e67ae7bSJianzhou Zhao 
17494e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1750a9aa8137SNico Weber int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
1751a9aa8137SNico Weber                         dfsan_label tv_label, dfsan_label tz_label,
1752a9aa8137SNico Weber                         dfsan_label *ret_label) {
1753a9aa8137SNico Weber   int ret = gettimeofday(tv, tz);
1754a9aa8137SNico Weber   if (tv) {
1755a9aa8137SNico Weber     dfsan_set_label(0, tv, sizeof(struct timeval));
1756a9aa8137SNico Weber   }
1757a9aa8137SNico Weber   if (tz) {
1758a9aa8137SNico Weber     dfsan_set_label(0, tz, sizeof(struct timezone));
1759a9aa8137SNico Weber   }
1760a9aa8137SNico Weber   *ret_label = 0;
1761a9aa8137SNico Weber   return ret;
1762a9aa8137SNico Weber }
1763a9aa8137SNico Weber 
176491516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
176591516925SJianzhou Zhao int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz,
176691516925SJianzhou Zhao                         dfsan_label tv_label, dfsan_label tz_label,
176791516925SJianzhou Zhao                         dfsan_label *ret_label, dfsan_origin tv_origin,
176891516925SJianzhou Zhao                         dfsan_origin tz_origin, dfsan_origin *ret_origin) {
176991516925SJianzhou Zhao   return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label);
177091516925SJianzhou Zhao }
177191516925SJianzhou Zhao 
1772a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
1773a9aa8137SNico Weber                                                   dfsan_label s_label,
1774a9aa8137SNico Weber                                                   dfsan_label c_label,
1775a9aa8137SNico Weber                                                   dfsan_label n_label,
1776a9aa8137SNico Weber                                                   dfsan_label *ret_label) {
1777a9aa8137SNico Weber   void *ret = memchr(s, c, n);
1778a9aa8137SNico Weber   if (flags().strict_data_dependencies) {
1779a9aa8137SNico Weber     *ret_label = ret ? s_label : 0;
1780a9aa8137SNico Weber   } else {
1781a9aa8137SNico Weber     size_t len =
1782a9aa8137SNico Weber         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
1783a9aa8137SNico Weber             : n;
1784a9aa8137SNico Weber     *ret_label =
1785a9aa8137SNico Weber         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
1786a9aa8137SNico Weber   }
1787a9aa8137SNico Weber   return ret;
1788a9aa8137SNico Weber }
1789a9aa8137SNico Weber 
179091516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr(
179191516925SJianzhou Zhao     void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label,
179291516925SJianzhou Zhao     dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin,
179391516925SJianzhou Zhao     dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) {
179491516925SJianzhou Zhao   void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label);
179591516925SJianzhou Zhao   if (flags().strict_data_dependencies) {
179691516925SJianzhou Zhao     if (ret)
179791516925SJianzhou Zhao       *ret_origin = s_origin;
179891516925SJianzhou Zhao   } else {
179991516925SJianzhou Zhao     size_t len =
180091516925SJianzhou Zhao         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
180191516925SJianzhou Zhao             : n;
180291516925SJianzhou Zhao     dfsan_origin o = dfsan_read_origin_of_first_taint(s, len);
180391516925SJianzhou Zhao     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
180491516925SJianzhou Zhao   }
180591516925SJianzhou Zhao   return ret;
180691516925SJianzhou Zhao }
180791516925SJianzhou Zhao 
1808a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
1809a9aa8137SNico Weber                                                    dfsan_label s_label,
1810a9aa8137SNico Weber                                                    dfsan_label c_label,
1811a9aa8137SNico Weber                                                    dfsan_label *ret_label) {
1812a9aa8137SNico Weber   char *ret = strrchr(s, c);
1813a9aa8137SNico Weber   if (flags().strict_data_dependencies) {
1814a9aa8137SNico Weber     *ret_label = ret ? s_label : 0;
1815a9aa8137SNico Weber   } else {
1816a9aa8137SNico Weber     *ret_label =
1817a9aa8137SNico Weber         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
1818a9aa8137SNico Weber                     dfsan_union(s_label, c_label));
1819a9aa8137SNico Weber   }
1820a9aa8137SNico Weber 
1821a9aa8137SNico Weber   return ret;
1822a9aa8137SNico Weber }
1823a9aa8137SNico Weber 
182491516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr(
182591516925SJianzhou Zhao     char *s, int c, dfsan_label s_label, dfsan_label c_label,
182691516925SJianzhou Zhao     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
182791516925SJianzhou Zhao     dfsan_origin *ret_origin) {
182891516925SJianzhou Zhao   char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label);
182991516925SJianzhou Zhao   if (flags().strict_data_dependencies) {
183091516925SJianzhou Zhao     if (ret)
183191516925SJianzhou Zhao       *ret_origin = s_origin;
183291516925SJianzhou Zhao   } else {
183391516925SJianzhou Zhao     size_t s_len = strlen(s) + 1;
183491516925SJianzhou Zhao     dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len);
183591516925SJianzhou Zhao     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
183691516925SJianzhou Zhao   }
183791516925SJianzhou Zhao 
183891516925SJianzhou Zhao   return ret;
183991516925SJianzhou Zhao }
184091516925SJianzhou Zhao 
1841a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
1842a9aa8137SNico Weber                                                   dfsan_label haystack_label,
1843a9aa8137SNico Weber                                                   dfsan_label needle_label,
1844a9aa8137SNico Weber                                                   dfsan_label *ret_label) {
1845a9aa8137SNico Weber   char *ret = strstr(haystack, needle);
1846a9aa8137SNico Weber   if (flags().strict_data_dependencies) {
1847a9aa8137SNico Weber     *ret_label = ret ? haystack_label : 0;
1848a9aa8137SNico Weber   } else {
1849a9aa8137SNico Weber     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
1850a9aa8137SNico Weber     *ret_label =
1851a9aa8137SNico Weber         dfsan_union(dfsan_read_label(haystack, len),
1852a9aa8137SNico Weber                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
1853a9aa8137SNico Weber                                 dfsan_union(haystack_label, needle_label)));
1854a9aa8137SNico Weber   }
1855a9aa8137SNico Weber 
1856a9aa8137SNico Weber   return ret;
1857a9aa8137SNico Weber }
1858a9aa8137SNico Weber 
185991516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle,
186091516925SJianzhou Zhao                                                   dfsan_label haystack_label,
186191516925SJianzhou Zhao                                                   dfsan_label needle_label,
186291516925SJianzhou Zhao                                                   dfsan_label *ret_label,
186391516925SJianzhou Zhao                                                   dfsan_origin haystack_origin,
186491516925SJianzhou Zhao                                                   dfsan_origin needle_origin,
186591516925SJianzhou Zhao                                                   dfsan_origin *ret_origin) {
186691516925SJianzhou Zhao   char *ret =
186791516925SJianzhou Zhao       __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label);
186891516925SJianzhou Zhao   if (flags().strict_data_dependencies) {
186991516925SJianzhou Zhao     if (ret)
187091516925SJianzhou Zhao       *ret_origin = haystack_origin;
187191516925SJianzhou Zhao   } else {
187291516925SJianzhou Zhao     size_t needle_len = strlen(needle);
187391516925SJianzhou Zhao     size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1;
187491516925SJianzhou Zhao     dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len);
187591516925SJianzhou Zhao     if (o) {
187691516925SJianzhou Zhao       *ret_origin = o;
187791516925SJianzhou Zhao     } else {
187891516925SJianzhou Zhao       o = dfsan_read_origin_of_first_taint(needle, needle_len + 1);
187991516925SJianzhou Zhao       *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin);
188091516925SJianzhou Zhao     }
188191516925SJianzhou Zhao   }
188291516925SJianzhou Zhao 
188391516925SJianzhou Zhao   return ret;
188491516925SJianzhou Zhao }
188591516925SJianzhou Zhao 
1886a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
1887a9aa8137SNico Weber                                                    struct timespec *rem,
1888a9aa8137SNico Weber                                                    dfsan_label req_label,
1889a9aa8137SNico Weber                                                    dfsan_label rem_label,
1890a9aa8137SNico Weber                                                    dfsan_label *ret_label) {
1891a9aa8137SNico Weber   int ret = nanosleep(req, rem);
1892a9aa8137SNico Weber   *ret_label = 0;
1893a9aa8137SNico Weber   if (ret == -1) {
1894a9aa8137SNico Weber     // Interrupted by a signal, rem is filled with the remaining time.
1895a9aa8137SNico Weber     dfsan_set_label(0, rem, sizeof(struct timespec));
1896a9aa8137SNico Weber   }
1897a9aa8137SNico Weber   return ret;
1898a9aa8137SNico Weber }
1899a9aa8137SNico Weber 
190091516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
190191516925SJianzhou Zhao     const struct timespec *req, struct timespec *rem, dfsan_label req_label,
190291516925SJianzhou Zhao     dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin,
190391516925SJianzhou Zhao     dfsan_origin rem_origin, dfsan_origin *ret_origin) {
190491516925SJianzhou Zhao   return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
190591516925SJianzhou Zhao }
190691516925SJianzhou Zhao 
19073b3d622bSAndrew Browne static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg,
19083b3d622bSAndrew Browne                                 int flags) {
19097bc7501aSMatt Morehouse   dfsan_set_label(0, msg, sizeof(*msg));
19107bc7501aSMatt Morehouse   dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
19117bc7501aSMatt Morehouse   dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
19123b3d622bSAndrew Browne   for (size_t i = 0; i < msg->msg_iovlen; ++i) {
19137bc7501aSMatt Morehouse     struct iovec *iov = &msg->msg_iov[i];
19143b3d622bSAndrew Browne     size_t iov_written = iov->iov_len;
19153b3d622bSAndrew Browne 
19163b3d622bSAndrew Browne     // When MSG_TRUNC is not set, we want to avoid setting 0 label on bytes that
19173b3d622bSAndrew Browne     // may not have changed, using bytes_written to bound the 0 label write.
19183b3d622bSAndrew Browne     // When MSG_TRUNC flag is set, bytes_written may be larger than the buffer,
19193b3d622bSAndrew Browne     // and should not be used as a bound.
19203b3d622bSAndrew Browne     if (!(MSG_TRUNC & flags)) {
19213b3d622bSAndrew Browne       if (bytes_written < iov->iov_len) {
19223b3d622bSAndrew Browne         iov_written = bytes_written;
19233b3d622bSAndrew Browne       }
19247bc7501aSMatt Morehouse       bytes_written -= iov_written;
19257bc7501aSMatt Morehouse     }
19263b3d622bSAndrew Browne 
19273b3d622bSAndrew Browne     dfsan_set_label(0, iov->iov_base, iov_written);
19283b3d622bSAndrew Browne   }
19297bc7501aSMatt Morehouse }
19307bc7501aSMatt Morehouse 
19317bc7501aSMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
19327bc7501aSMatt Morehouse     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
19337bc7501aSMatt Morehouse     struct timespec *timeout, dfsan_label sockfd_label,
19347bc7501aSMatt Morehouse     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
19357bc7501aSMatt Morehouse     dfsan_label timeout_label, dfsan_label *ret_label) {
19367bc7501aSMatt Morehouse   int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
19377bc7501aSMatt Morehouse   for (int i = 0; i < ret; ++i) {
19387bc7501aSMatt Morehouse     dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
19393b3d622bSAndrew Browne     clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr, flags);
19407bc7501aSMatt Morehouse   }
19417bc7501aSMatt Morehouse   *ret_label = 0;
19427bc7501aSMatt Morehouse   return ret;
19437bc7501aSMatt Morehouse }
19447bc7501aSMatt Morehouse 
194591516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg(
194691516925SJianzhou Zhao     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
194791516925SJianzhou Zhao     struct timespec *timeout, dfsan_label sockfd_label,
194891516925SJianzhou Zhao     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
194991516925SJianzhou Zhao     dfsan_label timeout_label, dfsan_label *ret_label,
195091516925SJianzhou Zhao     dfsan_origin sockfd_origin, dfsan_origin msgvec_origin,
195191516925SJianzhou Zhao     dfsan_origin vlen_origin, dfsan_origin flags_origin,
195291516925SJianzhou Zhao     dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
195391516925SJianzhou Zhao   return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label,
195491516925SJianzhou Zhao                          msgvec_label, vlen_label, flags_label, timeout_label,
195591516925SJianzhou Zhao                          ret_label);
195691516925SJianzhou Zhao }
195791516925SJianzhou Zhao 
1958a3eb2fb2SMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
1959a3eb2fb2SMatt Morehouse     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1960a3eb2fb2SMatt Morehouse     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
1961a3eb2fb2SMatt Morehouse   ssize_t ret = recvmsg(sockfd, msg, flags);
19627bc7501aSMatt Morehouse   if (ret >= 0)
19633b3d622bSAndrew Browne     clear_msghdr_labels(ret, msg, flags);
1964a3eb2fb2SMatt Morehouse   *ret_label = 0;
1965a3eb2fb2SMatt Morehouse   return ret;
1966a3eb2fb2SMatt Morehouse }
1967a3eb2fb2SMatt Morehouse 
196891516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg(
196991516925SJianzhou Zhao     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
197091516925SJianzhou Zhao     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label,
197191516925SJianzhou Zhao     dfsan_origin sockfd_origin, dfsan_origin msg_origin,
197291516925SJianzhou Zhao     dfsan_origin flags_origin, dfsan_origin *ret_origin) {
197391516925SJianzhou Zhao   return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label,
197491516925SJianzhou Zhao                         flags_label, ret_label);
197591516925SJianzhou Zhao }
197691516925SJianzhou Zhao 
1977a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int
1978a9aa8137SNico Weber __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
1979a9aa8137SNico Weber                   dfsan_label domain_label, dfsan_label type_label,
1980a9aa8137SNico Weber                   dfsan_label protocol_label, dfsan_label sv_label,
1981a9aa8137SNico Weber                   dfsan_label *ret_label) {
1982a9aa8137SNico Weber   int ret = socketpair(domain, type, protocol, sv);
1983a9aa8137SNico Weber   *ret_label = 0;
1984a9aa8137SNico Weber   if (ret == 0) {
1985a9aa8137SNico Weber     dfsan_set_label(0, sv, sizeof(*sv) * 2);
1986a9aa8137SNico Weber   }
1987a9aa8137SNico Weber   return ret;
1988a9aa8137SNico Weber }
1989a9aa8137SNico Weber 
199091516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair(
199191516925SJianzhou Zhao     int domain, int type, int protocol, int sv[2], dfsan_label domain_label,
199291516925SJianzhou Zhao     dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label,
199391516925SJianzhou Zhao     dfsan_label *ret_label, dfsan_origin domain_origin,
199491516925SJianzhou Zhao     dfsan_origin type_origin, dfsan_origin protocol_origin,
199591516925SJianzhou Zhao     dfsan_origin sv_origin, dfsan_origin *ret_origin) {
199691516925SJianzhou Zhao   return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label,
199791516925SJianzhou Zhao                            protocol_label, sv_label, ret_label);
199891516925SJianzhou Zhao }
199991516925SJianzhou Zhao 
20004eedc2e3SMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt(
20014eedc2e3SMatt Morehouse     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
20024eedc2e3SMatt Morehouse     dfsan_label sockfd_label, dfsan_label level_label,
20034eedc2e3SMatt Morehouse     dfsan_label optname_label, dfsan_label optval_label,
20044eedc2e3SMatt Morehouse     dfsan_label optlen_label, dfsan_label *ret_label) {
20054eedc2e3SMatt Morehouse   int ret = getsockopt(sockfd, level, optname, optval, optlen);
20064eedc2e3SMatt Morehouse   if (ret != -1 && optval && optlen) {
20074eedc2e3SMatt Morehouse     dfsan_set_label(0, optlen, sizeof(*optlen));
20084eedc2e3SMatt Morehouse     dfsan_set_label(0, optval, *optlen);
20094eedc2e3SMatt Morehouse   }
20104eedc2e3SMatt Morehouse   *ret_label = 0;
20114eedc2e3SMatt Morehouse   return ret;
20124eedc2e3SMatt Morehouse }
20134eedc2e3SMatt Morehouse 
201491516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt(
201591516925SJianzhou Zhao     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
201691516925SJianzhou Zhao     dfsan_label sockfd_label, dfsan_label level_label,
201791516925SJianzhou Zhao     dfsan_label optname_label, dfsan_label optval_label,
201891516925SJianzhou Zhao     dfsan_label optlen_label, dfsan_label *ret_label,
201991516925SJianzhou Zhao     dfsan_origin sockfd_origin, dfsan_origin level_origin,
202091516925SJianzhou Zhao     dfsan_origin optname_origin, dfsan_origin optval_origin,
202191516925SJianzhou Zhao     dfsan_origin optlen_origin, dfsan_origin *ret_origin) {
202291516925SJianzhou Zhao   return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label,
202391516925SJianzhou Zhao                            level_label, optname_label, optval_label,
202491516925SJianzhou Zhao                            optlen_label, ret_label);
202591516925SJianzhou Zhao }
202691516925SJianzhou Zhao 
20278a874a42SMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname(
20288a874a42SMatt Morehouse     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
20298a874a42SMatt Morehouse     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
20308a874a42SMatt Morehouse     dfsan_label *ret_label) {
20318a874a42SMatt Morehouse   socklen_t origlen = addrlen ? *addrlen : 0;
20328a874a42SMatt Morehouse   int ret = getsockname(sockfd, addr, addrlen);
20338a874a42SMatt Morehouse   if (ret != -1 && addr && addrlen) {
20348a874a42SMatt Morehouse     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
20358a874a42SMatt Morehouse     dfsan_set_label(0, addrlen, sizeof(*addrlen));
20368a874a42SMatt Morehouse     dfsan_set_label(0, addr, written_bytes);
20378a874a42SMatt Morehouse   }
20388a874a42SMatt Morehouse   *ret_label = 0;
20398a874a42SMatt Morehouse   return ret;
20408a874a42SMatt Morehouse }
20418a874a42SMatt Morehouse 
204291516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname(
204391516925SJianzhou Zhao     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
204491516925SJianzhou Zhao     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
204591516925SJianzhou Zhao     dfsan_label *ret_label, dfsan_origin sockfd_origin,
204691516925SJianzhou Zhao     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
204791516925SJianzhou Zhao     dfsan_origin *ret_origin) {
204891516925SJianzhou Zhao   return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label,
204991516925SJianzhou Zhao                             addrlen_label, ret_label);
205091516925SJianzhou Zhao }
205191516925SJianzhou Zhao 
2052fa4bd4b3SMatt Morehouse SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername(
2053fa4bd4b3SMatt Morehouse     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2054fa4bd4b3SMatt Morehouse     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2055fa4bd4b3SMatt Morehouse     dfsan_label *ret_label) {
2056fa4bd4b3SMatt Morehouse   socklen_t origlen = addrlen ? *addrlen : 0;
2057fa4bd4b3SMatt Morehouse   int ret = getpeername(sockfd, addr, addrlen);
2058fa4bd4b3SMatt Morehouse   if (ret != -1 && addr && addrlen) {
2059fa4bd4b3SMatt Morehouse     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2060fa4bd4b3SMatt Morehouse     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2061fa4bd4b3SMatt Morehouse     dfsan_set_label(0, addr, written_bytes);
2062fa4bd4b3SMatt Morehouse   }
2063fa4bd4b3SMatt Morehouse   *ret_label = 0;
2064fa4bd4b3SMatt Morehouse   return ret;
2065fa4bd4b3SMatt Morehouse }
2066fa4bd4b3SMatt Morehouse 
206791516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername(
206891516925SJianzhou Zhao     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
206991516925SJianzhou Zhao     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
207091516925SJianzhou Zhao     dfsan_label *ret_label, dfsan_origin sockfd_origin,
207191516925SJianzhou Zhao     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
207291516925SJianzhou Zhao     dfsan_origin *ret_origin) {
207391516925SJianzhou Zhao   return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label,
207491516925SJianzhou Zhao                             addrlen_label, ret_label);
207591516925SJianzhou Zhao }
207691516925SJianzhou Zhao 
2077dbf8c00bSAndrew Browne // Type of the function passed to dfsan_set_write_callback.
2078dbf8c00bSAndrew Browne typedef void (*write_dfsan_callback_t)(int fd, const void *buf, ssize_t count);
20794e67ae7bSJianzhou Zhao 
2080a9aa8137SNico Weber // Calls to dfsan_set_write_callback() set the values in this struct.
2081a9aa8137SNico Weber // Calls to the custom version of write() read (and invoke) them.
2082a9aa8137SNico Weber static struct {
2083dbf8c00bSAndrew Browne   write_dfsan_callback_t write_callback = nullptr;
2084a9aa8137SNico Weber } write_callback_info;
2085a9aa8137SNico Weber 
2086dbf8c00bSAndrew Browne SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_dfsan_set_write_callback(
2087dbf8c00bSAndrew Browne     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
2088a9aa8137SNico Weber     dfsan_label *ret_label) {
2089a9aa8137SNico Weber   write_callback_info.write_callback = write_callback;
2090a9aa8137SNico Weber }
2091a9aa8137SNico Weber 
20924e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
2093dbf8c00bSAndrew Browne     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
2094dbf8c00bSAndrew Browne     dfsan_label *ret_label, dfsan_origin write_callback_origin,
2095dbf8c00bSAndrew Browne     dfsan_origin *ret_origin) {
2096dbf8c00bSAndrew Browne   write_callback_info.write_callback = write_callback;
2097dbf8c00bSAndrew Browne }
2098dbf8c00bSAndrew Browne 
2099dbf8c00bSAndrew Browne static inline void setup_tls_args_for_write_callback(
2100dbf8c00bSAndrew Browne     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
2101dbf8c00bSAndrew Browne     bool origins, dfsan_origin fd_origin, dfsan_origin buf_origin,
2102dbf8c00bSAndrew Browne     dfsan_origin count_origin) {
2103dbf8c00bSAndrew Browne   // The callback code will expect argument shadow labels in the args TLS,
2104dbf8c00bSAndrew Browne   // and origin labels in the origin args TLS.
2105dbf8c00bSAndrew Browne   // Previously this was done by a trampoline, but we want to remove this:
2106dbf8c00bSAndrew Browne   // https://github.com/llvm/llvm-project/issues/54172
2107dbf8c00bSAndrew Browne   //
2108dbf8c00bSAndrew Browne   // Instead, this code is manually setting up the args TLS data.
2109dbf8c00bSAndrew Browne   //
2110dbf8c00bSAndrew Browne   // The offsets used need to correspond with the instrumentation code,
2111dbf8c00bSAndrew Browne   // see llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
2112dbf8c00bSAndrew Browne   // DFSanFunction::getShadowForTLSArgument.
2113dbf8c00bSAndrew Browne   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L1684
2114dbf8c00bSAndrew Browne   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L125
2115dbf8c00bSAndrew Browne   //
2116dbf8c00bSAndrew Browne   // Here the arguments are all primitives, but it can be more complex
2117dbf8c00bSAndrew Browne   // to compute offsets for array/aggregate type arguments.
2118dbf8c00bSAndrew Browne   //
2119dbf8c00bSAndrew Browne   // TODO(browneee): Consider a builtin to improve maintainabliity.
2120dbf8c00bSAndrew Browne   // With a builtin, we would provide the argument labels via builtin,
2121dbf8c00bSAndrew Browne   // and the builtin would reuse parts of the instrumentation code to ensure
2122dbf8c00bSAndrew Browne   // that this code and the instrumentation can never be out of sync.
2123dbf8c00bSAndrew Browne   // Note: Currently DFSan instrumentation does not run on this code, so
2124dbf8c00bSAndrew Browne   // the builtin may need to be handled outside DFSan instrumentation.
2125dbf8c00bSAndrew Browne   dfsan_set_arg_tls(0, fd_label);
2126dbf8c00bSAndrew Browne   dfsan_set_arg_tls(1, buf_label);
2127dbf8c00bSAndrew Browne   dfsan_set_arg_tls(2, count_label);
2128dbf8c00bSAndrew Browne   if (origins) {
2129dbf8c00bSAndrew Browne     dfsan_set_arg_origin_tls(0, fd_origin);
2130dbf8c00bSAndrew Browne     dfsan_set_arg_origin_tls(1, buf_origin);
2131dbf8c00bSAndrew Browne     dfsan_set_arg_origin_tls(2, count_origin);
2132dbf8c00bSAndrew Browne   }
21334e67ae7bSJianzhou Zhao }
21344e67ae7bSJianzhou Zhao 
2135a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE int
2136a9aa8137SNico Weber __dfsw_write(int fd, const void *buf, size_t count,
2137a9aa8137SNico Weber              dfsan_label fd_label, dfsan_label buf_label,
2138a9aa8137SNico Weber              dfsan_label count_label, dfsan_label *ret_label) {
2139a9aa8137SNico Weber   if (write_callback_info.write_callback) {
2140dbf8c00bSAndrew Browne     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, false,
2141dbf8c00bSAndrew Browne                                       0, 0, 0);
2142dbf8c00bSAndrew Browne     write_callback_info.write_callback(fd, buf, count);
2143a9aa8137SNico Weber   }
2144a9aa8137SNico Weber 
2145a9aa8137SNico Weber   *ret_label = 0;
2146a9aa8137SNico Weber   return write(fd, buf, count);
2147a9aa8137SNico Weber }
21484e67ae7bSJianzhou Zhao 
21494e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
21504e67ae7bSJianzhou Zhao     int fd, const void *buf, size_t count, dfsan_label fd_label,
21514e67ae7bSJianzhou Zhao     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
21524e67ae7bSJianzhou Zhao     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
21534e67ae7bSJianzhou Zhao     dfsan_origin *ret_origin) {
2154dbf8c00bSAndrew Browne   if (write_callback_info.write_callback) {
2155dbf8c00bSAndrew Browne     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, true,
2156dbf8c00bSAndrew Browne                                       fd_origin, buf_origin, count_origin);
2157dbf8c00bSAndrew Browne     write_callback_info.write_callback(fd, buf, count);
21584e67ae7bSJianzhou Zhao   }
21594e67ae7bSJianzhou Zhao 
21604e67ae7bSJianzhou Zhao   *ret_label = 0;
21614e67ae7bSJianzhou Zhao   return write(fd, buf, count);
21624e67ae7bSJianzhou Zhao }
2163a9aa8137SNico Weber }  // namespace __dfsan
2164a9aa8137SNico Weber 
2165a9aa8137SNico Weber // Type used to extract a dfsan_label with va_arg()
2166a9aa8137SNico Weber typedef int dfsan_label_va;
2167a9aa8137SNico Weber 
2168a9aa8137SNico Weber // Formats a chunk either a constant string or a single format directive (e.g.,
2169a9aa8137SNico Weber // '%.3f').
2170a9aa8137SNico Weber struct Formatter {
2171a9aa8137SNico Weber   Formatter(char *str_, const char *fmt_, size_t size_)
21728dbcf8ebSTomasz Kuchta       : str(str_),
21738dbcf8ebSTomasz Kuchta         str_off(0),
21748dbcf8ebSTomasz Kuchta         size(size_),
21758dbcf8ebSTomasz Kuchta         fmt_start(fmt_),
21768dbcf8ebSTomasz Kuchta         fmt_cur(fmt_),
21778dbcf8ebSTomasz Kuchta         width(-1),
2178368d7493SAndrew Browne         num_scanned(-1),
2179368d7493SAndrew Browne         skip(false) {}
2180a9aa8137SNico Weber 
2181a9aa8137SNico Weber   int format() {
2182a9aa8137SNico Weber     char *tmp_fmt = build_format_string();
2183a9aa8137SNico Weber     int retval =
2184a9aa8137SNico Weber         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
2185a9aa8137SNico Weber                  0 /* used only to avoid warnings */);
2186a9aa8137SNico Weber     free(tmp_fmt);
2187a9aa8137SNico Weber     return retval;
2188a9aa8137SNico Weber   }
2189a9aa8137SNico Weber 
2190a9aa8137SNico Weber   template <typename T> int format(T arg) {
2191a9aa8137SNico Weber     char *tmp_fmt = build_format_string();
2192a9aa8137SNico Weber     int retval;
2193a9aa8137SNico Weber     if (width >= 0) {
2194a9aa8137SNico Weber       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
2195a9aa8137SNico Weber                         tmp_fmt, width, arg);
2196a9aa8137SNico Weber     } else {
2197a9aa8137SNico Weber       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
2198a9aa8137SNico Weber                         tmp_fmt, arg);
2199a9aa8137SNico Weber     }
2200a9aa8137SNico Weber     free(tmp_fmt);
2201a9aa8137SNico Weber     return retval;
2202a9aa8137SNico Weber   }
2203a9aa8137SNico Weber 
2204cd94fa7eSAndrew Browne   char *build_format_string() {
2205a9aa8137SNico Weber     size_t fmt_size = fmt_cur - fmt_start + 1;
2206cd94fa7eSAndrew Browne     char *new_fmt = (char *)malloc(fmt_size + 1);
2207a9aa8137SNico Weber     assert(new_fmt);
2208a9aa8137SNico Weber     internal_memcpy(new_fmt, fmt_start, fmt_size);
2209a9aa8137SNico Weber     new_fmt[fmt_size] = '\0';
2210a9aa8137SNico Weber     return new_fmt;
2211a9aa8137SNico Weber   }
2212a9aa8137SNico Weber 
2213a9aa8137SNico Weber   char *str_cur() { return str + str_off; }
2214a9aa8137SNico Weber 
2215a9aa8137SNico Weber   size_t num_written_bytes(int retval) {
2216a9aa8137SNico Weber     if (retval < 0) {
2217a9aa8137SNico Weber       return 0;
2218a9aa8137SNico Weber     }
2219a9aa8137SNico Weber 
2220a9aa8137SNico Weber     size_t num_avail = str_off < size ? size - str_off : 0;
2221a9aa8137SNico Weber     if (num_avail == 0) {
2222a9aa8137SNico Weber       return 0;
2223a9aa8137SNico Weber     }
2224a9aa8137SNico Weber 
2225a9aa8137SNico Weber     size_t num_written = retval;
2226a9aa8137SNico Weber     // A return value of {v,}snprintf of size or more means that the output was
2227a9aa8137SNico Weber     // truncated.
2228a9aa8137SNico Weber     if (num_written >= num_avail) {
2229a9aa8137SNico Weber       num_written -= num_avail;
2230a9aa8137SNico Weber     }
2231a9aa8137SNico Weber 
2232a9aa8137SNico Weber     return num_written;
2233a9aa8137SNico Weber   }
2234a9aa8137SNico Weber 
2235a9aa8137SNico Weber   char *str;
2236a9aa8137SNico Weber   size_t str_off;
2237a9aa8137SNico Weber   size_t size;
2238a9aa8137SNico Weber   const char *fmt_start;
2239a9aa8137SNico Weber   const char *fmt_cur;
2240a9aa8137SNico Weber   int width;
22418dbcf8ebSTomasz Kuchta   int num_scanned;
2242368d7493SAndrew Browne   bool skip;
2243a9aa8137SNico Weber };
2244a9aa8137SNico Weber 
2245a9aa8137SNico Weber // Formats the input and propagates the input labels to the output. The output
2246a9aa8137SNico Weber // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
2247a9aa8137SNico Weber // 'ap' are the format string and the list of arguments for formatting. Returns
2248a9aa8137SNico Weber // the return value vsnprintf would return.
2249a9aa8137SNico Weber //
2250a9aa8137SNico Weber // The function tokenizes the format string in chunks representing either a
2251a9aa8137SNico Weber // constant string or a single format directive (e.g., '%.3f') and formats each
2252a9aa8137SNico Weber // chunk independently into the output string. This approach allows to figure
2253a9aa8137SNico Weber // out which bytes of the output string depends on which argument and thus to
2254a9aa8137SNico Weber // propagate labels more precisely.
2255a9aa8137SNico Weber //
2256a9aa8137SNico Weber // WARNING: This implementation does not support conversion specifiers with
2257a9aa8137SNico Weber // positional arguments.
2258a9aa8137SNico Weber static int format_buffer(char *str, size_t size, const char *fmt,
2259a9aa8137SNico Weber                          dfsan_label *va_labels, dfsan_label *ret_label,
226091516925SJianzhou Zhao                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
2261a9aa8137SNico Weber                          va_list ap) {
2262a9aa8137SNico Weber   Formatter formatter(str, fmt, size);
2263a9aa8137SNico Weber 
2264a9aa8137SNico Weber   while (*formatter.fmt_cur) {
2265a9aa8137SNico Weber     formatter.fmt_start = formatter.fmt_cur;
2266a9aa8137SNico Weber     formatter.width = -1;
2267a9aa8137SNico Weber     int retval = 0;
2268a9aa8137SNico Weber 
2269a9aa8137SNico Weber     if (*formatter.fmt_cur != '%') {
2270a9aa8137SNico Weber       // Ordinary character. Consume all the characters until a '%' or the end
2271a9aa8137SNico Weber       // of the string.
2272a9aa8137SNico Weber       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
2273a9aa8137SNico Weber            ++formatter.fmt_cur) {}
2274a9aa8137SNico Weber       retval = formatter.format();
2275a9aa8137SNico Weber       dfsan_set_label(0, formatter.str_cur(),
2276a9aa8137SNico Weber                       formatter.num_written_bytes(retval));
2277a9aa8137SNico Weber     } else {
2278a9aa8137SNico Weber       // Conversion directive. Consume all the characters until a conversion
2279a9aa8137SNico Weber       // specifier or the end of the string.
2280a9aa8137SNico Weber       bool end_fmt = false;
2281a9aa8137SNico Weber       for (; *formatter.fmt_cur && !end_fmt; ) {
2282a9aa8137SNico Weber         switch (*++formatter.fmt_cur) {
2283a9aa8137SNico Weber         case 'd':
2284a9aa8137SNico Weber         case 'i':
2285a9aa8137SNico Weber         case 'o':
2286a9aa8137SNico Weber         case 'u':
2287a9aa8137SNico Weber         case 'x':
2288a9aa8137SNico Weber         case 'X':
2289a9aa8137SNico Weber           switch (*(formatter.fmt_cur - 1)) {
2290a9aa8137SNico Weber           case 'h':
2291a9aa8137SNico Weber             // Also covers the 'hh' case (since the size of the arg is still
2292a9aa8137SNico Weber             // an int).
2293a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, int));
2294a9aa8137SNico Weber             break;
2295a9aa8137SNico Weber           case 'l':
2296a9aa8137SNico Weber             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
2297a9aa8137SNico Weber                 *(formatter.fmt_cur - 2) == 'l') {
2298a9aa8137SNico Weber               retval = formatter.format(va_arg(ap, long long int));
2299a9aa8137SNico Weber             } else {
2300a9aa8137SNico Weber               retval = formatter.format(va_arg(ap, long int));
2301a9aa8137SNico Weber             }
2302a9aa8137SNico Weber             break;
2303a9aa8137SNico Weber           case 'q':
2304a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, long long int));
2305a9aa8137SNico Weber             break;
2306a9aa8137SNico Weber           case 'j':
2307a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, intmax_t));
2308a9aa8137SNico Weber             break;
2309a9aa8137SNico Weber           case 'z':
2310a9aa8137SNico Weber           case 't':
2311a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, size_t));
2312a9aa8137SNico Weber             break;
2313a9aa8137SNico Weber           default:
2314a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, int));
2315a9aa8137SNico Weber           }
231691516925SJianzhou Zhao           if (va_origins == nullptr)
2317a9aa8137SNico Weber             dfsan_set_label(*va_labels++, formatter.str_cur(),
2318a9aa8137SNico Weber                             formatter.num_written_bytes(retval));
231991516925SJianzhou Zhao           else
232091516925SJianzhou Zhao             dfsan_set_label_origin(*va_labels++, *va_origins++,
232191516925SJianzhou Zhao                                    formatter.str_cur(),
232291516925SJianzhou Zhao                                    formatter.num_written_bytes(retval));
2323a9aa8137SNico Weber           end_fmt = true;
2324a9aa8137SNico Weber           break;
2325a9aa8137SNico Weber 
2326a9aa8137SNico Weber         case 'a':
2327a9aa8137SNico Weber         case 'A':
2328a9aa8137SNico Weber         case 'e':
2329a9aa8137SNico Weber         case 'E':
2330a9aa8137SNico Weber         case 'f':
2331a9aa8137SNico Weber         case 'F':
2332a9aa8137SNico Weber         case 'g':
2333a9aa8137SNico Weber         case 'G':
2334a9aa8137SNico Weber           if (*(formatter.fmt_cur - 1) == 'L') {
2335a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, long double));
2336a9aa8137SNico Weber           } else {
2337a9aa8137SNico Weber             retval = formatter.format(va_arg(ap, double));
2338a9aa8137SNico Weber           }
233991516925SJianzhou Zhao           if (va_origins == nullptr)
2340a9aa8137SNico Weber             dfsan_set_label(*va_labels++, formatter.str_cur(),
2341a9aa8137SNico Weber                             formatter.num_written_bytes(retval));
234291516925SJianzhou Zhao           else
234391516925SJianzhou Zhao             dfsan_set_label_origin(*va_labels++, *va_origins++,
234491516925SJianzhou Zhao                                    formatter.str_cur(),
234591516925SJianzhou Zhao                                    formatter.num_written_bytes(retval));
2346a9aa8137SNico Weber           end_fmt = true;
2347a9aa8137SNico Weber           break;
2348a9aa8137SNico Weber 
2349a9aa8137SNico Weber         case 'c':
2350a9aa8137SNico Weber           retval = formatter.format(va_arg(ap, int));
235191516925SJianzhou Zhao           if (va_origins == nullptr)
2352a9aa8137SNico Weber             dfsan_set_label(*va_labels++, formatter.str_cur(),
2353a9aa8137SNico Weber                             formatter.num_written_bytes(retval));
235491516925SJianzhou Zhao           else
235591516925SJianzhou Zhao             dfsan_set_label_origin(*va_labels++, *va_origins++,
235691516925SJianzhou Zhao                                    formatter.str_cur(),
235791516925SJianzhou Zhao                                    formatter.num_written_bytes(retval));
2358a9aa8137SNico Weber           end_fmt = true;
2359a9aa8137SNico Weber           break;
2360a9aa8137SNico Weber 
2361a9aa8137SNico Weber         case 's': {
2362a9aa8137SNico Weber           char *arg = va_arg(ap, char *);
2363a9aa8137SNico Weber           retval = formatter.format(arg);
236491516925SJianzhou Zhao           if (va_origins) {
236591516925SJianzhou Zhao             va_origins++;
236691516925SJianzhou Zhao             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
236791516925SJianzhou Zhao                                       formatter.num_written_bytes(retval));
236891516925SJianzhou Zhao           }
2369a9aa8137SNico Weber           va_labels++;
237032167bfeSAndrew Browne           dfsan_mem_shadow_transfer(formatter.str_cur(), arg,
2371a9aa8137SNico Weber                                     formatter.num_written_bytes(retval));
2372a9aa8137SNico Weber           end_fmt = true;
2373a9aa8137SNico Weber           break;
2374a9aa8137SNico Weber         }
2375a9aa8137SNico Weber 
2376a9aa8137SNico Weber         case 'p':
2377a9aa8137SNico Weber           retval = formatter.format(va_arg(ap, void *));
237891516925SJianzhou Zhao           if (va_origins == nullptr)
2379a9aa8137SNico Weber             dfsan_set_label(*va_labels++, formatter.str_cur(),
2380a9aa8137SNico Weber                             formatter.num_written_bytes(retval));
238191516925SJianzhou Zhao           else
238291516925SJianzhou Zhao             dfsan_set_label_origin(*va_labels++, *va_origins++,
238391516925SJianzhou Zhao                                    formatter.str_cur(),
238491516925SJianzhou Zhao                                    formatter.num_written_bytes(retval));
2385a9aa8137SNico Weber           end_fmt = true;
2386a9aa8137SNico Weber           break;
2387a9aa8137SNico Weber 
2388a9aa8137SNico Weber         case 'n': {
2389a9aa8137SNico Weber           int *ptr = va_arg(ap, int *);
2390a9aa8137SNico Weber           *ptr = (int)formatter.str_off;
2391a9aa8137SNico Weber           va_labels++;
239291516925SJianzhou Zhao           if (va_origins)
239391516925SJianzhou Zhao             va_origins++;
2394a9aa8137SNico Weber           dfsan_set_label(0, ptr, sizeof(ptr));
2395a9aa8137SNico Weber           end_fmt = true;
2396a9aa8137SNico Weber           break;
2397a9aa8137SNico Weber         }
2398a9aa8137SNico Weber 
2399a9aa8137SNico Weber         case '%':
2400a9aa8137SNico Weber           retval = formatter.format();
2401a9aa8137SNico Weber           dfsan_set_label(0, formatter.str_cur(),
2402a9aa8137SNico Weber                           formatter.num_written_bytes(retval));
2403a9aa8137SNico Weber           end_fmt = true;
2404a9aa8137SNico Weber           break;
2405a9aa8137SNico Weber 
2406a9aa8137SNico Weber         case '*':
2407a9aa8137SNico Weber           formatter.width = va_arg(ap, int);
2408a9aa8137SNico Weber           va_labels++;
240991516925SJianzhou Zhao           if (va_origins)
241091516925SJianzhou Zhao             va_origins++;
2411a9aa8137SNico Weber           break;
2412a9aa8137SNico Weber 
2413a9aa8137SNico Weber         default:
2414a9aa8137SNico Weber           break;
2415a9aa8137SNico Weber         }
2416a9aa8137SNico Weber       }
2417a9aa8137SNico Weber     }
2418a9aa8137SNico Weber 
2419a9aa8137SNico Weber     if (retval < 0) {
2420a9aa8137SNico Weber       return retval;
2421a9aa8137SNico Weber     }
2422a9aa8137SNico Weber 
2423a9aa8137SNico Weber     formatter.fmt_cur++;
2424a9aa8137SNico Weber     formatter.str_off += retval;
2425a9aa8137SNico Weber   }
2426a9aa8137SNico Weber 
2427a9aa8137SNico Weber   *ret_label = 0;
242891516925SJianzhou Zhao   if (ret_origin)
242991516925SJianzhou Zhao     *ret_origin = 0;
2430a9aa8137SNico Weber 
2431a9aa8137SNico Weber   // Number of bytes written in total.
2432a9aa8137SNico Weber   return formatter.str_off;
2433a9aa8137SNico Weber }
2434a9aa8137SNico Weber 
2435cd94fa7eSAndrew Browne // Scans a chunk either a constant string or a single format directive (e.g.,
2436cd94fa7eSAndrew Browne // '%.3f').
2437cd94fa7eSAndrew Browne struct Scanner {
2438cd94fa7eSAndrew Browne   Scanner(char *str_, const char *fmt_, size_t size_)
2439cd94fa7eSAndrew Browne       : str(str_),
2440cd94fa7eSAndrew Browne         str_off(0),
2441cd94fa7eSAndrew Browne         size(size_),
2442cd94fa7eSAndrew Browne         fmt_start(fmt_),
2443cd94fa7eSAndrew Browne         fmt_cur(fmt_),
2444cd94fa7eSAndrew Browne         width(-1),
2445cd94fa7eSAndrew Browne         num_scanned(0),
2446cd94fa7eSAndrew Browne         skip(false) {}
2447cd94fa7eSAndrew Browne 
2448cd94fa7eSAndrew Browne   // Consumes a chunk of ordinary characters.
2449cd94fa7eSAndrew Browne   // Returns number of matching ordinary characters.
2450cd94fa7eSAndrew Browne   // Returns -1 if the match failed.
2451cd94fa7eSAndrew Browne   // In format strings, a space will match multiple spaces.
2452cd94fa7eSAndrew Browne   int check_match_ordinary() {
2453cd94fa7eSAndrew Browne     char *tmp_fmt = build_format_string_with_n();
2454cd94fa7eSAndrew Browne     int read_count = -1;
2455cd94fa7eSAndrew Browne     sscanf(str + str_off, tmp_fmt, &read_count);
2456cd94fa7eSAndrew Browne     free(tmp_fmt);
2457cd94fa7eSAndrew Browne     if (read_count > 0) {
2458cd94fa7eSAndrew Browne       str_off += read_count;
2459cd94fa7eSAndrew Browne     }
2460cd94fa7eSAndrew Browne     return read_count;
2461cd94fa7eSAndrew Browne   }
2462cd94fa7eSAndrew Browne 
2463cd94fa7eSAndrew Browne   int scan() {
2464cd94fa7eSAndrew Browne     char *tmp_fmt = build_format_string_with_n();
2465cd94fa7eSAndrew Browne     int read_count = 0;
2466cd94fa7eSAndrew Browne     int retval = sscanf(str + str_off, tmp_fmt, &read_count);
2467cd94fa7eSAndrew Browne     free(tmp_fmt);
2468cd94fa7eSAndrew Browne     if (retval > 0) {
2469cd94fa7eSAndrew Browne       num_scanned += retval;
2470cd94fa7eSAndrew Browne     }
2471cd94fa7eSAndrew Browne     return read_count;
2472cd94fa7eSAndrew Browne   }
2473cd94fa7eSAndrew Browne 
2474cd94fa7eSAndrew Browne   template <typename T>
2475cd94fa7eSAndrew Browne   int scan(T arg) {
2476cd94fa7eSAndrew Browne     char *tmp_fmt = build_format_string_with_n();
2477cd94fa7eSAndrew Browne     int read_count = 0;
2478cd94fa7eSAndrew Browne     int retval = sscanf(str + str_off, tmp_fmt, arg, &read_count);
2479cd94fa7eSAndrew Browne     free(tmp_fmt);
2480cd94fa7eSAndrew Browne     if (retval > 0) {
2481cd94fa7eSAndrew Browne       num_scanned += retval;
2482cd94fa7eSAndrew Browne     }
2483cd94fa7eSAndrew Browne     return read_count;
2484cd94fa7eSAndrew Browne   }
2485cd94fa7eSAndrew Browne 
2486cd94fa7eSAndrew Browne   // Adds %n onto current format string to measure length.
2487cd94fa7eSAndrew Browne   char *build_format_string_with_n() {
2488cd94fa7eSAndrew Browne     size_t fmt_size = fmt_cur - fmt_start + 1;
2489cd94fa7eSAndrew Browne     // +2 for %n, +1 for \0
2490cd94fa7eSAndrew Browne     char *new_fmt = (char *)malloc(fmt_size + 2 + 1);
2491cd94fa7eSAndrew Browne     assert(new_fmt);
2492cd94fa7eSAndrew Browne     internal_memcpy(new_fmt, fmt_start, fmt_size);
2493cd94fa7eSAndrew Browne     new_fmt[fmt_size] = '%';
2494cd94fa7eSAndrew Browne     new_fmt[fmt_size + 1] = 'n';
2495cd94fa7eSAndrew Browne     new_fmt[fmt_size + 2] = '\0';
2496cd94fa7eSAndrew Browne     return new_fmt;
2497cd94fa7eSAndrew Browne   }
2498cd94fa7eSAndrew Browne 
2499cd94fa7eSAndrew Browne   char *str_cur() { return str + str_off; }
2500cd94fa7eSAndrew Browne 
2501cd94fa7eSAndrew Browne   size_t num_written_bytes(int retval) {
2502cd94fa7eSAndrew Browne     if (retval < 0) {
2503cd94fa7eSAndrew Browne       return 0;
2504cd94fa7eSAndrew Browne     }
2505cd94fa7eSAndrew Browne 
2506cd94fa7eSAndrew Browne     size_t num_avail = str_off < size ? size - str_off : 0;
2507cd94fa7eSAndrew Browne     if (num_avail == 0) {
2508cd94fa7eSAndrew Browne       return 0;
2509cd94fa7eSAndrew Browne     }
2510cd94fa7eSAndrew Browne 
2511cd94fa7eSAndrew Browne     size_t num_written = retval;
2512cd94fa7eSAndrew Browne     // A return value of {v,}snprintf of size or more means that the output was
2513cd94fa7eSAndrew Browne     // truncated.
2514cd94fa7eSAndrew Browne     if (num_written >= num_avail) {
2515cd94fa7eSAndrew Browne       num_written -= num_avail;
2516cd94fa7eSAndrew Browne     }
2517cd94fa7eSAndrew Browne 
2518cd94fa7eSAndrew Browne     return num_written;
2519cd94fa7eSAndrew Browne   }
2520cd94fa7eSAndrew Browne 
2521cd94fa7eSAndrew Browne   char *str;
2522cd94fa7eSAndrew Browne   size_t str_off;
2523cd94fa7eSAndrew Browne   size_t size;
2524cd94fa7eSAndrew Browne   const char *fmt_start;
2525cd94fa7eSAndrew Browne   const char *fmt_cur;
2526cd94fa7eSAndrew Browne   int width;
2527cd94fa7eSAndrew Browne   int num_scanned;
2528cd94fa7eSAndrew Browne   bool skip;
2529cd94fa7eSAndrew Browne };
2530cd94fa7eSAndrew Browne 
25318dbcf8ebSTomasz Kuchta // This function is an inverse of format_buffer: we take the input buffer,
25328dbcf8ebSTomasz Kuchta // scan it in search for format strings and store the results in the varargs.
25338dbcf8ebSTomasz Kuchta // The labels are propagated from the input buffer to the varargs.
25348dbcf8ebSTomasz Kuchta static int scan_buffer(char *str, size_t size, const char *fmt,
25358dbcf8ebSTomasz Kuchta                        dfsan_label *va_labels, dfsan_label *ret_label,
25368dbcf8ebSTomasz Kuchta                        dfsan_origin *str_origin, dfsan_origin *ret_origin,
25378dbcf8ebSTomasz Kuchta                        va_list ap) {
2538cd94fa7eSAndrew Browne   Scanner scanner(str, fmt, size);
2539cd94fa7eSAndrew Browne   while (*scanner.fmt_cur) {
2540cd94fa7eSAndrew Browne     scanner.fmt_start = scanner.fmt_cur;
2541cd94fa7eSAndrew Browne     scanner.width = -1;
2542cd94fa7eSAndrew Browne     scanner.skip = false;
2543368d7493SAndrew Browne     int read_count = 0;
25448dbcf8ebSTomasz Kuchta     void *dst_ptr = 0;
25458dbcf8ebSTomasz Kuchta     size_t write_size = 0;
2546cd94fa7eSAndrew Browne     if (*scanner.fmt_cur != '%') {
2547cd94fa7eSAndrew Browne       // Ordinary character and spaces.
2548cd94fa7eSAndrew Browne       // Consume all the characters until a '%' or the end of the string.
2549cd94fa7eSAndrew Browne       for (; *(scanner.fmt_cur + 1) && *(scanner.fmt_cur + 1) != '%';
2550cd94fa7eSAndrew Browne            ++scanner.fmt_cur) {
25518dbcf8ebSTomasz Kuchta       }
2552cd94fa7eSAndrew Browne       if (scanner.check_match_ordinary() < 0) {
2553cd94fa7eSAndrew Browne         // The ordinary characters did not match.
2554cd94fa7eSAndrew Browne         break;
2555cd94fa7eSAndrew Browne       }
25568dbcf8ebSTomasz Kuchta     } else {
25578dbcf8ebSTomasz Kuchta       // Conversion directive. Consume all the characters until a conversion
25588dbcf8ebSTomasz Kuchta       // specifier or the end of the string.
25598dbcf8ebSTomasz Kuchta       bool end_fmt = false;
2560cd94fa7eSAndrew Browne       for (; *scanner.fmt_cur && !end_fmt;) {
2561cd94fa7eSAndrew Browne         switch (*++scanner.fmt_cur) {
25628dbcf8ebSTomasz Kuchta           case 'd':
25638dbcf8ebSTomasz Kuchta           case 'i':
25648dbcf8ebSTomasz Kuchta           case 'o':
25658dbcf8ebSTomasz Kuchta           case 'u':
25668dbcf8ebSTomasz Kuchta           case 'x':
25678dbcf8ebSTomasz Kuchta           case 'X':
2568cd94fa7eSAndrew Browne             if (scanner.skip) {
2569cd94fa7eSAndrew Browne               read_count = scanner.scan();
2570368d7493SAndrew Browne             } else {
2571cd94fa7eSAndrew Browne               switch (*(scanner.fmt_cur - 1)) {
25728dbcf8ebSTomasz Kuchta                 case 'h':
2573cd94fa7eSAndrew Browne                   // Also covers the 'hh' case (since the size of the arg is
2574cd94fa7eSAndrew Browne                   // still an int).
25758dbcf8ebSTomasz Kuchta                   dst_ptr = va_arg(ap, int *);
2576cd94fa7eSAndrew Browne                   read_count = scanner.scan((int *)dst_ptr);
25778dbcf8ebSTomasz Kuchta                   write_size = sizeof(int);
25788dbcf8ebSTomasz Kuchta                   break;
25798dbcf8ebSTomasz Kuchta                 case 'l':
2580cd94fa7eSAndrew Browne                   if (scanner.fmt_cur - scanner.fmt_start >= 2 &&
2581cd94fa7eSAndrew Browne                       *(scanner.fmt_cur - 2) == 'l') {
25828dbcf8ebSTomasz Kuchta                     dst_ptr = va_arg(ap, long long int *);
2583cd94fa7eSAndrew Browne                     read_count = scanner.scan((long long int *)dst_ptr);
25848dbcf8ebSTomasz Kuchta                     write_size = sizeof(long long int);
25858dbcf8ebSTomasz Kuchta                   } else {
25868dbcf8ebSTomasz Kuchta                     dst_ptr = va_arg(ap, long int *);
2587cd94fa7eSAndrew Browne                     read_count = scanner.scan((long int *)dst_ptr);
25888dbcf8ebSTomasz Kuchta                     write_size = sizeof(long int);
25898dbcf8ebSTomasz Kuchta                   }
25908dbcf8ebSTomasz Kuchta                   break;
25918dbcf8ebSTomasz Kuchta                 case 'q':
25928dbcf8ebSTomasz Kuchta                   dst_ptr = va_arg(ap, long long int *);
2593cd94fa7eSAndrew Browne                   read_count = scanner.scan((long long int *)dst_ptr);
25948dbcf8ebSTomasz Kuchta                   write_size = sizeof(long long int);
25958dbcf8ebSTomasz Kuchta                   break;
25968dbcf8ebSTomasz Kuchta                 case 'j':
25978dbcf8ebSTomasz Kuchta                   dst_ptr = va_arg(ap, intmax_t *);
2598cd94fa7eSAndrew Browne                   read_count = scanner.scan((intmax_t *)dst_ptr);
25998dbcf8ebSTomasz Kuchta                   write_size = sizeof(intmax_t);
26008dbcf8ebSTomasz Kuchta                   break;
26018dbcf8ebSTomasz Kuchta                 case 'z':
26028dbcf8ebSTomasz Kuchta                 case 't':
26038dbcf8ebSTomasz Kuchta                   dst_ptr = va_arg(ap, size_t *);
2604cd94fa7eSAndrew Browne                   read_count = scanner.scan((size_t *)dst_ptr);
26058dbcf8ebSTomasz Kuchta                   write_size = sizeof(size_t);
26068dbcf8ebSTomasz Kuchta                   break;
26078dbcf8ebSTomasz Kuchta                 default:
26088dbcf8ebSTomasz Kuchta                   dst_ptr = va_arg(ap, int *);
2609cd94fa7eSAndrew Browne                   read_count = scanner.scan((int *)dst_ptr);
26108dbcf8ebSTomasz Kuchta                   write_size = sizeof(int);
26118dbcf8ebSTomasz Kuchta               }
26128dbcf8ebSTomasz Kuchta               // get the label associated with the string at the corresponding
26138dbcf8ebSTomasz Kuchta               // place
2614368d7493SAndrew Browne               dfsan_label l = dfsan_read_label(
2615cd94fa7eSAndrew Browne                   scanner.str_cur(), scanner.num_written_bytes(read_count));
26168dbcf8ebSTomasz Kuchta               dfsan_set_label(l, dst_ptr, write_size);
2617368d7493SAndrew Browne               if (str_origin != nullptr) {
26188dbcf8ebSTomasz Kuchta                 dfsan_set_label(l, dst_ptr, write_size);
2619cd94fa7eSAndrew Browne                 size_t scan_count = scanner.num_written_bytes(read_count);
26208dbcf8ebSTomasz Kuchta                 size_t size = scan_count > write_size ? write_size : scan_count;
2621cd94fa7eSAndrew Browne                 dfsan_mem_origin_transfer(dst_ptr, scanner.str_cur(), size);
26228dbcf8ebSTomasz Kuchta               }
2623368d7493SAndrew Browne             }
26248dbcf8ebSTomasz Kuchta             end_fmt = true;
26258dbcf8ebSTomasz Kuchta 
26268dbcf8ebSTomasz Kuchta             break;
26278dbcf8ebSTomasz Kuchta 
26288dbcf8ebSTomasz Kuchta           case 'a':
26298dbcf8ebSTomasz Kuchta           case 'A':
26308dbcf8ebSTomasz Kuchta           case 'e':
26318dbcf8ebSTomasz Kuchta           case 'E':
26328dbcf8ebSTomasz Kuchta           case 'f':
26338dbcf8ebSTomasz Kuchta           case 'F':
26348dbcf8ebSTomasz Kuchta           case 'g':
26358dbcf8ebSTomasz Kuchta           case 'G':
2636cd94fa7eSAndrew Browne             if (scanner.skip) {
2637cd94fa7eSAndrew Browne               read_count = scanner.scan();
2638368d7493SAndrew Browne             } else {
2639cd94fa7eSAndrew Browne               if (*(scanner.fmt_cur - 1) == 'L') {
26408dbcf8ebSTomasz Kuchta                 dst_ptr = va_arg(ap, long double *);
2641cd94fa7eSAndrew Browne                 read_count = scanner.scan((long double *)dst_ptr);
26428dbcf8ebSTomasz Kuchta                 write_size = sizeof(long double);
2643cd94fa7eSAndrew Browne               } else if (*(scanner.fmt_cur - 1) == 'l') {
26448dbcf8ebSTomasz Kuchta                 dst_ptr = va_arg(ap, double *);
2645cd94fa7eSAndrew Browne                 read_count = scanner.scan((double *)dst_ptr);
26468dbcf8ebSTomasz Kuchta                 write_size = sizeof(double);
26478dbcf8ebSTomasz Kuchta               } else {
26488dbcf8ebSTomasz Kuchta                 dst_ptr = va_arg(ap, float *);
2649cd94fa7eSAndrew Browne                 read_count = scanner.scan((float *)dst_ptr);
26508dbcf8ebSTomasz Kuchta                 write_size = sizeof(float);
26518dbcf8ebSTomasz Kuchta               }
2652368d7493SAndrew Browne               dfsan_label l = dfsan_read_label(
2653cd94fa7eSAndrew Browne                   scanner.str_cur(), scanner.num_written_bytes(read_count));
26548dbcf8ebSTomasz Kuchta               dfsan_set_label(l, dst_ptr, write_size);
2655368d7493SAndrew Browne               if (str_origin != nullptr) {
26568dbcf8ebSTomasz Kuchta                 dfsan_set_label(l, dst_ptr, write_size);
2657cd94fa7eSAndrew Browne                 size_t scan_count = scanner.num_written_bytes(read_count);
26588dbcf8ebSTomasz Kuchta                 size_t size = scan_count > write_size ? write_size : scan_count;
2659cd94fa7eSAndrew Browne                 dfsan_mem_origin_transfer(dst_ptr, scanner.str_cur(), size);
26608dbcf8ebSTomasz Kuchta               }
2661368d7493SAndrew Browne             }
26628dbcf8ebSTomasz Kuchta             end_fmt = true;
26638dbcf8ebSTomasz Kuchta             break;
26648dbcf8ebSTomasz Kuchta 
26658dbcf8ebSTomasz Kuchta           case 'c':
2666cd94fa7eSAndrew Browne             if (scanner.skip) {
2667cd94fa7eSAndrew Browne               read_count = scanner.scan();
2668368d7493SAndrew Browne             } else {
26698dbcf8ebSTomasz Kuchta               dst_ptr = va_arg(ap, char *);
2670cd94fa7eSAndrew Browne               read_count = scanner.scan((char *)dst_ptr);
26718dbcf8ebSTomasz Kuchta               write_size = sizeof(char);
2672368d7493SAndrew Browne               dfsan_label l = dfsan_read_label(
2673cd94fa7eSAndrew Browne                   scanner.str_cur(), scanner.num_written_bytes(read_count));
26748dbcf8ebSTomasz Kuchta               dfsan_set_label(l, dst_ptr, write_size);
2675368d7493SAndrew Browne               if (str_origin != nullptr) {
2676cd94fa7eSAndrew Browne                 size_t scan_count = scanner.num_written_bytes(read_count);
26778dbcf8ebSTomasz Kuchta                 size_t size = scan_count > write_size ? write_size : scan_count;
2678cd94fa7eSAndrew Browne                 dfsan_mem_origin_transfer(dst_ptr, scanner.str_cur(), size);
26798dbcf8ebSTomasz Kuchta               }
2680368d7493SAndrew Browne             }
26818dbcf8ebSTomasz Kuchta             end_fmt = true;
26828dbcf8ebSTomasz Kuchta             break;
26838dbcf8ebSTomasz Kuchta 
26848dbcf8ebSTomasz Kuchta           case 's': {
2685cd94fa7eSAndrew Browne             if (scanner.skip) {
2686cd94fa7eSAndrew Browne               read_count = scanner.scan();
2687368d7493SAndrew Browne             } else {
26888dbcf8ebSTomasz Kuchta               dst_ptr = va_arg(ap, char *);
2689cd94fa7eSAndrew Browne               read_count = scanner.scan((char *)dst_ptr);
2690368d7493SAndrew Browne               if (1 == read_count) {
26918dbcf8ebSTomasz Kuchta                 // special case: we have parsed a single string and we need to
2692368d7493SAndrew Browne                 // update read_count with the string size
2693368d7493SAndrew Browne                 read_count = strlen((char *)dst_ptr);
26948dbcf8ebSTomasz Kuchta               }
26958dbcf8ebSTomasz Kuchta               if (str_origin)
2696cd94fa7eSAndrew Browne                 dfsan_mem_origin_transfer(
2697cd94fa7eSAndrew Browne                     dst_ptr, scanner.str_cur(),
2698cd94fa7eSAndrew Browne                     scanner.num_written_bytes(read_count));
26998dbcf8ebSTomasz Kuchta               va_labels++;
2700cd94fa7eSAndrew Browne               dfsan_mem_shadow_transfer(dst_ptr, scanner.str_cur(),
2701cd94fa7eSAndrew Browne                                         scanner.num_written_bytes(read_count));
2702368d7493SAndrew Browne             }
27038dbcf8ebSTomasz Kuchta             end_fmt = true;
27048dbcf8ebSTomasz Kuchta             break;
27058dbcf8ebSTomasz Kuchta           }
27068dbcf8ebSTomasz Kuchta 
27078dbcf8ebSTomasz Kuchta           case 'p':
2708cd94fa7eSAndrew Browne             if (scanner.skip) {
2709cd94fa7eSAndrew Browne               read_count = scanner.scan();
2710368d7493SAndrew Browne             } else {
27118dbcf8ebSTomasz Kuchta               dst_ptr = va_arg(ap, void *);
2712368d7493SAndrew Browne               read_count =
2713cd94fa7eSAndrew Browne                   scanner.scan((int *)dst_ptr);  // note: changing void* to int*
27148dbcf8ebSTomasz Kuchta                                                  // since we need to call sizeof
27158dbcf8ebSTomasz Kuchta               write_size = sizeof(int);
27168dbcf8ebSTomasz Kuchta 
2717368d7493SAndrew Browne               dfsan_label l = dfsan_read_label(
2718cd94fa7eSAndrew Browne                   scanner.str_cur(), scanner.num_written_bytes(read_count));
27198dbcf8ebSTomasz Kuchta               dfsan_set_label(l, dst_ptr, write_size);
2720368d7493SAndrew Browne               if (str_origin != nullptr) {
27218dbcf8ebSTomasz Kuchta                 dfsan_set_label(l, dst_ptr, write_size);
2722cd94fa7eSAndrew Browne                 size_t scan_count = scanner.num_written_bytes(read_count);
27238dbcf8ebSTomasz Kuchta                 size_t size = scan_count > write_size ? write_size : scan_count;
2724cd94fa7eSAndrew Browne                 dfsan_mem_origin_transfer(dst_ptr, scanner.str_cur(), size);
27258dbcf8ebSTomasz Kuchta               }
2726368d7493SAndrew Browne             }
27278dbcf8ebSTomasz Kuchta             end_fmt = true;
27288dbcf8ebSTomasz Kuchta             break;
27298dbcf8ebSTomasz Kuchta 
27308dbcf8ebSTomasz Kuchta           case 'n': {
2731cd94fa7eSAndrew Browne             if (!scanner.skip) {
27328dbcf8ebSTomasz Kuchta               int *ptr = va_arg(ap, int *);
2733cd94fa7eSAndrew Browne               *ptr = (int)scanner.str_off;
2734368d7493SAndrew Browne               *va_labels++ = 0;
27358dbcf8ebSTomasz Kuchta               dfsan_set_label(0, ptr, sizeof(*ptr));
2736368d7493SAndrew Browne               if (str_origin != nullptr)
2737368d7493SAndrew Browne                 *str_origin++ = 0;
2738368d7493SAndrew Browne             }
27398dbcf8ebSTomasz Kuchta             end_fmt = true;
27408dbcf8ebSTomasz Kuchta             break;
27418dbcf8ebSTomasz Kuchta           }
27428dbcf8ebSTomasz Kuchta 
27438dbcf8ebSTomasz Kuchta           case '%':
2744cd94fa7eSAndrew Browne             read_count = scanner.scan();
27458dbcf8ebSTomasz Kuchta             end_fmt = true;
27468dbcf8ebSTomasz Kuchta             break;
27478dbcf8ebSTomasz Kuchta 
27488dbcf8ebSTomasz Kuchta           case '*':
2749cd94fa7eSAndrew Browne             scanner.skip = true;
27508dbcf8ebSTomasz Kuchta             break;
27518dbcf8ebSTomasz Kuchta 
27528dbcf8ebSTomasz Kuchta           default:
27538dbcf8ebSTomasz Kuchta             break;
27548dbcf8ebSTomasz Kuchta         }
27558dbcf8ebSTomasz Kuchta       }
27568dbcf8ebSTomasz Kuchta     }
27578dbcf8ebSTomasz Kuchta 
2758368d7493SAndrew Browne     if (read_count < 0) {
2759368d7493SAndrew Browne       // There was an error.
2760368d7493SAndrew Browne       return read_count;
27618dbcf8ebSTomasz Kuchta     }
27628dbcf8ebSTomasz Kuchta 
2763cd94fa7eSAndrew Browne     scanner.fmt_cur++;
2764cd94fa7eSAndrew Browne     scanner.str_off += read_count;
27658dbcf8ebSTomasz Kuchta   }
27668dbcf8ebSTomasz Kuchta 
27671438544eSJie Fu   (void)va_labels; // Silence unused-but-set-parameter warning
27688dbcf8ebSTomasz Kuchta   *ret_label = 0;
27698dbcf8ebSTomasz Kuchta   if (ret_origin)
27708dbcf8ebSTomasz Kuchta     *ret_origin = 0;
27718dbcf8ebSTomasz Kuchta 
27728dbcf8ebSTomasz Kuchta   // Number of items scanned in total.
2773cd94fa7eSAndrew Browne   return scanner.num_scanned;
27748dbcf8ebSTomasz Kuchta }
27758dbcf8ebSTomasz Kuchta 
2776a9aa8137SNico Weber extern "C" {
2777a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
2778a9aa8137SNico Weber int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
2779a9aa8137SNico Weber                    dfsan_label format_label, dfsan_label *va_labels,
2780a9aa8137SNico Weber                    dfsan_label *ret_label, ...) {
2781a9aa8137SNico Weber   va_list ap;
2782a9aa8137SNico Weber   va_start(ap, ret_label);
27838dbcf8ebSTomasz Kuchta 
278467e0f410SFangrui Song   int ret = format_buffer(str, INT32_MAX, format, va_labels, ret_label, nullptr,
278591516925SJianzhou Zhao                           nullptr, ap);
278691516925SJianzhou Zhao   va_end(ap);
278791516925SJianzhou Zhao   return ret;
278891516925SJianzhou Zhao }
278991516925SJianzhou Zhao 
279091516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
279191516925SJianzhou Zhao int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
279291516925SJianzhou Zhao                    dfsan_label format_label, dfsan_label *va_labels,
279391516925SJianzhou Zhao                    dfsan_label *ret_label, dfsan_origin str_origin,
279491516925SJianzhou Zhao                    dfsan_origin format_origin, dfsan_origin *va_origins,
279591516925SJianzhou Zhao                    dfsan_origin *ret_origin, ...) {
279691516925SJianzhou Zhao   va_list ap;
279791516925SJianzhou Zhao   va_start(ap, ret_origin);
279867e0f410SFangrui Song   int ret = format_buffer(str, INT32_MAX, format, va_labels, ret_label,
279967e0f410SFangrui Song                           va_origins, ret_origin, ap);
2800a9aa8137SNico Weber   va_end(ap);
2801a9aa8137SNico Weber   return ret;
2802a9aa8137SNico Weber }
2803a9aa8137SNico Weber 
2804a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
2805a9aa8137SNico Weber int __dfsw_snprintf(char *str, size_t size, const char *format,
2806a9aa8137SNico Weber                     dfsan_label str_label, dfsan_label size_label,
2807a9aa8137SNico Weber                     dfsan_label format_label, dfsan_label *va_labels,
2808a9aa8137SNico Weber                     dfsan_label *ret_label, ...) {
2809a9aa8137SNico Weber   va_list ap;
2810a9aa8137SNico Weber   va_start(ap, ret_label);
281191516925SJianzhou Zhao   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
281291516925SJianzhou Zhao                           nullptr, ap);
281391516925SJianzhou Zhao   va_end(ap);
281491516925SJianzhou Zhao   return ret;
281591516925SJianzhou Zhao }
281691516925SJianzhou Zhao 
281791516925SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
281891516925SJianzhou Zhao int __dfso_snprintf(char *str, size_t size, const char *format,
281991516925SJianzhou Zhao                     dfsan_label str_label, dfsan_label size_label,
282091516925SJianzhou Zhao                     dfsan_label format_label, dfsan_label *va_labels,
282191516925SJianzhou Zhao                     dfsan_label *ret_label, dfsan_origin str_origin,
282291516925SJianzhou Zhao                     dfsan_origin size_origin, dfsan_origin format_origin,
282391516925SJianzhou Zhao                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
282491516925SJianzhou Zhao   va_list ap;
282591516925SJianzhou Zhao   va_start(ap, ret_origin);
282691516925SJianzhou Zhao   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
282791516925SJianzhou Zhao                           ret_origin, ap);
2828a9aa8137SNico Weber   va_end(ap);
2829a9aa8137SNico Weber   return ret;
2830a9aa8137SNico Weber }
2831a9aa8137SNico Weber 
28328dbcf8ebSTomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE
28338dbcf8ebSTomasz Kuchta int __dfsw_sscanf(char *str, const char *format, dfsan_label str_label,
28348dbcf8ebSTomasz Kuchta                   dfsan_label format_label, dfsan_label *va_labels,
28358dbcf8ebSTomasz Kuchta                   dfsan_label *ret_label, ...) {
28368dbcf8ebSTomasz Kuchta   va_list ap;
28378dbcf8ebSTomasz Kuchta   va_start(ap, ret_label);
28388dbcf8ebSTomasz Kuchta   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
28398dbcf8ebSTomasz Kuchta                         nullptr, ap);
28408dbcf8ebSTomasz Kuchta   va_end(ap);
28418dbcf8ebSTomasz Kuchta   return ret;
28428dbcf8ebSTomasz Kuchta }
28438dbcf8ebSTomasz Kuchta 
28448dbcf8ebSTomasz Kuchta SANITIZER_INTERFACE_ATTRIBUTE
28458dbcf8ebSTomasz Kuchta int __dfso_sscanf(char *str, const char *format, dfsan_label str_label,
28468dbcf8ebSTomasz Kuchta                   dfsan_label format_label, dfsan_label *va_labels,
28478dbcf8ebSTomasz Kuchta                   dfsan_label *ret_label, dfsan_origin str_origin,
28488dbcf8ebSTomasz Kuchta                   dfsan_origin format_origin, dfsan_origin *va_origins,
28498dbcf8ebSTomasz Kuchta                   dfsan_origin *ret_origin, ...) {
28508dbcf8ebSTomasz Kuchta   va_list ap;
28518dbcf8ebSTomasz Kuchta   va_start(ap, ret_origin);
28528dbcf8ebSTomasz Kuchta   int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, &str_origin,
28538dbcf8ebSTomasz Kuchta                         ret_origin, ap);
28548dbcf8ebSTomasz Kuchta   va_end(ap);
28558dbcf8ebSTomasz Kuchta   return ret;
28568dbcf8ebSTomasz Kuchta }
28578dbcf8ebSTomasz Kuchta 
285864856006SFangrui Song WRAPPER_ALIAS(__isoc99_sscanf, sscanf)
285964856006SFangrui Song WRAPPER_ALIAS(__isoc23_sscanf, sscanf)
28608dbcf8ebSTomasz Kuchta 
28614e67ae7bSJianzhou Zhao static void BeforeFork() {
2862*36bd9aebSVitaly Buka   VReport(2, "BeforeFork tid: %llu\n", GetTid());
2863f78a742aSVitaly Buka   StackDepotLockBeforeFork();
2864f78a742aSVitaly Buka   ChainedOriginDepotLockBeforeFork();
28654e67ae7bSJianzhou Zhao }
28664e67ae7bSJianzhou Zhao 
2867f78a742aSVitaly Buka static void AfterFork(bool fork_child) {
2868f78a742aSVitaly Buka   ChainedOriginDepotUnlockAfterFork(fork_child);
2869f78a742aSVitaly Buka   StackDepotUnlockAfterFork(fork_child);
2870*36bd9aebSVitaly Buka   VReport(2, "AfterFork tid: %llu\n", GetTid());
28714e67ae7bSJianzhou Zhao }
28724e67ae7bSJianzhou Zhao 
28734e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
28744e67ae7bSJianzhou Zhao pid_t __dfsw_fork(dfsan_label *ret_label) {
28754e67ae7bSJianzhou Zhao   pid_t pid = fork();
28764e67ae7bSJianzhou Zhao   *ret_label = 0;
28774e67ae7bSJianzhou Zhao   return pid;
28784e67ae7bSJianzhou Zhao }
28794e67ae7bSJianzhou Zhao 
28804e67ae7bSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
28814e67ae7bSJianzhou Zhao pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
28824e67ae7bSJianzhou Zhao   BeforeFork();
28834e67ae7bSJianzhou Zhao   pid_t pid = __dfsw_fork(ret_label);
2884f78a742aSVitaly Buka   AfterFork(/* fork_child= */ pid == 0);
28854e67ae7bSJianzhou Zhao   return pid;
28864e67ae7bSJianzhou Zhao }
28874e67ae7bSJianzhou Zhao 
2888a9aa8137SNico Weber // Default empty implementations (weak). Users should redefine them.
2889a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
2890a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
2891a9aa8137SNico Weber                              u32 *) {}
28928103b070SKostya Serebryany SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
28938103b070SKostya Serebryany                              const uptr *end) {}
2894a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
2895a9aa8137SNico Weber 
2896a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
2897a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
2898a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
2899a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
2900a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
2901a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
2902a9aa8137SNico Weber                              void) {}
2903a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
2904a9aa8137SNico Weber                              void) {}
2905a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
2906a9aa8137SNico Weber                              void) {}
2907a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
2908a9aa8137SNico Weber                              void) {}
2909a9aa8137SNico Weber SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
2910a9aa8137SNico Weber }  // extern "C"
2911