xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1fe6060f1SDimitry Andric //===-- dfsan_custom.cpp --------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of DataFlowSanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // This file defines the custom functions listed in done_abilist.txt.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include <arpa/inet.h>
1568d75effSDimitry Andric #include <assert.h>
1668d75effSDimitry Andric #include <ctype.h>
1768d75effSDimitry Andric #include <dlfcn.h>
1868d75effSDimitry Andric #include <link.h>
1968d75effSDimitry Andric #include <poll.h>
2068d75effSDimitry Andric #include <pthread.h>
2168d75effSDimitry Andric #include <pwd.h>
2268d75effSDimitry Andric #include <sched.h>
2368d75effSDimitry Andric #include <signal.h>
2468d75effSDimitry Andric #include <stdarg.h>
2568d75effSDimitry Andric #include <stdint.h>
2668d75effSDimitry Andric #include <stdio.h>
2768d75effSDimitry Andric #include <stdlib.h>
2868d75effSDimitry Andric #include <string.h>
29e8d8bef9SDimitry Andric #include <sys/epoll.h>
3068d75effSDimitry Andric #include <sys/resource.h>
3168d75effSDimitry Andric #include <sys/select.h>
32e8d8bef9SDimitry Andric #include <sys/socket.h>
3368d75effSDimitry Andric #include <sys/stat.h>
3468d75effSDimitry Andric #include <sys/time.h>
3568d75effSDimitry Andric #include <sys/types.h>
3668d75effSDimitry Andric #include <time.h>
3768d75effSDimitry Andric #include <unistd.h>
3868d75effSDimitry Andric 
39e8d8bef9SDimitry Andric #include "dfsan/dfsan.h"
40fe6060f1SDimitry Andric #include "dfsan/dfsan_chained_origin_depot.h"
41fe6060f1SDimitry Andric #include "dfsan/dfsan_flags.h"
42fe6060f1SDimitry Andric #include "dfsan/dfsan_thread.h"
43e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
44e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
45e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
46fe6060f1SDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
47e8d8bef9SDimitry Andric 
4868d75effSDimitry Andric using namespace __dfsan;
4968d75effSDimitry Andric 
5068d75effSDimitry Andric #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)                                     \
5168d75effSDimitry Andric   do {                                                                         \
5268d75effSDimitry Andric     if (f)                                                                     \
5368d75effSDimitry Andric       f(__VA_ARGS__);                                                          \
5468d75effSDimitry Andric   } while (false)
5568d75effSDimitry Andric #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
5668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
5768d75effSDimitry Andric 
58fe6060f1SDimitry Andric // Async-safe, non-reentrant spin lock.
59fe6060f1SDimitry Andric class SignalSpinLocker {
60fe6060f1SDimitry Andric  public:
61fe6060f1SDimitry Andric   SignalSpinLocker() {
62fe6060f1SDimitry Andric     sigset_t all_set;
63fe6060f1SDimitry Andric     sigfillset(&all_set);
64fe6060f1SDimitry Andric     pthread_sigmask(SIG_SETMASK, &all_set, &saved_thread_mask_);
65fe6060f1SDimitry Andric     sigactions_mu.Lock();
66fe6060f1SDimitry Andric   }
67fe6060f1SDimitry Andric   ~SignalSpinLocker() {
68fe6060f1SDimitry Andric     sigactions_mu.Unlock();
69fe6060f1SDimitry Andric     pthread_sigmask(SIG_SETMASK, &saved_thread_mask_, nullptr);
70fe6060f1SDimitry Andric   }
71fe6060f1SDimitry Andric 
72fe6060f1SDimitry Andric  private:
73fe6060f1SDimitry Andric   static StaticSpinMutex sigactions_mu;
74fe6060f1SDimitry Andric   sigset_t saved_thread_mask_;
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric   SignalSpinLocker(const SignalSpinLocker &) = delete;
77fe6060f1SDimitry Andric   SignalSpinLocker &operator=(const SignalSpinLocker &) = delete;
78fe6060f1SDimitry Andric };
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric StaticSpinMutex SignalSpinLocker::sigactions_mu;
81fe6060f1SDimitry Andric 
8268d75effSDimitry Andric extern "C" {
8368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
8468d75effSDimitry Andric __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
8568d75effSDimitry Andric             dfsan_label buf_label, dfsan_label *ret_label) {
8668d75effSDimitry Andric   int ret = stat(path, buf);
8768d75effSDimitry Andric   if (ret == 0)
8868d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
8968d75effSDimitry Andric   *ret_label = 0;
9068d75effSDimitry Andric   return ret;
9168d75effSDimitry Andric }
9268d75effSDimitry Andric 
93fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_stat(
94fe6060f1SDimitry Andric     const char *path, struct stat *buf, dfsan_label path_label,
95fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label *ret_label, dfsan_origin path_origin,
96fe6060f1SDimitry Andric     dfsan_origin buf_origin, dfsan_origin *ret_origin) {
97fe6060f1SDimitry Andric   int ret = __dfsw_stat(path, buf, path_label, buf_label, ret_label);
98fe6060f1SDimitry Andric   return ret;
99fe6060f1SDimitry Andric }
100fe6060f1SDimitry Andric 
10168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
10268d75effSDimitry Andric                                                dfsan_label fd_label,
10368d75effSDimitry Andric                                                dfsan_label buf_label,
10468d75effSDimitry Andric                                                dfsan_label *ret_label) {
10568d75effSDimitry Andric   int ret = fstat(fd, buf);
10668d75effSDimitry Andric   if (ret == 0)
10768d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
10868d75effSDimitry Andric   *ret_label = 0;
10968d75effSDimitry Andric   return ret;
11068d75effSDimitry Andric }
11168d75effSDimitry Andric 
112fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_fstat(
113fe6060f1SDimitry Andric     int fd, struct stat *buf, dfsan_label fd_label, dfsan_label buf_label,
114fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
115fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
116fe6060f1SDimitry Andric   int ret = __dfsw_fstat(fd, buf, fd_label, buf_label, ret_label);
117fe6060f1SDimitry Andric   return ret;
118fe6060f1SDimitry Andric }
119fe6060f1SDimitry Andric 
120fe6060f1SDimitry Andric static char *dfsan_strchr_with_label(const char *s, int c, size_t *bytes_read,
121fe6060f1SDimitry Andric                                      dfsan_label s_label, dfsan_label c_label,
122fe6060f1SDimitry Andric                                      dfsan_label *ret_label) {
123fe6060f1SDimitry Andric   char *match_pos = nullptr;
124fe6060f1SDimitry Andric   for (size_t i = 0;; ++i) {
125fe6060f1SDimitry Andric     if (s[i] == c || s[i] == 0) {
126fe6060f1SDimitry Andric       // If s[i] is the \0 at the end of the string, and \0 is not the
127fe6060f1SDimitry Andric       // character we are searching for, then return null.
128fe6060f1SDimitry Andric       *bytes_read = i + 1;
129fe6060f1SDimitry Andric       match_pos = s[i] == 0 && c != 0 ? nullptr : const_cast<char *>(s + i);
130fe6060f1SDimitry Andric       break;
131fe6060f1SDimitry Andric     }
132fe6060f1SDimitry Andric   }
133fe6060f1SDimitry Andric   if (flags().strict_data_dependencies)
134fe6060f1SDimitry Andric     *ret_label = s_label;
135fe6060f1SDimitry Andric   else
136fe6060f1SDimitry Andric     *ret_label = dfsan_union(dfsan_read_label(s, *bytes_read),
137fe6060f1SDimitry Andric                              dfsan_union(s_label, c_label));
138fe6060f1SDimitry Andric   return match_pos;
139fe6060f1SDimitry Andric }
140fe6060f1SDimitry Andric 
14168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
14268d75effSDimitry Andric                                                   dfsan_label s_label,
14368d75effSDimitry Andric                                                   dfsan_label c_label,
14468d75effSDimitry Andric                                                   dfsan_label *ret_label) {
145fe6060f1SDimitry Andric   size_t bytes_read;
146fe6060f1SDimitry Andric   return dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label,
147fe6060f1SDimitry Andric                                  ret_label);
14868d75effSDimitry Andric }
1495ffd83dbSDimitry Andric 
150fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strchr(
151fe6060f1SDimitry Andric     const char *s, int c, dfsan_label s_label, dfsan_label c_label,
152fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
153fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
154fe6060f1SDimitry Andric   size_t bytes_read;
155fe6060f1SDimitry Andric   char *r =
156fe6060f1SDimitry Andric       dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label, ret_label);
157fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
158fe6060f1SDimitry Andric     *ret_origin = s_origin;
159fe6060f1SDimitry Andric   } else if (*ret_label) {
160fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, bytes_read);
161fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1625ffd83dbSDimitry Andric   }
163fe6060f1SDimitry Andric   return r;
16468d75effSDimitry Andric }
16568d75effSDimitry Andric 
166e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strpbrk(const char *s,
167e8d8bef9SDimitry Andric                                                    const char *accept,
168e8d8bef9SDimitry Andric                                                    dfsan_label s_label,
169e8d8bef9SDimitry Andric                                                    dfsan_label accept_label,
17068d75effSDimitry Andric                                                    dfsan_label *ret_label) {
171e8d8bef9SDimitry Andric   const char *ret = strpbrk(s, accept);
172e8d8bef9SDimitry Andric   if (flags().strict_data_dependencies) {
173e8d8bef9SDimitry Andric     *ret_label = ret ? s_label : 0;
174e8d8bef9SDimitry Andric   } else {
175e8d8bef9SDimitry Andric     size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
176e8d8bef9SDimitry Andric     *ret_label =
177e8d8bef9SDimitry Andric         dfsan_union(dfsan_read_label(s, s_bytes_read),
178e8d8bef9SDimitry Andric                     dfsan_union(dfsan_read_label(accept, strlen(accept) + 1),
179e8d8bef9SDimitry Andric                                 dfsan_union(s_label, accept_label)));
180e8d8bef9SDimitry Andric   }
181e8d8bef9SDimitry Andric   return const_cast<char *>(ret);
182e8d8bef9SDimitry Andric }
183e8d8bef9SDimitry Andric 
184fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strpbrk(
185fe6060f1SDimitry Andric     const char *s, const char *accept, dfsan_label s_label,
186fe6060f1SDimitry Andric     dfsan_label accept_label, dfsan_label *ret_label, dfsan_origin s_origin,
187fe6060f1SDimitry Andric     dfsan_origin accept_origin, dfsan_origin *ret_origin) {
188fe6060f1SDimitry Andric   const char *ret = __dfsw_strpbrk(s, accept, s_label, accept_label, ret_label);
189fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
190fe6060f1SDimitry Andric     if (ret)
191fe6060f1SDimitry Andric       *ret_origin = s_origin;
192fe6060f1SDimitry Andric   } else {
193fe6060f1SDimitry Andric     if (*ret_label) {
194fe6060f1SDimitry Andric       size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1;
195fe6060f1SDimitry Andric       dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_bytes_read);
196fe6060f1SDimitry Andric       if (o) {
197fe6060f1SDimitry Andric         *ret_origin = o;
198fe6060f1SDimitry Andric       } else {
199fe6060f1SDimitry Andric         o = dfsan_read_origin_of_first_taint(accept, strlen(accept) + 1);
200fe6060f1SDimitry Andric         *ret_origin = o ? o : (s_label ? s_origin : accept_origin);
201fe6060f1SDimitry Andric       }
202fe6060f1SDimitry Andric     }
203fe6060f1SDimitry Andric   }
204fe6060f1SDimitry Andric   return const_cast<char *>(ret);
205fe6060f1SDimitry Andric }
206fe6060f1SDimitry Andric 
207e8d8bef9SDimitry Andric static int dfsan_memcmp_bcmp(const void *s1, const void *s2, size_t n,
208fe6060f1SDimitry Andric                              size_t *bytes_read) {
20968d75effSDimitry Andric   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
21068d75effSDimitry Andric   for (size_t i = 0; i != n; ++i) {
21168d75effSDimitry Andric     if (cs1[i] != cs2[i]) {
212fe6060f1SDimitry Andric       *bytes_read = i + 1;
21368d75effSDimitry Andric       return cs1[i] - cs2[i];
21468d75effSDimitry Andric     }
21568d75effSDimitry Andric   }
216fe6060f1SDimitry Andric   *bytes_read = n;
21768d75effSDimitry Andric   return 0;
21868d75effSDimitry Andric }
21968d75effSDimitry Andric 
220fe6060f1SDimitry Andric static dfsan_label dfsan_get_memcmp_label(const void *s1, const void *s2,
221fe6060f1SDimitry Andric                                           size_t pos) {
222fe6060f1SDimitry Andric   if (flags().strict_data_dependencies)
223fe6060f1SDimitry Andric     return 0;
224fe6060f1SDimitry Andric   return dfsan_union(dfsan_read_label(s1, pos), dfsan_read_label(s2, pos));
225fe6060f1SDimitry Andric }
226fe6060f1SDimitry Andric 
227fe6060f1SDimitry Andric static void dfsan_get_memcmp_origin(const void *s1, const void *s2, size_t pos,
228fe6060f1SDimitry Andric                                     dfsan_label *ret_label,
229fe6060f1SDimitry Andric                                     dfsan_origin *ret_origin) {
230fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, pos);
231fe6060f1SDimitry Andric   if (*ret_label == 0)
232fe6060f1SDimitry Andric     return;
233fe6060f1SDimitry Andric   dfsan_origin o = dfsan_read_origin_of_first_taint(s1, pos);
234fe6060f1SDimitry Andric   *ret_origin = o ? o : dfsan_read_origin_of_first_taint(s2, pos);
235fe6060f1SDimitry Andric }
236fe6060f1SDimitry Andric 
237fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_label(const void *s1, const void *s2, size_t n,
238fe6060f1SDimitry Andric                                    dfsan_label *ret_label) {
239fe6060f1SDimitry Andric   size_t bytes_read;
240fe6060f1SDimitry Andric   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
241fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
242fe6060f1SDimitry Andric   return r;
243fe6060f1SDimitry Andric }
244fe6060f1SDimitry Andric 
245fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_origin(const void *s1, const void *s2, size_t n,
246fe6060f1SDimitry Andric                                     dfsan_label *ret_label,
247fe6060f1SDimitry Andric                                     dfsan_origin *ret_origin) {
248fe6060f1SDimitry Andric   size_t bytes_read;
249fe6060f1SDimitry Andric   int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read);
250fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
251fe6060f1SDimitry Andric   return r;
252fe6060f1SDimitry Andric }
253fe6060f1SDimitry Andric 
254e8d8bef9SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
255e8d8bef9SDimitry Andric                               const void *s1, const void *s2, size_t n,
256e8d8bef9SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
257e8d8bef9SDimitry Andric                               dfsan_label n_label)
258e8d8bef9SDimitry Andric 
259fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, uptr caller_pc,
260fe6060f1SDimitry Andric                               const void *s1, const void *s2, size_t n,
261fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
262fe6060f1SDimitry Andric                               dfsan_label n_label, dfsan_origin s1_origin,
263fe6060f1SDimitry Andric                               dfsan_origin s2_origin, dfsan_origin n_origin)
264fe6060f1SDimitry Andric 
265e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
266e8d8bef9SDimitry Andric                                                 size_t n, dfsan_label s1_label,
267e8d8bef9SDimitry Andric                                                 dfsan_label s2_label,
268e8d8bef9SDimitry Andric                                                 dfsan_label n_label,
269e8d8bef9SDimitry Andric                                                 dfsan_label *ret_label) {
270e8d8bef9SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
271e8d8bef9SDimitry Andric                              s1_label, s2_label, n_label);
272fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
273fe6060f1SDimitry Andric }
274fe6060f1SDimitry Andric 
275fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_memcmp(
276fe6060f1SDimitry Andric     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
277fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
278fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
279fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
280fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, GET_CALLER_PC(), s1,
281fe6060f1SDimitry Andric                              s2, n, s1_label, s2_label, n_label, s1_origin,
282fe6060f1SDimitry Andric                              s2_origin, n_origin);
283fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
284e8d8bef9SDimitry Andric }
285e8d8bef9SDimitry Andric 
286e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_bcmp(const void *s1, const void *s2,
287e8d8bef9SDimitry Andric                                               size_t n, dfsan_label s1_label,
288e8d8bef9SDimitry Andric                                               dfsan_label s2_label,
289e8d8bef9SDimitry Andric                                               dfsan_label n_label,
290e8d8bef9SDimitry Andric                                               dfsan_label *ret_label) {
291fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label);
292fe6060f1SDimitry Andric }
293fe6060f1SDimitry Andric 
294fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_bcmp(
295fe6060f1SDimitry Andric     const void *s1, const void *s2, size_t n, dfsan_label s1_label,
296fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
297fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
298fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
299fe6060f1SDimitry Andric   return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin);
300fe6060f1SDimitry Andric }
301fe6060f1SDimitry Andric 
302fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit.
303fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2.
304fe6060f1SDimitry Andric static int dfsan_strncmp(const char *s1, const char *s2, size_t n,
305fe6060f1SDimitry Andric                          size_t *bytes_read) {
306fe6060f1SDimitry Andric   for (size_t i = 0;; ++i) {
307fe6060f1SDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || (n > 0 && i == n - 1)) {
308fe6060f1SDimitry Andric       *bytes_read = i + 1;
309fe6060f1SDimitry Andric       return s1[i] - s2[i];
310fe6060f1SDimitry Andric     }
311fe6060f1SDimitry Andric   }
312e8d8bef9SDimitry Andric }
313e8d8bef9SDimitry Andric 
31468d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
31568d75effSDimitry Andric                               const char *s1, const char *s2,
31668d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label)
31768d75effSDimitry Andric 
318fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, uptr caller_pc,
319fe6060f1SDimitry Andric                               const char *s1, const char *s2,
320fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
321fe6060f1SDimitry Andric                               dfsan_origin s1_origin, dfsan_origin s2_origin)
322fe6060f1SDimitry Andric 
32368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
32468d75effSDimitry Andric                                                 dfsan_label s1_label,
32568d75effSDimitry Andric                                                 dfsan_label s2_label,
32668d75effSDimitry Andric                                                 dfsan_label *ret_label) {
32768d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
32868d75effSDimitry Andric                              s1_label, s2_label);
329fe6060f1SDimitry Andric   size_t bytes_read;
330fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
331fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
332fe6060f1SDimitry Andric   return r;
33368d75effSDimitry Andric }
33468d75effSDimitry Andric 
335fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcmp(
336fe6060f1SDimitry Andric     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
337fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
338fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
339fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, GET_CALLER_PC(), s1,
340fe6060f1SDimitry Andric                              s2, s1_label, s2_label, s1_origin, s2_origin);
341fe6060f1SDimitry Andric   size_t bytes_read;
342fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, 0, &bytes_read);
343fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
344fe6060f1SDimitry Andric   return r;
345fe6060f1SDimitry Andric }
346fe6060f1SDimitry Andric 
347fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit.
348fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2.
349fe6060f1SDimitry Andric static int dfsan_strncasecmp(const char *s1, const char *s2, size_t n,
350fe6060f1SDimitry Andric                              size_t *bytes_read) {
35168d75effSDimitry Andric   for (size_t i = 0;; ++i) {
3525ffd83dbSDimitry Andric     char s1_lower = tolower(s1[i]);
3535ffd83dbSDimitry Andric     char s2_lower = tolower(s2[i]);
3545ffd83dbSDimitry Andric 
355fe6060f1SDimitry Andric     if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0 ||
356fe6060f1SDimitry Andric         (n > 0 && i == n - 1)) {
357fe6060f1SDimitry Andric       *bytes_read = i + 1;
3585ffd83dbSDimitry Andric       return s1_lower - s2_lower;
35968d75effSDimitry Andric     }
36068d75effSDimitry Andric   }
361fe6060f1SDimitry Andric }
362fe6060f1SDimitry Andric 
363fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcasecmp(const char *s1,
364fe6060f1SDimitry Andric                                                     const char *s2,
365fe6060f1SDimitry Andric                                                     dfsan_label s1_label,
366fe6060f1SDimitry Andric                                                     dfsan_label s2_label,
367fe6060f1SDimitry Andric                                                     dfsan_label *ret_label) {
368fe6060f1SDimitry Andric   size_t bytes_read;
369fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
370fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
371fe6060f1SDimitry Andric   return r;
372fe6060f1SDimitry Andric }
373fe6060f1SDimitry Andric 
374fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcasecmp(
375fe6060f1SDimitry Andric     const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label,
376fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin,
377fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
378fe6060f1SDimitry Andric   size_t bytes_read;
379fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read);
380fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
381fe6060f1SDimitry Andric   return r;
38268d75effSDimitry Andric }
38368d75effSDimitry Andric 
38468d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
38568d75effSDimitry Andric                               const char *s1, const char *s2, size_t n,
38668d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
38768d75effSDimitry Andric                               dfsan_label n_label)
38868d75effSDimitry Andric 
389fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, uptr caller_pc,
390fe6060f1SDimitry Andric                               const char *s1, const char *s2, size_t n,
391fe6060f1SDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
392fe6060f1SDimitry Andric                               dfsan_label n_label, dfsan_origin s1_origin,
393fe6060f1SDimitry Andric                               dfsan_origin s2_origin, dfsan_origin n_origin)
394fe6060f1SDimitry Andric 
39568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
39668d75effSDimitry Andric                                                  size_t n, dfsan_label s1_label,
39768d75effSDimitry Andric                                                  dfsan_label s2_label,
39868d75effSDimitry Andric                                                  dfsan_label n_label,
39968d75effSDimitry Andric                                                  dfsan_label *ret_label) {
40068d75effSDimitry Andric   if (n == 0) {
40168d75effSDimitry Andric     *ret_label = 0;
40268d75effSDimitry Andric     return 0;
40368d75effSDimitry Andric   }
40468d75effSDimitry Andric 
40568d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
40668d75effSDimitry Andric                              n, s1_label, s2_label, n_label);
40768d75effSDimitry Andric 
408fe6060f1SDimitry Andric   size_t bytes_read;
409fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
410fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
411fe6060f1SDimitry Andric   return r;
41268d75effSDimitry Andric }
41368d75effSDimitry Andric 
414fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncmp(
415fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
416fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
417fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
418fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
41968d75effSDimitry Andric   if (n == 0) {
42068d75effSDimitry Andric     *ret_label = 0;
42168d75effSDimitry Andric     return 0;
42268d75effSDimitry Andric   }
42368d75effSDimitry Andric 
424fe6060f1SDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, GET_CALLER_PC(),
425fe6060f1SDimitry Andric                              s1, s2, n, s1_label, s2_label, n_label, s1_origin,
426fe6060f1SDimitry Andric                              s2_origin, n_origin);
4275ffd83dbSDimitry Andric 
428fe6060f1SDimitry Andric   size_t bytes_read;
429fe6060f1SDimitry Andric   int r = dfsan_strncmp(s1, s2, n, &bytes_read);
430fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
431fe6060f1SDimitry Andric   return r;
432fe6060f1SDimitry Andric }
433fe6060f1SDimitry Andric 
434fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncasecmp(
435fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
436fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) {
437fe6060f1SDimitry Andric   if (n == 0) {
43868d75effSDimitry Andric     *ret_label = 0;
43968d75effSDimitry Andric     return 0;
44068d75effSDimitry Andric   }
44168d75effSDimitry Andric 
442fe6060f1SDimitry Andric   size_t bytes_read;
443fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
444fe6060f1SDimitry Andric   *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read);
445fe6060f1SDimitry Andric   return r;
44668d75effSDimitry Andric }
44768d75effSDimitry Andric 
448fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncasecmp(
449fe6060f1SDimitry Andric     const char *s1, const char *s2, size_t n, dfsan_label s1_label,
450fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
451fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
452fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
453fe6060f1SDimitry Andric   if (n == 0) {
454fe6060f1SDimitry Andric     *ret_label = 0;
455fe6060f1SDimitry Andric     return 0;
456fe6060f1SDimitry Andric   }
457fe6060f1SDimitry Andric 
458fe6060f1SDimitry Andric   size_t bytes_read;
459fe6060f1SDimitry Andric   int r = dfsan_strncasecmp(s1, s2, n, &bytes_read);
460fe6060f1SDimitry Andric   dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin);
461fe6060f1SDimitry Andric   return r;
462fe6060f1SDimitry Andric }
463fe6060f1SDimitry Andric 
464fe6060f1SDimitry Andric 
46568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t
46668d75effSDimitry Andric __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
46768d75effSDimitry Andric   size_t ret = strlen(s);
46868d75effSDimitry Andric   if (flags().strict_data_dependencies) {
46968d75effSDimitry Andric     *ret_label = 0;
47068d75effSDimitry Andric   } else {
47168d75effSDimitry Andric     *ret_label = dfsan_read_label(s, ret + 1);
47268d75effSDimitry Andric   }
47368d75effSDimitry Andric   return ret;
47468d75effSDimitry Andric }
47568d75effSDimitry Andric 
476fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s,
477fe6060f1SDimitry Andric                                                    dfsan_label s_label,
478fe6060f1SDimitry Andric                                                    dfsan_label *ret_label,
479fe6060f1SDimitry Andric                                                    dfsan_origin s_origin,
480fe6060f1SDimitry Andric                                                    dfsan_origin *ret_origin) {
481fe6060f1SDimitry Andric   size_t ret = __dfsw_strlen(s, s_label, ret_label);
482fe6060f1SDimitry Andric   if (!flags().strict_data_dependencies)
483fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1);
484fe6060f1SDimitry Andric   return ret;
485fe6060f1SDimitry Andric }
486fe6060f1SDimitry Andric 
487fe6060f1SDimitry Andric static void *dfsan_memmove(void *dest, const void *src, size_t n) {
488fe6060f1SDimitry Andric   dfsan_label *sdest = shadow_for(dest);
489fe6060f1SDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
490fe6060f1SDimitry Andric   internal_memmove((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
491fe6060f1SDimitry Andric   return internal_memmove(dest, src, n);
492fe6060f1SDimitry Andric }
493fe6060f1SDimitry Andric 
494fe6060f1SDimitry Andric static void *dfsan_memmove_with_origin(void *dest, const void *src, size_t n) {
495fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
496fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
497fe6060f1SDimitry Andric }
49868d75effSDimitry Andric 
49968d75effSDimitry Andric static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
50068d75effSDimitry Andric   dfsan_label *sdest = shadow_for(dest);
50168d75effSDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
50268d75effSDimitry Andric   internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
50368d75effSDimitry Andric   return internal_memcpy(dest, src, n);
50468d75effSDimitry Andric }
50568d75effSDimitry Andric 
506fe6060f1SDimitry Andric static void *dfsan_memcpy_with_origin(void *dest, const void *src, size_t n) {
507fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
508fe6060f1SDimitry Andric   return dfsan_memcpy(dest, src, n);
509fe6060f1SDimitry Andric }
510fe6060f1SDimitry Andric 
51168d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
51268d75effSDimitry Andric   internal_memset(s, c, n);
51368d75effSDimitry Andric   dfsan_set_label(c_label, s, n);
51468d75effSDimitry Andric }
51568d75effSDimitry Andric 
516fe6060f1SDimitry Andric static void dfsan_memset_with_origin(void *s, int c, dfsan_label c_label,
517fe6060f1SDimitry Andric                                      dfsan_origin c_origin, size_t n) {
518fe6060f1SDimitry Andric   internal_memset(s, c, n);
519fe6060f1SDimitry Andric   dfsan_set_label_origin(c_label, c_origin, s, n);
520fe6060f1SDimitry Andric }
521fe6060f1SDimitry Andric 
52268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
52368d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n,
52468d75effSDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
52568d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
52668d75effSDimitry Andric   *ret_label = dest_label;
52768d75effSDimitry Andric   return dfsan_memcpy(dest, src, n);
52868d75effSDimitry Andric }
52968d75effSDimitry Andric 
53068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
531fe6060f1SDimitry Andric void *__dfso_memcpy(void *dest, const void *src, size_t n,
532fe6060f1SDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
533fe6060f1SDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label,
534fe6060f1SDimitry Andric                     dfsan_origin dest_origin, dfsan_origin src_origin,
535fe6060f1SDimitry Andric                     dfsan_origin n_origin, dfsan_origin *ret_origin) {
536fe6060f1SDimitry Andric   *ret_label = dest_label;
537fe6060f1SDimitry Andric   *ret_origin = dest_origin;
538fe6060f1SDimitry Andric   return dfsan_memcpy_with_origin(dest, src, n);
539fe6060f1SDimitry Andric }
540fe6060f1SDimitry Andric 
541fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
542fe6060f1SDimitry Andric void *__dfsw_memmove(void *dest, const void *src, size_t n,
543fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
544fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label) {
545fe6060f1SDimitry Andric   *ret_label = dest_label;
546fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
547fe6060f1SDimitry Andric }
548fe6060f1SDimitry Andric 
549fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
550fe6060f1SDimitry Andric void *__dfso_memmove(void *dest, const void *src, size_t n,
551fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
552fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label,
553fe6060f1SDimitry Andric                      dfsan_origin dest_origin, dfsan_origin src_origin,
554fe6060f1SDimitry Andric                      dfsan_origin n_origin, dfsan_origin *ret_origin) {
555fe6060f1SDimitry Andric   *ret_label = dest_label;
556fe6060f1SDimitry Andric   *ret_origin = dest_origin;
557fe6060f1SDimitry Andric   return dfsan_memmove_with_origin(dest, src, n);
558fe6060f1SDimitry Andric }
559fe6060f1SDimitry Andric 
560fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
56168d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n,
56268d75effSDimitry Andric                     dfsan_label s_label, dfsan_label c_label,
56368d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
56468d75effSDimitry Andric   dfsan_memset(s, c, c_label, n);
56568d75effSDimitry Andric   *ret_label = s_label;
56668d75effSDimitry Andric   return s;
56768d75effSDimitry Andric }
56868d75effSDimitry Andric 
569fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
570fe6060f1SDimitry Andric void *__dfso_memset(void *s, int c, size_t n, dfsan_label s_label,
571fe6060f1SDimitry Andric                     dfsan_label c_label, dfsan_label n_label,
572fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin s_origin,
573fe6060f1SDimitry Andric                     dfsan_origin c_origin, dfsan_origin n_origin,
574fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
575fe6060f1SDimitry Andric   dfsan_memset_with_origin(s, c, c_label, c_origin, n);
576fe6060f1SDimitry Andric   *ret_label = s_label;
577fe6060f1SDimitry Andric   *ret_origin = s_origin;
578fe6060f1SDimitry Andric   return s;
579fe6060f1SDimitry Andric }
580fe6060f1SDimitry Andric 
581fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src,
582fe6060f1SDimitry Andric                                                   dfsan_label dest_label,
583fe6060f1SDimitry Andric                                                   dfsan_label src_label,
584fe6060f1SDimitry Andric                                                   dfsan_label *ret_label) {
585fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
586*349cc55cSDimitry Andric   char *ret = strcat(dest, src);
587fe6060f1SDimitry Andric   dfsan_label *sdest = shadow_for(dest + dest_len);
588fe6060f1SDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
589fe6060f1SDimitry Andric   internal_memcpy((void *)sdest, (const void *)ssrc,
590fe6060f1SDimitry Andric                   strlen(src) * sizeof(dfsan_label));
591fe6060f1SDimitry Andric   *ret_label = dest_label;
592fe6060f1SDimitry Andric   return ret;
593fe6060f1SDimitry Andric }
594fe6060f1SDimitry Andric 
595fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat(
596fe6060f1SDimitry Andric     char *dest, const char *src, dfsan_label dest_label, dfsan_label src_label,
597fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin,
598fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
599fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
600*349cc55cSDimitry Andric   char *ret = strcat(dest, src);
601fe6060f1SDimitry Andric   dfsan_label *sdest = shadow_for(dest + dest_len);
602fe6060f1SDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
603fe6060f1SDimitry Andric   size_t src_len = strlen(src);
604fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
605fe6060f1SDimitry Andric   internal_memcpy((void *)sdest, (const void *)ssrc,
606fe6060f1SDimitry Andric                   src_len * sizeof(dfsan_label));
607fe6060f1SDimitry Andric   *ret_label = dest_label;
608fe6060f1SDimitry Andric   *ret_origin = dest_origin;
609fe6060f1SDimitry Andric   return ret;
610fe6060f1SDimitry Andric }
611fe6060f1SDimitry Andric 
61268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
61368d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
61468d75effSDimitry Andric   size_t len = strlen(s);
61568d75effSDimitry Andric   void *p = malloc(len+1);
61668d75effSDimitry Andric   dfsan_memcpy(p, s, len+1);
61768d75effSDimitry Andric   *ret_label = 0;
61868d75effSDimitry Andric   return static_cast<char *>(p);
61968d75effSDimitry Andric }
62068d75effSDimitry Andric 
621fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strdup(const char *s,
622fe6060f1SDimitry Andric                                                   dfsan_label s_label,
623fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
624fe6060f1SDimitry Andric                                                   dfsan_origin s_origin,
625fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
626fe6060f1SDimitry Andric   size_t len = strlen(s);
627fe6060f1SDimitry Andric   void *p = malloc(len + 1);
628fe6060f1SDimitry Andric   dfsan_memcpy_with_origin(p, s, len + 1);
629fe6060f1SDimitry Andric   *ret_label = 0;
630fe6060f1SDimitry Andric   return static_cast<char *>(p);
631fe6060f1SDimitry Andric }
632fe6060f1SDimitry Andric 
63368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
63468d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
63568d75effSDimitry Andric                dfsan_label s2_label, dfsan_label n_label,
63668d75effSDimitry Andric                dfsan_label *ret_label) {
63768d75effSDimitry Andric   size_t len = strlen(s2);
63868d75effSDimitry Andric   if (len < n) {
63968d75effSDimitry Andric     dfsan_memcpy(s1, s2, len+1);
64068d75effSDimitry Andric     dfsan_memset(s1+len+1, 0, 0, n-len-1);
64168d75effSDimitry Andric   } else {
64268d75effSDimitry Andric     dfsan_memcpy(s1, s2, n);
64368d75effSDimitry Andric   }
64468d75effSDimitry Andric 
64568d75effSDimitry Andric   *ret_label = s1_label;
64668d75effSDimitry Andric   return s1;
64768d75effSDimitry Andric }
64868d75effSDimitry Andric 
649fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncpy(
650fe6060f1SDimitry Andric     char *s1, const char *s2, size_t n, dfsan_label s1_label,
651fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
652fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
653fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
654fe6060f1SDimitry Andric   size_t len = strlen(s2);
655fe6060f1SDimitry Andric   if (len < n) {
656fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, len + 1);
657fe6060f1SDimitry Andric     dfsan_memset_with_origin(s1 + len + 1, 0, 0, 0, n - len - 1);
658fe6060f1SDimitry Andric   } else {
659fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, n);
660fe6060f1SDimitry Andric   }
661fe6060f1SDimitry Andric 
662fe6060f1SDimitry Andric   *ret_label = s1_label;
663fe6060f1SDimitry Andric   *ret_origin = s1_origin;
664fe6060f1SDimitry Andric   return s1;
665fe6060f1SDimitry Andric }
666fe6060f1SDimitry Andric 
66768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
66868d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
66968d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
67068d75effSDimitry Andric              dfsan_label count_label, dfsan_label offset_label,
67168d75effSDimitry Andric              dfsan_label *ret_label) {
67268d75effSDimitry Andric   ssize_t ret = pread(fd, buf, count, offset);
67368d75effSDimitry Andric   if (ret > 0)
67468d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
67568d75effSDimitry Andric   *ret_label = 0;
67668d75effSDimitry Andric   return ret;
67768d75effSDimitry Andric }
67868d75effSDimitry Andric 
679fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_pread(
680fe6060f1SDimitry Andric     int fd, void *buf, size_t count, off_t offset, dfsan_label fd_label,
681fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label offset_label,
682fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
683fe6060f1SDimitry Andric     dfsan_origin count_origin, dfsan_label offset_origin,
684fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
685fe6060f1SDimitry Andric   return __dfsw_pread(fd, buf, count, offset, fd_label, buf_label, count_label,
686fe6060f1SDimitry Andric                       offset_label, ret_label);
687fe6060f1SDimitry Andric }
688fe6060f1SDimitry Andric 
68968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
69068d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count,
69168d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
69268d75effSDimitry Andric              dfsan_label count_label,
69368d75effSDimitry Andric              dfsan_label *ret_label) {
69468d75effSDimitry Andric   ssize_t ret = read(fd, buf, count);
69568d75effSDimitry Andric   if (ret > 0)
69668d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
69768d75effSDimitry Andric   *ret_label = 0;
69868d75effSDimitry Andric   return ret;
69968d75effSDimitry Andric }
70068d75effSDimitry Andric 
701fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_read(
702fe6060f1SDimitry Andric     int fd, void *buf, size_t count, dfsan_label fd_label,
703fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
704fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
705fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
706fe6060f1SDimitry Andric   return __dfsw_read(fd, buf, count, fd_label, buf_label, count_label,
707fe6060f1SDimitry Andric                      ret_label);
708fe6060f1SDimitry Andric }
709fe6060f1SDimitry Andric 
71068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
71168d75effSDimitry Andric                                                        struct timespec *tp,
71268d75effSDimitry Andric                                                        dfsan_label clk_id_label,
71368d75effSDimitry Andric                                                        dfsan_label tp_label,
71468d75effSDimitry Andric                                                        dfsan_label *ret_label) {
71568d75effSDimitry Andric   int ret = clock_gettime(clk_id, tp);
71668d75effSDimitry Andric   if (ret == 0)
71768d75effSDimitry Andric     dfsan_set_label(0, tp, sizeof(struct timespec));
71868d75effSDimitry Andric   *ret_label = 0;
71968d75effSDimitry Andric   return ret;
72068d75effSDimitry Andric }
72168d75effSDimitry Andric 
722fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_clock_gettime(
723fe6060f1SDimitry Andric     clockid_t clk_id, struct timespec *tp, dfsan_label clk_id_label,
724fe6060f1SDimitry Andric     dfsan_label tp_label, dfsan_label *ret_label, dfsan_origin clk_id_origin,
725fe6060f1SDimitry Andric     dfsan_origin tp_origin, dfsan_origin *ret_origin) {
726fe6060f1SDimitry Andric   return __dfsw_clock_gettime(clk_id, tp, clk_id_label, tp_label, ret_label);
727fe6060f1SDimitry Andric }
728fe6060f1SDimitry Andric 
729fe6060f1SDimitry Andric static void dfsan_set_zero_label(const void *ptr, uptr size) {
73068d75effSDimitry Andric   dfsan_set_label(0, const_cast<void *>(ptr), size);
73168d75effSDimitry Andric }
73268d75effSDimitry Andric 
73368d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally
73468d75effSDimitry Andric // doesn't participate in dynamic symbol resolution.  Therefore we won't
73568d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here.
73668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *
73768d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
73868d75effSDimitry Andric               dfsan_label flag_label, dfsan_label *ret_label) {
73968d75effSDimitry Andric   void *handle = dlopen(filename, flag);
74068d75effSDimitry Andric   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
74168d75effSDimitry Andric   if (map)
742fe6060f1SDimitry Andric     ForEachMappedRegion(map, dfsan_set_zero_label);
74368d75effSDimitry Andric   *ret_label = 0;
74468d75effSDimitry Andric   return handle;
74568d75effSDimitry Andric }
74668d75effSDimitry Andric 
747fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen(
748fe6060f1SDimitry Andric     const char *filename, int flag, dfsan_label filename_label,
749fe6060f1SDimitry Andric     dfsan_label flag_label, dfsan_label *ret_label,
750fe6060f1SDimitry Andric     dfsan_origin filename_origin, dfsan_origin flag_origin,
751fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
752fe6060f1SDimitry Andric   return __dfsw_dlopen(filename, flag, filename_label, flag_label, ret_label);
753fe6060f1SDimitry Andric }
75468d75effSDimitry Andric 
755fe6060f1SDimitry Andric static void *DFsanThreadStartFunc(void *arg) {
756fe6060f1SDimitry Andric   DFsanThread *t = (DFsanThread *)arg;
757fe6060f1SDimitry Andric   SetCurrentThread(t);
758*349cc55cSDimitry Andric   t->Init();
759*349cc55cSDimitry Andric   SetSigProcMask(&t->starting_sigset_, nullptr);
760fe6060f1SDimitry Andric   return t->ThreadStart();
761fe6060f1SDimitry Andric }
762fe6060f1SDimitry Andric 
763fe6060f1SDimitry Andric static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
764fe6060f1SDimitry Andric                                 void *start_routine_trampoline,
765fe6060f1SDimitry Andric                                 void *start_routine, void *arg,
766fe6060f1SDimitry Andric                                 dfsan_label *ret_label,
767fe6060f1SDimitry Andric                                 bool track_origins = false) {
768fe6060f1SDimitry Andric   pthread_attr_t myattr;
769fe6060f1SDimitry Andric   if (!attr) {
770fe6060f1SDimitry Andric     pthread_attr_init(&myattr);
771fe6060f1SDimitry Andric     attr = &myattr;
772fe6060f1SDimitry Andric   }
773fe6060f1SDimitry Andric 
774fe6060f1SDimitry Andric   // Ensure that the thread stack is large enough to hold all TLS data.
775fe6060f1SDimitry Andric   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
776fe6060f1SDimitry Andric 
777fe6060f1SDimitry Andric   DFsanThread *t =
778fe6060f1SDimitry Andric       DFsanThread::Create(start_routine_trampoline,
779fe6060f1SDimitry Andric                           (thread_callback_t)start_routine, arg, track_origins);
780*349cc55cSDimitry Andric   ScopedBlockSignals block(&t->starting_sigset_);
781fe6060f1SDimitry Andric   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
782fe6060f1SDimitry Andric 
783fe6060f1SDimitry Andric   if (attr == &myattr)
784fe6060f1SDimitry Andric     pthread_attr_destroy(&myattr);
785fe6060f1SDimitry Andric   *ret_label = 0;
786fe6060f1SDimitry Andric   return res;
78768d75effSDimitry Andric }
78868d75effSDimitry Andric 
78968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
79068d75effSDimitry Andric     pthread_t *thread, const pthread_attr_t *attr,
79168d75effSDimitry Andric     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
79268d75effSDimitry Andric                                       dfsan_label *),
79368d75effSDimitry Andric     void *start_routine, void *arg, dfsan_label thread_label,
79468d75effSDimitry Andric     dfsan_label attr_label, dfsan_label start_routine_label,
79568d75effSDimitry Andric     dfsan_label arg_label, dfsan_label *ret_label) {
796fe6060f1SDimitry Andric   return dfsan_pthread_create(thread, attr, (void *)start_routine_trampoline,
797fe6060f1SDimitry Andric                               start_routine, arg, ret_label);
798fe6060f1SDimitry Andric }
799fe6060f1SDimitry Andric 
800fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
801fe6060f1SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr,
802fe6060f1SDimitry Andric     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
803fe6060f1SDimitry Andric                                       dfsan_label *, dfsan_origin,
804fe6060f1SDimitry Andric                                       dfsan_origin *),
805fe6060f1SDimitry Andric     void *start_routine, void *arg, dfsan_label thread_label,
806fe6060f1SDimitry Andric     dfsan_label attr_label, dfsan_label start_routine_label,
807fe6060f1SDimitry Andric     dfsan_label arg_label, dfsan_label *ret_label, dfsan_origin thread_origin,
808fe6060f1SDimitry Andric     dfsan_origin attr_origin, dfsan_origin start_routine_origin,
809fe6060f1SDimitry Andric     dfsan_origin arg_origin, dfsan_origin *ret_origin) {
810fe6060f1SDimitry Andric   return dfsan_pthread_create(thread, attr, (void *)start_routine_trampoline,
811fe6060f1SDimitry Andric                               start_routine, arg, ret_label, true);
81268d75effSDimitry Andric }
81368d75effSDimitry Andric 
814e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
815e8d8bef9SDimitry Andric                                                       void **retval,
816e8d8bef9SDimitry Andric                                                       dfsan_label thread_label,
817e8d8bef9SDimitry Andric                                                       dfsan_label retval_label,
818e8d8bef9SDimitry Andric                                                       dfsan_label *ret_label) {
819e8d8bef9SDimitry Andric   int ret = pthread_join(thread, retval);
820e8d8bef9SDimitry Andric   if (ret == 0 && retval)
821e8d8bef9SDimitry Andric     dfsan_set_label(0, retval, sizeof(*retval));
822e8d8bef9SDimitry Andric   *ret_label = 0;
823e8d8bef9SDimitry Andric   return ret;
824e8d8bef9SDimitry Andric }
825e8d8bef9SDimitry Andric 
826fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
827fe6060f1SDimitry Andric     pthread_t thread, void **retval, dfsan_label thread_label,
828fe6060f1SDimitry Andric     dfsan_label retval_label, dfsan_label *ret_label,
829fe6060f1SDimitry Andric     dfsan_origin thread_origin, dfsan_origin retval_origin,
830fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
831fe6060f1SDimitry Andric   return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
832fe6060f1SDimitry Andric                              ret_label);
833fe6060f1SDimitry Andric }
834fe6060f1SDimitry Andric 
83568d75effSDimitry Andric struct dl_iterate_phdr_info {
83668d75effSDimitry Andric   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
83768d75effSDimitry Andric                              size_t size, void *data, dfsan_label info_label,
83868d75effSDimitry Andric                              dfsan_label size_label, dfsan_label data_label,
83968d75effSDimitry Andric                              dfsan_label *ret_label);
84068d75effSDimitry Andric   void *callback;
84168d75effSDimitry Andric   void *data;
84268d75effSDimitry Andric };
84368d75effSDimitry Andric 
844fe6060f1SDimitry Andric struct dl_iterate_phdr_origin_info {
845fe6060f1SDimitry Andric   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
846fe6060f1SDimitry Andric                              size_t size, void *data, dfsan_label info_label,
847fe6060f1SDimitry Andric                              dfsan_label size_label, dfsan_label data_label,
848fe6060f1SDimitry Andric                              dfsan_label *ret_label, dfsan_origin info_origin,
849fe6060f1SDimitry Andric                              dfsan_origin size_origin, dfsan_origin data_origin,
850fe6060f1SDimitry Andric                              dfsan_origin *ret_origin);
851fe6060f1SDimitry Andric   void *callback;
852fe6060f1SDimitry Andric   void *data;
853fe6060f1SDimitry Andric };
854fe6060f1SDimitry Andric 
85568d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
85668d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
85768d75effSDimitry Andric   dfsan_set_label(0, *info);
85868d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
85968d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
86068d75effSDimitry Andric   dfsan_set_label(
86168d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
86268d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
86368d75effSDimitry Andric   dfsan_label ret_label;
86468d75effSDimitry Andric   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
86568d75effSDimitry Andric                                    0, &ret_label);
86668d75effSDimitry Andric }
86768d75effSDimitry Andric 
868fe6060f1SDimitry Andric int dl_iterate_phdr_origin_cb(struct dl_phdr_info *info, size_t size,
869fe6060f1SDimitry Andric                               void *data) {
870fe6060f1SDimitry Andric   dl_iterate_phdr_origin_info *dipi = (dl_iterate_phdr_origin_info *)data;
871fe6060f1SDimitry Andric   dfsan_set_label(0, *info);
872fe6060f1SDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
873fe6060f1SDimitry Andric                   strlen(info->dlpi_name) + 1);
874fe6060f1SDimitry Andric   dfsan_set_label(
875fe6060f1SDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
876fe6060f1SDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
877fe6060f1SDimitry Andric   dfsan_label ret_label;
878fe6060f1SDimitry Andric   dfsan_origin ret_origin;
879fe6060f1SDimitry Andric   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
880fe6060f1SDimitry Andric                                    0, &ret_label, 0, 0, 0, &ret_origin);
881fe6060f1SDimitry Andric }
882fe6060f1SDimitry Andric 
88368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
88468d75effSDimitry Andric     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
88568d75effSDimitry Andric                                size_t size, void *data, dfsan_label info_label,
88668d75effSDimitry Andric                                dfsan_label size_label, dfsan_label data_label,
88768d75effSDimitry Andric                                dfsan_label *ret_label),
88868d75effSDimitry Andric     void *callback, void *data, dfsan_label callback_label,
88968d75effSDimitry Andric     dfsan_label data_label, dfsan_label *ret_label) {
89068d75effSDimitry Andric   dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
89168d75effSDimitry Andric   *ret_label = 0;
89268d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
89368d75effSDimitry Andric }
89468d75effSDimitry Andric 
895fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr(
896fe6060f1SDimitry Andric     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
897fe6060f1SDimitry Andric                                size_t size, void *data, dfsan_label info_label,
898fe6060f1SDimitry Andric                                dfsan_label size_label, dfsan_label data_label,
899fe6060f1SDimitry Andric                                dfsan_label *ret_label, dfsan_origin info_origin,
900fe6060f1SDimitry Andric                                dfsan_origin size_origin,
901fe6060f1SDimitry Andric                                dfsan_origin data_origin,
902fe6060f1SDimitry Andric                                dfsan_origin *ret_origin),
903fe6060f1SDimitry Andric     void *callback, void *data, dfsan_label callback_label,
904fe6060f1SDimitry Andric     dfsan_label data_label, dfsan_label *ret_label,
905fe6060f1SDimitry Andric     dfsan_origin callback_origin, dfsan_origin data_origin,
906fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
907fe6060f1SDimitry Andric   dl_iterate_phdr_origin_info dipi = {callback_trampoline, callback, data};
908fe6060f1SDimitry Andric   *ret_label = 0;
909fe6060f1SDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_origin_cb, &dipi);
910fe6060f1SDimitry Andric }
911fe6060f1SDimitry Andric 
912e8d8bef9SDimitry Andric // This function is only available for glibc 2.27 or newer.  Mark it weak so
913e8d8bef9SDimitry Andric // linking succeeds with older glibcs.
914e8d8bef9SDimitry Andric SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep,
915e8d8bef9SDimitry Andric                                                       size_t *alignp);
916e8d8bef9SDimitry Andric 
917e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info(
918e8d8bef9SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
919e8d8bef9SDimitry Andric     dfsan_label alignp_label) {
920e8d8bef9SDimitry Andric   assert(_dl_get_tls_static_info);
921e8d8bef9SDimitry Andric   _dl_get_tls_static_info(sizep, alignp);
922e8d8bef9SDimitry Andric   dfsan_set_label(0, sizep, sizeof(*sizep));
923e8d8bef9SDimitry Andric   dfsan_set_label(0, alignp, sizeof(*alignp));
924e8d8bef9SDimitry Andric }
925e8d8bef9SDimitry Andric 
926fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info(
927fe6060f1SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
928fe6060f1SDimitry Andric     dfsan_label alignp_label, dfsan_origin sizep_origin,
929fe6060f1SDimitry Andric     dfsan_origin alignp_origin) {
930fe6060f1SDimitry Andric   __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label);
931fe6060f1SDimitry Andric }
932fe6060f1SDimitry Andric 
93368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
93468d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
93568d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
93668d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
93768d75effSDimitry Andric   if (ret) {
93868d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
93968d75effSDimitry Andric                     strlen(buf) + 1);
94068d75effSDimitry Andric     *ret_label = buf_label;
94168d75effSDimitry Andric   } else {
94268d75effSDimitry Andric     *ret_label = 0;
94368d75effSDimitry Andric   }
94468d75effSDimitry Andric   return ret;
94568d75effSDimitry Andric }
94668d75effSDimitry Andric 
94768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
948fe6060f1SDimitry Andric char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
949fe6060f1SDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label,
950fe6060f1SDimitry Andric                      dfsan_origin timep_origin, dfsan_origin buf_origin,
951fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
952fe6060f1SDimitry Andric   char *ret = ctime_r(timep, buf);
953fe6060f1SDimitry Andric   if (ret) {
954fe6060f1SDimitry Andric     dfsan_set_label_origin(
955fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
956fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf,
957fe6060f1SDimitry Andric         strlen(buf) + 1);
958fe6060f1SDimitry Andric     *ret_label = buf_label;
959fe6060f1SDimitry Andric     *ret_origin = buf_origin;
960fe6060f1SDimitry Andric   } else {
961fe6060f1SDimitry Andric     *ret_label = 0;
962fe6060f1SDimitry Andric   }
963fe6060f1SDimitry Andric   return ret;
964fe6060f1SDimitry Andric }
965fe6060f1SDimitry Andric 
966fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
96768d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
96868d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
96968d75effSDimitry Andric                    dfsan_label *ret_label) {
97068d75effSDimitry Andric   char *ret = fgets(s, size, stream);
97168d75effSDimitry Andric   if (ret) {
97268d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
97368d75effSDimitry Andric     *ret_label = s_label;
97468d75effSDimitry Andric   } else {
97568d75effSDimitry Andric     *ret_label = 0;
97668d75effSDimitry Andric   }
97768d75effSDimitry Andric   return ret;
97868d75effSDimitry Andric }
97968d75effSDimitry Andric 
98068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
981fe6060f1SDimitry Andric char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
982fe6060f1SDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
983fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin s_origin,
984fe6060f1SDimitry Andric                    dfsan_origin size_origin, dfsan_origin stream_origin,
985fe6060f1SDimitry Andric                    dfsan_origin *ret_origin) {
986fe6060f1SDimitry Andric   char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label,
987fe6060f1SDimitry Andric                            ret_label);
988fe6060f1SDimitry Andric   if (ret)
989fe6060f1SDimitry Andric     *ret_origin = s_origin;
990fe6060f1SDimitry Andric   return ret;
991fe6060f1SDimitry Andric }
992fe6060f1SDimitry Andric 
993fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
99468d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
99568d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
99668d75effSDimitry Andric   char *ret = getcwd(buf, size);
99768d75effSDimitry Andric   if (ret) {
99868d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
99968d75effSDimitry Andric     *ret_label = buf_label;
100068d75effSDimitry Andric   } else {
100168d75effSDimitry Andric     *ret_label = 0;
100268d75effSDimitry Andric   }
100368d75effSDimitry Andric   return ret;
100468d75effSDimitry Andric }
100568d75effSDimitry Andric 
100668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1007fe6060f1SDimitry Andric char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label,
1008fe6060f1SDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label,
1009fe6060f1SDimitry Andric                     dfsan_origin buf_origin, dfsan_origin size_origin,
1010fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1011fe6060f1SDimitry Andric   char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label);
1012fe6060f1SDimitry Andric   if (ret)
1013fe6060f1SDimitry Andric     *ret_origin = buf_origin;
1014fe6060f1SDimitry Andric   return ret;
1015fe6060f1SDimitry Andric }
1016fe6060f1SDimitry Andric 
1017fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
101868d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
101968d75effSDimitry Andric   char *ret = get_current_dir_name();
1020fe6060f1SDimitry Andric   if (ret)
102168d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
102268d75effSDimitry Andric   *ret_label = 0;
102368d75effSDimitry Andric   return ret;
102468d75effSDimitry Andric }
102568d75effSDimitry Andric 
102668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1027fe6060f1SDimitry Andric char *__dfso_get_current_dir_name(dfsan_label *ret_label,
1028fe6060f1SDimitry Andric                                   dfsan_origin *ret_origin) {
1029fe6060f1SDimitry Andric   return __dfsw_get_current_dir_name(ret_label);
1030fe6060f1SDimitry Andric }
1031fe6060f1SDimitry Andric 
1032*349cc55cSDimitry Andric // This function is only available for glibc 2.25 or newer.  Mark it weak so
1033*349cc55cSDimitry Andric // linking succeeds with older glibcs.
1034*349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length);
1035*349cc55cSDimitry Andric 
1036*349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length,
1037*349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1038*349cc55cSDimitry Andric                                                     dfsan_label length_label,
1039*349cc55cSDimitry Andric                                                     dfsan_label *ret_label) {
1040*349cc55cSDimitry Andric   int ret = getentropy(buffer, length);
1041*349cc55cSDimitry Andric   if (ret == 0) {
1042*349cc55cSDimitry Andric     dfsan_set_label(0, buffer, length);
1043*349cc55cSDimitry Andric   }
1044*349cc55cSDimitry Andric   *ret_label = 0;
1045*349cc55cSDimitry Andric   return ret;
1046*349cc55cSDimitry Andric }
1047*349cc55cSDimitry Andric 
1048*349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length,
1049*349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1050*349cc55cSDimitry Andric                                                     dfsan_label length_label,
1051*349cc55cSDimitry Andric                                                     dfsan_label *ret_label,
1052*349cc55cSDimitry Andric                                                     dfsan_origin buffer_origin,
1053*349cc55cSDimitry Andric                                                     dfsan_origin length_origin,
1054*349cc55cSDimitry Andric                                                     dfsan_origin *ret_origin) {
1055*349cc55cSDimitry Andric   return __dfsw_getentropy(buffer, length, buffer_label, length_label,
1056*349cc55cSDimitry Andric                            ret_label);
1057*349cc55cSDimitry Andric }
1058*349cc55cSDimitry Andric 
1059fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
106068d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
106168d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
106268d75effSDimitry Andric   int ret = gethostname(name, len);
106368d75effSDimitry Andric   if (ret == 0) {
106468d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
106568d75effSDimitry Andric   }
106668d75effSDimitry Andric   *ret_label = 0;
106768d75effSDimitry Andric   return ret;
106868d75effSDimitry Andric }
106968d75effSDimitry Andric 
107068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1071fe6060f1SDimitry Andric int __dfso_gethostname(char *name, size_t len, dfsan_label name_label,
1072fe6060f1SDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label,
1073fe6060f1SDimitry Andric                        dfsan_origin name_origin, dfsan_origin len_origin,
1074fe6060f1SDimitry Andric                        dfsan_label *ret_origin) {
1075fe6060f1SDimitry Andric   return __dfsw_gethostname(name, len, name_label, len_label, ret_label);
1076fe6060f1SDimitry Andric }
1077fe6060f1SDimitry Andric 
1078fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
107968d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
108068d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
108168d75effSDimitry Andric                      dfsan_label *ret_label) {
108268d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
108368d75effSDimitry Andric   if (ret == 0) {
108468d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
108568d75effSDimitry Andric   }
108668d75effSDimitry Andric   *ret_label = 0;
108768d75effSDimitry Andric   return ret;
108868d75effSDimitry Andric }
108968d75effSDimitry Andric 
109068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1091fe6060f1SDimitry Andric int __dfso_getrlimit(int resource, struct rlimit *rlim,
1092fe6060f1SDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
1093fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin resource_origin,
1094fe6060f1SDimitry Andric                      dfsan_origin rlim_origin, dfsan_origin *ret_origin) {
1095fe6060f1SDimitry Andric   return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label,
1096fe6060f1SDimitry Andric                           ret_label);
1097fe6060f1SDimitry Andric }
1098fe6060f1SDimitry Andric 
1099fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
110068d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
110168d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
110268d75effSDimitry Andric   int ret = getrusage(who, usage);
110368d75effSDimitry Andric   if (ret == 0) {
110468d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
110568d75effSDimitry Andric   }
110668d75effSDimitry Andric   *ret_label = 0;
110768d75effSDimitry Andric   return ret;
110868d75effSDimitry Andric }
110968d75effSDimitry Andric 
111068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1111fe6060f1SDimitry Andric int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label,
1112fe6060f1SDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label,
1113fe6060f1SDimitry Andric                      dfsan_origin who_origin, dfsan_origin usage_origin,
1114fe6060f1SDimitry Andric                      dfsan_label *ret_origin) {
1115fe6060f1SDimitry Andric   return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label);
1116fe6060f1SDimitry Andric }
1117fe6060f1SDimitry Andric 
1118fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
111968d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
112068d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
1121*349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
112268d75effSDimitry Andric   if (ret) {
112368d75effSDimitry Andric     internal_memcpy(shadow_for(dest), shadow_for(src),
112468d75effSDimitry Andric                     sizeof(dfsan_label) * (strlen(src) + 1));
112568d75effSDimitry Andric   }
112668d75effSDimitry Andric   *ret_label = dst_label;
112768d75effSDimitry Andric   return ret;
112868d75effSDimitry Andric }
112968d75effSDimitry Andric 
113068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1131fe6060f1SDimitry Andric char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label,
1132fe6060f1SDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label,
1133fe6060f1SDimitry Andric                     dfsan_origin dst_origin, dfsan_origin src_origin,
1134fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1135*349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
1136fe6060f1SDimitry Andric   if (ret) {
1137fe6060f1SDimitry Andric     size_t str_len = strlen(src) + 1;
1138fe6060f1SDimitry Andric     dfsan_mem_origin_transfer(dest, src, str_len);
1139fe6060f1SDimitry Andric     internal_memcpy(shadow_for(dest), shadow_for(src),
1140fe6060f1SDimitry Andric                     sizeof(dfsan_label) * str_len);
114168d75effSDimitry Andric   }
1142fe6060f1SDimitry Andric   *ret_label = dst_label;
1143fe6060f1SDimitry Andric   *ret_origin = dst_origin;
1144fe6060f1SDimitry Andric   return ret;
1145fe6060f1SDimitry Andric }
1146fe6060f1SDimitry Andric 
1147fe6060f1SDimitry Andric static long int dfsan_strtol(const char *nptr, char **endptr, int base,
1148fe6060f1SDimitry Andric                              char **tmp_endptr) {
1149fe6060f1SDimitry Andric   assert(tmp_endptr);
1150fe6060f1SDimitry Andric   long int ret = strtol(nptr, tmp_endptr, base);
1151fe6060f1SDimitry Andric   if (endptr)
1152fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1153fe6060f1SDimitry Andric   return ret;
1154fe6060f1SDimitry Andric }
1155fe6060f1SDimitry Andric 
1156fe6060f1SDimitry Andric static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr,
1157fe6060f1SDimitry Andric                                   dfsan_label base_label,
1158fe6060f1SDimitry Andric                                   dfsan_label *ret_label) {
115968d75effSDimitry Andric   if (tmp_endptr > nptr) {
116068d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
116168d75effSDimitry Andric     *ret_label = dfsan_union(
116268d75effSDimitry Andric         base_label,
116368d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
116468d75effSDimitry Andric   } else {
116568d75effSDimitry Andric     *ret_label = 0;
116668d75effSDimitry Andric   }
1167fe6060f1SDimitry Andric }
1168fe6060f1SDimitry Andric 
1169fe6060f1SDimitry Andric static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr,
1170fe6060f1SDimitry Andric                                    dfsan_label base_label,
1171fe6060f1SDimitry Andric                                    dfsan_label *ret_label,
1172fe6060f1SDimitry Andric                                    dfsan_origin base_origin,
1173fe6060f1SDimitry Andric                                    dfsan_origin *ret_origin) {
1174fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1175fe6060f1SDimitry Andric     // When multiple inputs are tainted, we propagate one of its origins.
1176fe6060f1SDimitry Andric     // Because checking if base_label is tainted does not need additional
1177fe6060f1SDimitry Andric     // computation, we prefer to propagating base_origin.
1178fe6060f1SDimitry Andric     *ret_origin = base_label
1179fe6060f1SDimitry Andric                       ? base_origin
1180fe6060f1SDimitry Andric                       : dfsan_read_origin_of_first_taint(
1181fe6060f1SDimitry Andric                             nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1182fe6060f1SDimitry Andric   }
1183fe6060f1SDimitry Andric }
1184fe6060f1SDimitry Andric 
1185fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1186fe6060f1SDimitry Andric long int __dfsw_strtol(const char *nptr, char **endptr, int base,
1187fe6060f1SDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1188fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
1189fe6060f1SDimitry Andric   char *tmp_endptr;
1190fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1191fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
119268d75effSDimitry Andric   return ret;
119368d75effSDimitry Andric }
119468d75effSDimitry Andric 
119568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1196fe6060f1SDimitry Andric long int __dfso_strtol(const char *nptr, char **endptr, int base,
119768d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1198fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label,
1199fe6060f1SDimitry Andric                        dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1200fe6060f1SDimitry Andric                        dfsan_origin base_origin, dfsan_origin *ret_origin) {
120168d75effSDimitry Andric   char *tmp_endptr;
1202fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1203fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1204fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1205fe6060f1SDimitry Andric                          ret_origin);
1206fe6060f1SDimitry Andric   return ret;
120768d75effSDimitry Andric }
1208fe6060f1SDimitry Andric 
1209fe6060f1SDimitry Andric static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) {
1210fe6060f1SDimitry Andric   assert(tmp_endptr);
1211fe6060f1SDimitry Andric   double ret = strtod(nptr, tmp_endptr);
1212fe6060f1SDimitry Andric   if (endptr)
1213fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1214fe6060f1SDimitry Andric   return ret;
1215fe6060f1SDimitry Andric }
1216fe6060f1SDimitry Andric 
1217fe6060f1SDimitry Andric static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr,
1218fe6060f1SDimitry Andric                                dfsan_label *ret_label) {
121968d75effSDimitry Andric   if (tmp_endptr > nptr) {
122068d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
122168d75effSDimitry Andric     *ret_label = dfsan_read_label(
122268d75effSDimitry Andric         nptr,
122368d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
122468d75effSDimitry Andric   } else {
122568d75effSDimitry Andric     *ret_label = 0;
122668d75effSDimitry Andric   }
1227fe6060f1SDimitry Andric }
1228fe6060f1SDimitry Andric 
1229fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1230fe6060f1SDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1231fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label) {
1232fe6060f1SDimitry Andric   char *tmp_endptr;
1233fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1234fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1235fe6060f1SDimitry Andric   return ret;
1236fe6060f1SDimitry Andric }
1237fe6060f1SDimitry Andric 
1238fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1239fe6060f1SDimitry Andric double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1240fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label,
1241fe6060f1SDimitry Andric                      dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1242fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1243fe6060f1SDimitry Andric   char *tmp_endptr;
1244fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1245fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1246fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1247fe6060f1SDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
1248fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(
1249fe6060f1SDimitry Andric         nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1250fe6060f1SDimitry Andric   } else {
1251fe6060f1SDimitry Andric     *ret_origin = 0;
1252fe6060f1SDimitry Andric   }
1253fe6060f1SDimitry Andric   return ret;
1254fe6060f1SDimitry Andric }
1255fe6060f1SDimitry Andric 
1256fe6060f1SDimitry Andric static long long int dfsan_strtoll(const char *nptr, char **endptr, int base,
1257fe6060f1SDimitry Andric                                    char **tmp_endptr) {
1258fe6060f1SDimitry Andric   assert(tmp_endptr);
1259fe6060f1SDimitry Andric   long long int ret = strtoll(nptr, tmp_endptr, base);
1260fe6060f1SDimitry Andric   if (endptr)
1261fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
126268d75effSDimitry Andric   return ret;
126368d75effSDimitry Andric }
126468d75effSDimitry Andric 
126568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
126668d75effSDimitry Andric long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
126768d75effSDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
126868d75effSDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label) {
126968d75effSDimitry Andric   char *tmp_endptr;
1270fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1271fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1272fe6060f1SDimitry Andric   return ret;
127368d75effSDimitry Andric }
1274fe6060f1SDimitry Andric 
1275fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1276fe6060f1SDimitry Andric long long int __dfso_strtoll(const char *nptr, char **endptr, int base,
1277fe6060f1SDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
1278fe6060f1SDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label,
1279fe6060f1SDimitry Andric                              dfsan_origin nptr_origin,
1280fe6060f1SDimitry Andric                              dfsan_origin endptr_origin,
1281fe6060f1SDimitry Andric                              dfsan_origin base_origin,
1282fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1283fe6060f1SDimitry Andric   char *tmp_endptr;
1284fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1285fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1286fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1287fe6060f1SDimitry Andric                          ret_origin);
1288fe6060f1SDimitry Andric   return ret;
128968d75effSDimitry Andric }
1290fe6060f1SDimitry Andric 
1291fe6060f1SDimitry Andric static unsigned long int dfsan_strtoul(const char *nptr, char **endptr,
1292fe6060f1SDimitry Andric                                        int base, char **tmp_endptr) {
1293fe6060f1SDimitry Andric   assert(tmp_endptr);
1294fe6060f1SDimitry Andric   unsigned long int ret = strtoul(nptr, tmp_endptr, base);
1295fe6060f1SDimitry Andric   if (endptr)
1296fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
129768d75effSDimitry Andric   return ret;
129868d75effSDimitry Andric }
129968d75effSDimitry Andric 
130068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
130168d75effSDimitry Andric unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
130268d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
130368d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
130468d75effSDimitry Andric   char *tmp_endptr;
1305fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1306fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1307fe6060f1SDimitry Andric   return ret;
130868d75effSDimitry Andric }
1309fe6060f1SDimitry Andric 
1310fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1311fe6060f1SDimitry Andric unsigned long int __dfso_strtoul(
1312fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1313fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1314fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1315fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1316fe6060f1SDimitry Andric   char *tmp_endptr;
1317fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1318fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1319fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1320fe6060f1SDimitry Andric                          ret_origin);
1321fe6060f1SDimitry Andric   return ret;
132268d75effSDimitry Andric }
1323fe6060f1SDimitry Andric 
1324fe6060f1SDimitry Andric static long long unsigned int dfsan_strtoull(const char *nptr, char **endptr,
1325fe6060f1SDimitry Andric                                              int base, char **tmp_endptr) {
1326fe6060f1SDimitry Andric   assert(tmp_endptr);
1327fe6060f1SDimitry Andric   long long unsigned int ret = strtoull(nptr, tmp_endptr, base);
1328fe6060f1SDimitry Andric   if (endptr)
1329fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
133068d75effSDimitry Andric   return ret;
133168d75effSDimitry Andric }
133268d75effSDimitry Andric 
133368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
133468d75effSDimitry Andric long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
1335e8d8bef9SDimitry Andric                                        int base, dfsan_label nptr_label,
1336e8d8bef9SDimitry Andric                                        dfsan_label endptr_label,
133768d75effSDimitry Andric                                        dfsan_label base_label,
133868d75effSDimitry Andric                                        dfsan_label *ret_label) {
133968d75effSDimitry Andric   char *tmp_endptr;
1340fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1341fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1342fe6060f1SDimitry Andric   return ret;
134368d75effSDimitry Andric }
1344fe6060f1SDimitry Andric 
1345fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1346fe6060f1SDimitry Andric long long unsigned int __dfso_strtoull(
1347fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1348fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1349fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1350fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1351fe6060f1SDimitry Andric   char *tmp_endptr;
1352fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1353fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1354fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1355fe6060f1SDimitry Andric                          ret_origin);
135668d75effSDimitry Andric   return ret;
135768d75effSDimitry Andric }
135868d75effSDimitry Andric 
135968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
136068d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
136168d75effSDimitry Andric   time_t ret = time(t);
136268d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
136368d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
136468d75effSDimitry Andric   }
136568d75effSDimitry Andric   *ret_label = 0;
136668d75effSDimitry Andric   return ret;
136768d75effSDimitry Andric }
136868d75effSDimitry Andric 
136968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1370fe6060f1SDimitry Andric time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label,
1371fe6060f1SDimitry Andric                    dfsan_origin t_origin, dfsan_origin *ret_origin) {
1372fe6060f1SDimitry Andric   return __dfsw_time(t, t_label, ret_label);
1373fe6060f1SDimitry Andric }
1374fe6060f1SDimitry Andric 
1375fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
137668d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
137768d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
137868d75effSDimitry Andric                      dfsan_label *ret_label) {
137968d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
138068d75effSDimitry Andric   if (ret == 1) {
138168d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
138268d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
138368d75effSDimitry Andric   }
138468d75effSDimitry Andric   *ret_label = 0;
138568d75effSDimitry Andric   return ret;
138668d75effSDimitry Andric }
138768d75effSDimitry Andric 
138868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1389fe6060f1SDimitry Andric int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
1390fe6060f1SDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
1391fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin af_origin,
1392fe6060f1SDimitry Andric                      dfsan_origin src_origin, dfsan_origin dst_origin,
1393fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1394fe6060f1SDimitry Andric   int ret = inet_pton(af, src, dst);
1395fe6060f1SDimitry Andric   if (ret == 1) {
1396fe6060f1SDimitry Andric     int src_len = strlen(src) + 1;
1397fe6060f1SDimitry Andric     dfsan_set_label_origin(
1398fe6060f1SDimitry Andric         dfsan_read_label(src, src_len),
1399fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(src, src_len), dst,
1400fe6060f1SDimitry Andric         af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
1401fe6060f1SDimitry Andric   }
1402fe6060f1SDimitry Andric   *ret_label = 0;
1403fe6060f1SDimitry Andric   return ret;
1404fe6060f1SDimitry Andric }
1405fe6060f1SDimitry Andric 
1406fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
140768d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
140868d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
140968d75effSDimitry Andric                               dfsan_label *ret_label) {
141068d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
141168d75effSDimitry Andric   if (ret) {
141268d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
141368d75effSDimitry Andric                     sizeof(struct tm));
141468d75effSDimitry Andric     *ret_label = result_label;
141568d75effSDimitry Andric   } else {
141668d75effSDimitry Andric     *ret_label = 0;
141768d75effSDimitry Andric   }
141868d75effSDimitry Andric   return ret;
141968d75effSDimitry Andric }
142068d75effSDimitry Andric 
142168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1422fe6060f1SDimitry Andric struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result,
1423fe6060f1SDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
1424fe6060f1SDimitry Andric                               dfsan_label *ret_label, dfsan_origin timep_origin,
1425fe6060f1SDimitry Andric                               dfsan_origin result_origin,
1426fe6060f1SDimitry Andric                               dfsan_origin *ret_origin) {
1427fe6060f1SDimitry Andric   struct tm *ret = localtime_r(timep, result);
1428fe6060f1SDimitry Andric   if (ret) {
1429fe6060f1SDimitry Andric     dfsan_set_label_origin(
1430fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1431fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result,
1432fe6060f1SDimitry Andric         sizeof(struct tm));
1433fe6060f1SDimitry Andric     *ret_label = result_label;
1434fe6060f1SDimitry Andric     *ret_origin = result_origin;
1435fe6060f1SDimitry Andric   } else {
1436fe6060f1SDimitry Andric     *ret_label = 0;
1437fe6060f1SDimitry Andric   }
1438fe6060f1SDimitry Andric   return ret;
1439fe6060f1SDimitry Andric }
1440fe6060f1SDimitry Andric 
1441fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
144268d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
144368d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
144468d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
144568d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
144668d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
144768d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
144868d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
144968d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
145068d75effSDimitry Andric   if (ret == 0) {
145168d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
145268d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
145368d75effSDimitry Andric   }
145468d75effSDimitry Andric   *ret_label = 0;
145568d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
145668d75effSDimitry Andric   return ret;
145768d75effSDimitry Andric }
145868d75effSDimitry Andric 
145968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1460fe6060f1SDimitry Andric int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen,
1461fe6060f1SDimitry Andric                       struct passwd **result, dfsan_label uid_label,
1462fe6060f1SDimitry Andric                       dfsan_label pwd_label, dfsan_label buf_label,
1463fe6060f1SDimitry Andric                       dfsan_label buflen_label, dfsan_label result_label,
1464fe6060f1SDimitry Andric                       dfsan_label *ret_label, dfsan_origin uid_origin,
1465fe6060f1SDimitry Andric                       dfsan_origin pwd_origin, dfsan_origin buf_origin,
1466fe6060f1SDimitry Andric                       dfsan_origin buflen_origin, dfsan_origin result_origin,
1467fe6060f1SDimitry Andric                       dfsan_origin *ret_origin) {
1468fe6060f1SDimitry Andric   return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label,
1469fe6060f1SDimitry Andric                            buf_label, buflen_label, result_label, ret_label);
1470fe6060f1SDimitry Andric }
1471fe6060f1SDimitry Andric 
1472fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1473e8d8bef9SDimitry Andric int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1474e8d8bef9SDimitry Andric                       int timeout, dfsan_label epfd_label,
1475e8d8bef9SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1476e8d8bef9SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label) {
1477e8d8bef9SDimitry Andric   int ret = epoll_wait(epfd, events, maxevents, timeout);
1478e8d8bef9SDimitry Andric   if (ret > 0)
1479e8d8bef9SDimitry Andric     dfsan_set_label(0, events, ret * sizeof(*events));
1480e8d8bef9SDimitry Andric   *ret_label = 0;
1481e8d8bef9SDimitry Andric   return ret;
1482e8d8bef9SDimitry Andric }
1483e8d8bef9SDimitry Andric 
1484e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1485fe6060f1SDimitry Andric int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1486fe6060f1SDimitry Andric                       int timeout, dfsan_label epfd_label,
1487fe6060f1SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1488fe6060f1SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label,
1489fe6060f1SDimitry Andric                       dfsan_origin epfd_origin, dfsan_origin events_origin,
1490fe6060f1SDimitry Andric                       dfsan_origin maxevents_origin,
1491fe6060f1SDimitry Andric                       dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1492fe6060f1SDimitry Andric   return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label,
1493fe6060f1SDimitry Andric                            events_label, maxevents_label, timeout_label,
1494fe6060f1SDimitry Andric                            ret_label);
1495fe6060f1SDimitry Andric }
1496fe6060f1SDimitry Andric 
1497fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
149868d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
149968d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
150068d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
150168d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
150268d75effSDimitry Andric   if (ret >= 0) {
150368d75effSDimitry Andric     for (; nfds > 0; --nfds) {
150468d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
150568d75effSDimitry Andric     }
150668d75effSDimitry Andric   }
150768d75effSDimitry Andric   *ret_label = 0;
150868d75effSDimitry Andric   return ret;
150968d75effSDimitry Andric }
151068d75effSDimitry Andric 
151168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1512fe6060f1SDimitry Andric int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout,
1513fe6060f1SDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
1514fe6060f1SDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label,
1515fe6060f1SDimitry Andric                 dfsan_origin dfs_origin, dfsan_origin nfds_origin,
1516fe6060f1SDimitry Andric                 dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1517fe6060f1SDimitry Andric   return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label,
1518fe6060f1SDimitry Andric                      ret_label);
1519fe6060f1SDimitry Andric }
1520fe6060f1SDimitry Andric 
1521fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
152268d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
152368d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
152468d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
152568d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
152668d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
152768d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
152868d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
152968d75effSDimitry Andric   // undefined.
153068d75effSDimitry Andric   if (readfds) {
153168d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
153268d75effSDimitry Andric   }
153368d75effSDimitry Andric   if (writefds) {
153468d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
153568d75effSDimitry Andric   }
153668d75effSDimitry Andric   if (exceptfds) {
153768d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
153868d75effSDimitry Andric   }
153968d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
154068d75effSDimitry Andric   *ret_label = 0;
154168d75effSDimitry Andric   return ret;
154268d75effSDimitry Andric }
154368d75effSDimitry Andric 
154468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1545fe6060f1SDimitry Andric int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds,
1546fe6060f1SDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
1547fe6060f1SDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
1548fe6060f1SDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
1549fe6060f1SDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label,
1550fe6060f1SDimitry Andric                   dfsan_origin nfds_origin, dfsan_origin readfds_origin,
1551fe6060f1SDimitry Andric                   dfsan_origin writefds_origin, dfsan_origin exceptfds_origin,
1552fe6060f1SDimitry Andric                   dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1553fe6060f1SDimitry Andric   return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label,
1554fe6060f1SDimitry Andric                        readfds_label, writefds_label, exceptfds_label,
1555fe6060f1SDimitry Andric                        timeout_label, ret_label);
1556fe6060f1SDimitry Andric }
1557fe6060f1SDimitry Andric 
1558fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
155968d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
156068d75effSDimitry Andric                              dfsan_label pid_label,
156168d75effSDimitry Andric                              dfsan_label cpusetsize_label,
156268d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
156368d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
156468d75effSDimitry Andric   if (ret == 0) {
156568d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
156668d75effSDimitry Andric   }
156768d75effSDimitry Andric   *ret_label = 0;
156868d75effSDimitry Andric   return ret;
156968d75effSDimitry Andric }
157068d75effSDimitry Andric 
157168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1572fe6060f1SDimitry Andric int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
1573fe6060f1SDimitry Andric                              dfsan_label pid_label,
1574fe6060f1SDimitry Andric                              dfsan_label cpusetsize_label,
1575fe6060f1SDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label,
1576fe6060f1SDimitry Andric                              dfsan_origin pid_origin,
1577fe6060f1SDimitry Andric                              dfsan_origin cpusetsize_origin,
1578fe6060f1SDimitry Andric                              dfsan_origin mask_origin,
1579fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1580fe6060f1SDimitry Andric   return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label,
1581fe6060f1SDimitry Andric                                   cpusetsize_label, mask_label, ret_label);
1582fe6060f1SDimitry Andric }
1583fe6060f1SDimitry Andric 
1584fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
158568d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
158668d75effSDimitry Andric                        dfsan_label *ret_label) {
158768d75effSDimitry Andric   int ret = sigemptyset(set);
158868d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
1589fe6060f1SDimitry Andric   *ret_label = 0;
159068d75effSDimitry Andric   return ret;
159168d75effSDimitry Andric }
159268d75effSDimitry Andric 
159368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1594fe6060f1SDimitry Andric int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
1595fe6060f1SDimitry Andric                        dfsan_label *ret_label, dfsan_origin set_origin,
1596fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1597fe6060f1SDimitry Andric   return __dfsw_sigemptyset(set, set_label, ret_label);
1598fe6060f1SDimitry Andric }
1599fe6060f1SDimitry Andric 
1600fe6060f1SDimitry Andric class SignalHandlerScope {
1601fe6060f1SDimitry Andric  public:
1602fe6060f1SDimitry Andric   SignalHandlerScope() {
1603fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1604fe6060f1SDimitry Andric       t->EnterSignalHandler();
1605fe6060f1SDimitry Andric   }
1606fe6060f1SDimitry Andric   ~SignalHandlerScope() {
1607fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1608fe6060f1SDimitry Andric       t->LeaveSignalHandler();
1609fe6060f1SDimitry Andric   }
1610fe6060f1SDimitry Andric };
1611fe6060f1SDimitry Andric 
1612fe6060f1SDimitry Andric // Clear DFSan runtime TLS state at the end of a scope.
1613fe6060f1SDimitry Andric //
1614fe6060f1SDimitry Andric // Implementation must be async-signal-safe and use small data size, because
1615fe6060f1SDimitry Andric // instances of this class may live on the signal handler stack.
1616fe6060f1SDimitry Andric //
1617fe6060f1SDimitry Andric // DFSan uses TLS to pass metadata of arguments and return values. When an
1618fe6060f1SDimitry Andric // instrumented function accesses the TLS, if a signal callback happens, and the
1619fe6060f1SDimitry Andric // callback calls other instrumented functions with updating the same TLS, the
1620fe6060f1SDimitry Andric // TLS is in an inconsistent state after the callback ends. This may cause
1621fe6060f1SDimitry Andric // either under-tainting or over-tainting.
1622fe6060f1SDimitry Andric //
1623fe6060f1SDimitry Andric // The current implementation simply resets TLS at restore. This prevents from
1624fe6060f1SDimitry Andric // over-tainting. Although under-tainting may still happen, a taint flow can be
1625fe6060f1SDimitry Andric // found eventually if we run a DFSan-instrumented program multiple times. The
1626fe6060f1SDimitry Andric // alternative option is saving the entire TLS. However the TLS storage takes
1627fe6060f1SDimitry Andric // 2k bytes, and signal calls could be nested. So it does not seem worth.
1628fe6060f1SDimitry Andric class ScopedClearThreadLocalState {
1629fe6060f1SDimitry Andric  public:
1630fe6060f1SDimitry Andric   ScopedClearThreadLocalState() {}
1631fe6060f1SDimitry Andric   ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); }
1632fe6060f1SDimitry Andric };
1633fe6060f1SDimitry Andric 
1634fe6060f1SDimitry Andric // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls.
1635fe6060f1SDimitry Andric const int kMaxSignals = 1024;
1636fe6060f1SDimitry Andric static atomic_uintptr_t sigactions[kMaxSignals];
1637fe6060f1SDimitry Andric 
1638fe6060f1SDimitry Andric static void SignalHandler(int signo) {
1639fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1640fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1641fe6060f1SDimitry Andric 
1642fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. This is why DFSan
1643fe6060f1SDimitry Andric   // instrumentation generates a trampoline function to each function pointer,
1644fe6060f1SDimitry Andric   // and uses the trampoline to clear shadows. However sigaction does not use
1645fe6060f1SDimitry Andric   // a function pointer directly, so we have to do this manually.
1646fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, sizeof(dfsan_label));
1647fe6060f1SDimitry Andric 
1648fe6060f1SDimitry Andric   typedef void (*signal_cb)(int x);
1649fe6060f1SDimitry Andric   signal_cb cb =
1650fe6060f1SDimitry Andric       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1651fe6060f1SDimitry Andric   cb(signo);
1652fe6060f1SDimitry Andric }
1653fe6060f1SDimitry Andric 
1654fe6060f1SDimitry Andric static void SignalAction(int signo, siginfo_t *si, void *uc) {
1655fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1656fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1657fe6060f1SDimitry Andric 
1658fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. Similar to SignalHandler.
1659fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label));
1660fe6060f1SDimitry Andric   dfsan_set_label(0, si, sizeof(*si));
1661fe6060f1SDimitry Andric   dfsan_set_label(0, uc, sizeof(ucontext_t));
1662fe6060f1SDimitry Andric 
1663fe6060f1SDimitry Andric   typedef void (*sigaction_cb)(int, siginfo_t *, void *);
1664fe6060f1SDimitry Andric   sigaction_cb cb =
1665fe6060f1SDimitry Andric       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1666fe6060f1SDimitry Andric   cb(signo, si, uc);
1667fe6060f1SDimitry Andric }
1668fe6060f1SDimitry Andric 
1669fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
167068d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
167168d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
167268d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
167368d75effSDimitry Andric                      dfsan_label *ret_label) {
1674fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1675fe6060f1SDimitry Andric   SignalSpinLocker lock;
1676fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1677fe6060f1SDimitry Andric   struct sigaction new_act;
1678fe6060f1SDimitry Andric   struct sigaction *pnew_act = act ? &new_act : nullptr;
1679fe6060f1SDimitry Andric   if (act) {
1680fe6060f1SDimitry Andric     internal_memcpy(pnew_act, act, sizeof(struct sigaction));
1681fe6060f1SDimitry Andric     if (pnew_act->sa_flags & SA_SIGINFO) {
1682fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_sigaction);
1683fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1684fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1685fe6060f1SDimitry Andric         pnew_act->sa_sigaction = SignalAction;
1686fe6060f1SDimitry Andric       }
1687fe6060f1SDimitry Andric     } else {
1688fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_handler);
1689fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1690fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1691fe6060f1SDimitry Andric         pnew_act->sa_handler = SignalHandler;
1692fe6060f1SDimitry Andric       }
1693fe6060f1SDimitry Andric     }
1694fe6060f1SDimitry Andric   }
1695fe6060f1SDimitry Andric 
1696fe6060f1SDimitry Andric   int ret = sigaction(signum, pnew_act, oldact);
1697fe6060f1SDimitry Andric 
1698fe6060f1SDimitry Andric   if (ret == 0 && oldact) {
1699fe6060f1SDimitry Andric     if (oldact->sa_flags & SA_SIGINFO) {
1700fe6060f1SDimitry Andric       if (oldact->sa_sigaction == SignalAction)
1701fe6060f1SDimitry Andric         oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb;
1702fe6060f1SDimitry Andric     } else {
1703fe6060f1SDimitry Andric       if (oldact->sa_handler == SignalHandler)
1704fe6060f1SDimitry Andric         oldact->sa_handler = (decltype(oldact->sa_handler))old_cb;
1705fe6060f1SDimitry Andric     }
1706fe6060f1SDimitry Andric   }
1707fe6060f1SDimitry Andric 
170868d75effSDimitry Andric   if (oldact) {
170968d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
171068d75effSDimitry Andric   }
171168d75effSDimitry Andric   *ret_label = 0;
171268d75effSDimitry Andric   return ret;
171368d75effSDimitry Andric }
171468d75effSDimitry Andric 
171568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1716fe6060f1SDimitry Andric int __dfso_sigaction(int signum, const struct sigaction *act,
1717fe6060f1SDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
1718fe6060f1SDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
1719fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin signum_origin,
1720fe6060f1SDimitry Andric                      dfsan_origin act_origin, dfsan_origin oldact_origin,
1721fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1722fe6060f1SDimitry Andric   return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
1723fe6060f1SDimitry Andric                           oldact_label, ret_label);
1724fe6060f1SDimitry Andric }
1725fe6060f1SDimitry Andric 
1726fe6060f1SDimitry Andric static sighandler_t dfsan_signal(int signum, sighandler_t handler,
1727fe6060f1SDimitry Andric                                  dfsan_label *ret_label) {
1728fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1729fe6060f1SDimitry Andric   SignalSpinLocker lock;
1730fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1731fe6060f1SDimitry Andric   if (handler != SIG_IGN && handler != SIG_DFL) {
1732fe6060f1SDimitry Andric     atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
1733fe6060f1SDimitry Andric     handler = &SignalHandler;
1734fe6060f1SDimitry Andric   }
1735fe6060f1SDimitry Andric 
1736fe6060f1SDimitry Andric   sighandler_t ret = signal(signum, handler);
1737fe6060f1SDimitry Andric 
1738fe6060f1SDimitry Andric   if (ret == SignalHandler)
1739fe6060f1SDimitry Andric     ret = (sighandler_t)old_cb;
1740fe6060f1SDimitry Andric 
1741fe6060f1SDimitry Andric   *ret_label = 0;
1742fe6060f1SDimitry Andric   return ret;
1743fe6060f1SDimitry Andric }
1744fe6060f1SDimitry Andric 
1745fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1746fe6060f1SDimitry Andric sighandler_t __dfsw_signal(int signum,
1747fe6060f1SDimitry Andric                            void *(*handler_trampoline)(void *, int, dfsan_label,
1748fe6060f1SDimitry Andric                                                        dfsan_label *),
1749fe6060f1SDimitry Andric                            sighandler_t handler, dfsan_label signum_label,
1750fe6060f1SDimitry Andric                            dfsan_label handler_label, dfsan_label *ret_label) {
1751fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1752fe6060f1SDimitry Andric }
1753fe6060f1SDimitry Andric 
1754fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1755fe6060f1SDimitry Andric sighandler_t __dfso_signal(
1756fe6060f1SDimitry Andric     int signum,
1757fe6060f1SDimitry Andric     void *(*handler_trampoline)(void *, int, dfsan_label, dfsan_label *,
1758fe6060f1SDimitry Andric                                 dfsan_origin, dfsan_origin *),
1759fe6060f1SDimitry Andric     sighandler_t handler, dfsan_label signum_label, dfsan_label handler_label,
1760fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin signum_origin,
1761fe6060f1SDimitry Andric     dfsan_origin handler_origin, dfsan_origin *ret_origin) {
1762fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1763fe6060f1SDimitry Andric }
1764fe6060f1SDimitry Andric 
1765fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1766e8d8bef9SDimitry Andric int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1767e8d8bef9SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label) {
1768e8d8bef9SDimitry Andric   int ret = sigaltstack(ss, old_ss);
1769e8d8bef9SDimitry Andric   if (ret != -1 && old_ss)
1770e8d8bef9SDimitry Andric     dfsan_set_label(0, old_ss, sizeof(*old_ss));
1771e8d8bef9SDimitry Andric   *ret_label = 0;
1772e8d8bef9SDimitry Andric   return ret;
1773e8d8bef9SDimitry Andric }
1774e8d8bef9SDimitry Andric 
1775e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1776fe6060f1SDimitry Andric int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1777fe6060f1SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label,
1778fe6060f1SDimitry Andric                        dfsan_origin ss_origin, dfsan_origin old_ss_origin,
1779fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1780fe6060f1SDimitry Andric   return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
1781fe6060f1SDimitry Andric }
1782fe6060f1SDimitry Andric 
1783fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
178468d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
178568d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
178668d75effSDimitry Andric                         dfsan_label *ret_label) {
178768d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
178868d75effSDimitry Andric   if (tv) {
178968d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
179068d75effSDimitry Andric   }
179168d75effSDimitry Andric   if (tz) {
179268d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
179368d75effSDimitry Andric   }
179468d75effSDimitry Andric   *ret_label = 0;
179568d75effSDimitry Andric   return ret;
179668d75effSDimitry Andric }
179768d75effSDimitry Andric 
1798fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1799fe6060f1SDimitry Andric int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz,
1800fe6060f1SDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
1801fe6060f1SDimitry Andric                         dfsan_label *ret_label, dfsan_origin tv_origin,
1802fe6060f1SDimitry Andric                         dfsan_origin tz_origin, dfsan_origin *ret_origin) {
1803fe6060f1SDimitry Andric   return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label);
1804fe6060f1SDimitry Andric }
1805fe6060f1SDimitry Andric 
180668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
180768d75effSDimitry Andric                                                   dfsan_label s_label,
180868d75effSDimitry Andric                                                   dfsan_label c_label,
180968d75effSDimitry Andric                                                   dfsan_label n_label,
181068d75effSDimitry Andric                                                   dfsan_label *ret_label) {
181168d75effSDimitry Andric   void *ret = memchr(s, c, n);
181268d75effSDimitry Andric   if (flags().strict_data_dependencies) {
181368d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
181468d75effSDimitry Andric   } else {
181568d75effSDimitry Andric     size_t len =
181668d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
181768d75effSDimitry Andric             : n;
181868d75effSDimitry Andric     *ret_label =
181968d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
182068d75effSDimitry Andric   }
182168d75effSDimitry Andric   return ret;
182268d75effSDimitry Andric }
182368d75effSDimitry Andric 
1824fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr(
1825fe6060f1SDimitry Andric     void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label,
1826fe6060f1SDimitry Andric     dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin,
1827fe6060f1SDimitry Andric     dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) {
1828fe6060f1SDimitry Andric   void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label);
1829fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1830fe6060f1SDimitry Andric     if (ret)
1831fe6060f1SDimitry Andric       *ret_origin = s_origin;
1832fe6060f1SDimitry Andric   } else {
1833fe6060f1SDimitry Andric     size_t len =
1834fe6060f1SDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
1835fe6060f1SDimitry Andric             : n;
1836fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, len);
1837fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1838fe6060f1SDimitry Andric   }
1839fe6060f1SDimitry Andric   return ret;
1840fe6060f1SDimitry Andric }
1841fe6060f1SDimitry Andric 
184268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
184368d75effSDimitry Andric                                                    dfsan_label s_label,
184468d75effSDimitry Andric                                                    dfsan_label c_label,
184568d75effSDimitry Andric                                                    dfsan_label *ret_label) {
184668d75effSDimitry Andric   char *ret = strrchr(s, c);
184768d75effSDimitry Andric   if (flags().strict_data_dependencies) {
184868d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
184968d75effSDimitry Andric   } else {
185068d75effSDimitry Andric     *ret_label =
185168d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
185268d75effSDimitry Andric                     dfsan_union(s_label, c_label));
185368d75effSDimitry Andric   }
185468d75effSDimitry Andric 
185568d75effSDimitry Andric   return ret;
185668d75effSDimitry Andric }
185768d75effSDimitry Andric 
1858fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr(
1859fe6060f1SDimitry Andric     char *s, int c, dfsan_label s_label, dfsan_label c_label,
1860fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
1861fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
1862fe6060f1SDimitry Andric   char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label);
1863fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1864fe6060f1SDimitry Andric     if (ret)
1865fe6060f1SDimitry Andric       *ret_origin = s_origin;
1866fe6060f1SDimitry Andric   } else {
1867fe6060f1SDimitry Andric     size_t s_len = strlen(s) + 1;
1868fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len);
1869fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1870fe6060f1SDimitry Andric   }
1871fe6060f1SDimitry Andric 
1872fe6060f1SDimitry Andric   return ret;
1873fe6060f1SDimitry Andric }
1874fe6060f1SDimitry Andric 
187568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
187668d75effSDimitry Andric                                                   dfsan_label haystack_label,
187768d75effSDimitry Andric                                                   dfsan_label needle_label,
187868d75effSDimitry Andric                                                   dfsan_label *ret_label) {
187968d75effSDimitry Andric   char *ret = strstr(haystack, needle);
188068d75effSDimitry Andric   if (flags().strict_data_dependencies) {
188168d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
188268d75effSDimitry Andric   } else {
188368d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
188468d75effSDimitry Andric     *ret_label =
188568d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
188668d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
188768d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
188868d75effSDimitry Andric   }
188968d75effSDimitry Andric 
189068d75effSDimitry Andric   return ret;
189168d75effSDimitry Andric }
189268d75effSDimitry Andric 
1893fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle,
1894fe6060f1SDimitry Andric                                                   dfsan_label haystack_label,
1895fe6060f1SDimitry Andric                                                   dfsan_label needle_label,
1896fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
1897fe6060f1SDimitry Andric                                                   dfsan_origin haystack_origin,
1898fe6060f1SDimitry Andric                                                   dfsan_origin needle_origin,
1899fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
1900fe6060f1SDimitry Andric   char *ret =
1901fe6060f1SDimitry Andric       __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label);
1902fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1903fe6060f1SDimitry Andric     if (ret)
1904fe6060f1SDimitry Andric       *ret_origin = haystack_origin;
1905fe6060f1SDimitry Andric   } else {
1906fe6060f1SDimitry Andric     size_t needle_len = strlen(needle);
1907fe6060f1SDimitry Andric     size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1;
1908fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len);
1909fe6060f1SDimitry Andric     if (o) {
1910fe6060f1SDimitry Andric       *ret_origin = o;
1911fe6060f1SDimitry Andric     } else {
1912fe6060f1SDimitry Andric       o = dfsan_read_origin_of_first_taint(needle, needle_len + 1);
1913fe6060f1SDimitry Andric       *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin);
1914fe6060f1SDimitry Andric     }
1915fe6060f1SDimitry Andric   }
1916fe6060f1SDimitry Andric 
1917fe6060f1SDimitry Andric   return ret;
1918fe6060f1SDimitry Andric }
1919fe6060f1SDimitry Andric 
192068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
192168d75effSDimitry Andric                                                    struct timespec *rem,
192268d75effSDimitry Andric                                                    dfsan_label req_label,
192368d75effSDimitry Andric                                                    dfsan_label rem_label,
192468d75effSDimitry Andric                                                    dfsan_label *ret_label) {
192568d75effSDimitry Andric   int ret = nanosleep(req, rem);
192668d75effSDimitry Andric   *ret_label = 0;
192768d75effSDimitry Andric   if (ret == -1) {
192868d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
192968d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
193068d75effSDimitry Andric   }
193168d75effSDimitry Andric   return ret;
193268d75effSDimitry Andric }
193368d75effSDimitry Andric 
1934fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
1935fe6060f1SDimitry Andric     const struct timespec *req, struct timespec *rem, dfsan_label req_label,
1936fe6060f1SDimitry Andric     dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin,
1937fe6060f1SDimitry Andric     dfsan_origin rem_origin, dfsan_origin *ret_origin) {
1938fe6060f1SDimitry Andric   return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
1939fe6060f1SDimitry Andric }
1940fe6060f1SDimitry Andric 
1941e8d8bef9SDimitry Andric static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) {
1942e8d8bef9SDimitry Andric   dfsan_set_label(0, msg, sizeof(*msg));
1943e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
1944e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
1945e8d8bef9SDimitry Andric   for (size_t i = 0; bytes_written > 0; ++i) {
1946e8d8bef9SDimitry Andric     assert(i < msg->msg_iovlen);
1947e8d8bef9SDimitry Andric     struct iovec *iov = &msg->msg_iov[i];
1948e8d8bef9SDimitry Andric     size_t iov_written =
1949e8d8bef9SDimitry Andric         bytes_written < iov->iov_len ? bytes_written : iov->iov_len;
1950e8d8bef9SDimitry Andric     dfsan_set_label(0, iov->iov_base, iov_written);
1951e8d8bef9SDimitry Andric     bytes_written -= iov_written;
1952e8d8bef9SDimitry Andric   }
1953e8d8bef9SDimitry Andric }
1954e8d8bef9SDimitry Andric 
1955e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
1956e8d8bef9SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1957e8d8bef9SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1958e8d8bef9SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1959e8d8bef9SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label) {
1960e8d8bef9SDimitry Andric   int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
1961e8d8bef9SDimitry Andric   for (int i = 0; i < ret; ++i) {
1962e8d8bef9SDimitry Andric     dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
1963e8d8bef9SDimitry Andric     clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr);
1964e8d8bef9SDimitry Andric   }
1965e8d8bef9SDimitry Andric   *ret_label = 0;
1966e8d8bef9SDimitry Andric   return ret;
1967e8d8bef9SDimitry Andric }
1968e8d8bef9SDimitry Andric 
1969fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg(
1970fe6060f1SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1971fe6060f1SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1972fe6060f1SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1973fe6060f1SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label,
1974fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msgvec_origin,
1975fe6060f1SDimitry Andric     dfsan_origin vlen_origin, dfsan_origin flags_origin,
1976fe6060f1SDimitry Andric     dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1977fe6060f1SDimitry Andric   return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label,
1978fe6060f1SDimitry Andric                          msgvec_label, vlen_label, flags_label, timeout_label,
1979fe6060f1SDimitry Andric                          ret_label);
1980fe6060f1SDimitry Andric }
1981fe6060f1SDimitry Andric 
1982e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
1983e8d8bef9SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1984e8d8bef9SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
1985e8d8bef9SDimitry Andric   ssize_t ret = recvmsg(sockfd, msg, flags);
1986e8d8bef9SDimitry Andric   if (ret >= 0)
1987e8d8bef9SDimitry Andric     clear_msghdr_labels(ret, msg);
1988e8d8bef9SDimitry Andric   *ret_label = 0;
1989e8d8bef9SDimitry Andric   return ret;
1990e8d8bef9SDimitry Andric }
1991e8d8bef9SDimitry Andric 
1992fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg(
1993fe6060f1SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1994fe6060f1SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label,
1995fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msg_origin,
1996fe6060f1SDimitry Andric     dfsan_origin flags_origin, dfsan_origin *ret_origin) {
1997fe6060f1SDimitry Andric   return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label,
1998fe6060f1SDimitry Andric                         flags_label, ret_label);
1999fe6060f1SDimitry Andric }
2000fe6060f1SDimitry Andric 
200168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
200268d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
200368d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
200468d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
200568d75effSDimitry Andric                   dfsan_label *ret_label) {
200668d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
200768d75effSDimitry Andric   *ret_label = 0;
200868d75effSDimitry Andric   if (ret == 0) {
200968d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
201068d75effSDimitry Andric   }
201168d75effSDimitry Andric   return ret;
201268d75effSDimitry Andric }
201368d75effSDimitry Andric 
2014fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair(
2015fe6060f1SDimitry Andric     int domain, int type, int protocol, int sv[2], dfsan_label domain_label,
2016fe6060f1SDimitry Andric     dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label,
2017fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin domain_origin,
2018fe6060f1SDimitry Andric     dfsan_origin type_origin, dfsan_origin protocol_origin,
2019fe6060f1SDimitry Andric     dfsan_origin sv_origin, dfsan_origin *ret_origin) {
2020fe6060f1SDimitry Andric   return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label,
2021fe6060f1SDimitry Andric                            protocol_label, sv_label, ret_label);
2022fe6060f1SDimitry Andric }
2023fe6060f1SDimitry Andric 
2024e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt(
2025e8d8bef9SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2026e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2027e8d8bef9SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2028e8d8bef9SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label) {
2029e8d8bef9SDimitry Andric   int ret = getsockopt(sockfd, level, optname, optval, optlen);
2030e8d8bef9SDimitry Andric   if (ret != -1 && optval && optlen) {
2031e8d8bef9SDimitry Andric     dfsan_set_label(0, optlen, sizeof(*optlen));
2032e8d8bef9SDimitry Andric     dfsan_set_label(0, optval, *optlen);
2033e8d8bef9SDimitry Andric   }
2034e8d8bef9SDimitry Andric   *ret_label = 0;
2035e8d8bef9SDimitry Andric   return ret;
2036e8d8bef9SDimitry Andric }
2037e8d8bef9SDimitry Andric 
2038fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt(
2039fe6060f1SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2040fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2041fe6060f1SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2042fe6060f1SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label,
2043fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin level_origin,
2044fe6060f1SDimitry Andric     dfsan_origin optname_origin, dfsan_origin optval_origin,
2045fe6060f1SDimitry Andric     dfsan_origin optlen_origin, dfsan_origin *ret_origin) {
2046fe6060f1SDimitry Andric   return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label,
2047fe6060f1SDimitry Andric                            level_label, optname_label, optval_label,
2048fe6060f1SDimitry Andric                            optlen_label, ret_label);
2049fe6060f1SDimitry Andric }
2050fe6060f1SDimitry Andric 
2051e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname(
2052e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2053e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2054e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2055e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2056e8d8bef9SDimitry Andric   int ret = getsockname(sockfd, addr, addrlen);
2057e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2058e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2059e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2060e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2061e8d8bef9SDimitry Andric   }
2062e8d8bef9SDimitry Andric   *ret_label = 0;
2063e8d8bef9SDimitry Andric   return ret;
2064e8d8bef9SDimitry Andric }
2065e8d8bef9SDimitry Andric 
2066fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname(
2067fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2068fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2069fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2070fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2071fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2072fe6060f1SDimitry Andric   return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label,
2073fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2074fe6060f1SDimitry Andric }
2075fe6060f1SDimitry Andric 
2076e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername(
2077e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2078e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2079e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2080e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2081e8d8bef9SDimitry Andric   int ret = getpeername(sockfd, addr, addrlen);
2082e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2083e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2084e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2085e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2086e8d8bef9SDimitry Andric   }
2087e8d8bef9SDimitry Andric   *ret_label = 0;
2088e8d8bef9SDimitry Andric   return ret;
2089e8d8bef9SDimitry Andric }
2090e8d8bef9SDimitry Andric 
2091fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername(
2092fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2093fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2094fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2095fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2096fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2097fe6060f1SDimitry Andric   return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label,
2098fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2099fe6060f1SDimitry Andric }
2100fe6060f1SDimitry Andric 
210168d75effSDimitry Andric // Type of the trampoline function passed to the custom version of
210268d75effSDimitry Andric // dfsan_set_write_callback.
210368d75effSDimitry Andric typedef void (*write_trampoline_t)(
210468d75effSDimitry Andric     void *callback,
210568d75effSDimitry Andric     int fd, const void *buf, ssize_t count,
210668d75effSDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
210768d75effSDimitry Andric 
2108fe6060f1SDimitry Andric typedef void (*write_origin_trampoline_t)(
2109fe6060f1SDimitry Andric     void *callback, int fd, const void *buf, ssize_t count,
2110fe6060f1SDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
2111fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin);
2112fe6060f1SDimitry Andric 
211368d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
211468d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
211568d75effSDimitry Andric static struct {
211668d75effSDimitry Andric   write_trampoline_t write_callback_trampoline = nullptr;
211768d75effSDimitry Andric   void *write_callback = nullptr;
211868d75effSDimitry Andric } write_callback_info;
211968d75effSDimitry Andric 
2120fe6060f1SDimitry Andric static struct {
2121fe6060f1SDimitry Andric   write_origin_trampoline_t write_callback_trampoline = nullptr;
2122fe6060f1SDimitry Andric   void *write_callback = nullptr;
2123fe6060f1SDimitry Andric } write_origin_callback_info;
2124fe6060f1SDimitry Andric 
212568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void
212668d75effSDimitry Andric __dfsw_dfsan_set_write_callback(
212768d75effSDimitry Andric     write_trampoline_t write_callback_trampoline,
212868d75effSDimitry Andric     void *write_callback,
212968d75effSDimitry Andric     dfsan_label write_callback_label,
213068d75effSDimitry Andric     dfsan_label *ret_label) {
213168d75effSDimitry Andric   write_callback_info.write_callback_trampoline = write_callback_trampoline;
213268d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
213368d75effSDimitry Andric }
213468d75effSDimitry Andric 
2135fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
2136fe6060f1SDimitry Andric     write_origin_trampoline_t write_callback_trampoline, void *write_callback,
2137fe6060f1SDimitry Andric     dfsan_label write_callback_label, dfsan_label *ret_label,
2138fe6060f1SDimitry Andric     dfsan_origin write_callback_origin, dfsan_origin *ret_origin) {
2139fe6060f1SDimitry Andric   write_origin_callback_info.write_callback_trampoline =
2140fe6060f1SDimitry Andric       write_callback_trampoline;
2141fe6060f1SDimitry Andric   write_origin_callback_info.write_callback = write_callback;
2142fe6060f1SDimitry Andric }
2143fe6060f1SDimitry Andric 
214468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
214568d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
214668d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
214768d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
214868d75effSDimitry Andric   if (write_callback_info.write_callback) {
214968d75effSDimitry Andric     write_callback_info.write_callback_trampoline(
215068d75effSDimitry Andric         write_callback_info.write_callback,
215168d75effSDimitry Andric         fd, buf, count,
215268d75effSDimitry Andric         fd_label, buf_label, count_label);
215368d75effSDimitry Andric   }
215468d75effSDimitry Andric 
215568d75effSDimitry Andric   *ret_label = 0;
215668d75effSDimitry Andric   return write(fd, buf, count);
215768d75effSDimitry Andric }
2158fe6060f1SDimitry Andric 
2159fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
2160fe6060f1SDimitry Andric     int fd, const void *buf, size_t count, dfsan_label fd_label,
2161fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
2162fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
2163fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2164fe6060f1SDimitry Andric   if (write_origin_callback_info.write_callback) {
2165fe6060f1SDimitry Andric     write_origin_callback_info.write_callback_trampoline(
2166fe6060f1SDimitry Andric         write_origin_callback_info.write_callback, fd, buf, count, fd_label,
2167fe6060f1SDimitry Andric         buf_label, count_label, fd_origin, buf_origin, count_origin);
2168fe6060f1SDimitry Andric   }
2169fe6060f1SDimitry Andric 
2170fe6060f1SDimitry Andric   *ret_label = 0;
2171fe6060f1SDimitry Andric   return write(fd, buf, count);
2172fe6060f1SDimitry Andric }
217368d75effSDimitry Andric } // namespace __dfsan
217468d75effSDimitry Andric 
217568d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
217668d75effSDimitry Andric typedef int dfsan_label_va;
217768d75effSDimitry Andric 
217868d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
217968d75effSDimitry Andric // '%.3f').
218068d75effSDimitry Andric struct Formatter {
218168d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
218268d75effSDimitry Andric       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
218368d75effSDimitry Andric         width(-1) {}
218468d75effSDimitry Andric 
218568d75effSDimitry Andric   int format() {
218668d75effSDimitry Andric     char *tmp_fmt = build_format_string();
218768d75effSDimitry Andric     int retval =
218868d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
218968d75effSDimitry Andric                  0 /* used only to avoid warnings */);
219068d75effSDimitry Andric     free(tmp_fmt);
219168d75effSDimitry Andric     return retval;
219268d75effSDimitry Andric   }
219368d75effSDimitry Andric 
219468d75effSDimitry Andric   template <typename T> int format(T arg) {
219568d75effSDimitry Andric     char *tmp_fmt = build_format_string();
219668d75effSDimitry Andric     int retval;
219768d75effSDimitry Andric     if (width >= 0) {
219868d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
219968d75effSDimitry Andric                         tmp_fmt, width, arg);
220068d75effSDimitry Andric     } else {
220168d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
220268d75effSDimitry Andric                         tmp_fmt, arg);
220368d75effSDimitry Andric     }
220468d75effSDimitry Andric     free(tmp_fmt);
220568d75effSDimitry Andric     return retval;
220668d75effSDimitry Andric   }
220768d75effSDimitry Andric 
220868d75effSDimitry Andric   char *build_format_string() {
220968d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
221068d75effSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1);
221168d75effSDimitry Andric     assert(new_fmt);
221268d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
221368d75effSDimitry Andric     new_fmt[fmt_size] = '\0';
221468d75effSDimitry Andric     return new_fmt;
221568d75effSDimitry Andric   }
221668d75effSDimitry Andric 
221768d75effSDimitry Andric   char *str_cur() { return str + str_off; }
221868d75effSDimitry Andric 
221968d75effSDimitry Andric   size_t num_written_bytes(int retval) {
222068d75effSDimitry Andric     if (retval < 0) {
222168d75effSDimitry Andric       return 0;
222268d75effSDimitry Andric     }
222368d75effSDimitry Andric 
222468d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
222568d75effSDimitry Andric     if (num_avail == 0) {
222668d75effSDimitry Andric       return 0;
222768d75effSDimitry Andric     }
222868d75effSDimitry Andric 
222968d75effSDimitry Andric     size_t num_written = retval;
223068d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
223168d75effSDimitry Andric     // truncated.
223268d75effSDimitry Andric     if (num_written >= num_avail) {
223368d75effSDimitry Andric       num_written -= num_avail;
223468d75effSDimitry Andric     }
223568d75effSDimitry Andric 
223668d75effSDimitry Andric     return num_written;
223768d75effSDimitry Andric   }
223868d75effSDimitry Andric 
223968d75effSDimitry Andric   char *str;
224068d75effSDimitry Andric   size_t str_off;
224168d75effSDimitry Andric   size_t size;
224268d75effSDimitry Andric   const char *fmt_start;
224368d75effSDimitry Andric   const char *fmt_cur;
224468d75effSDimitry Andric   int width;
224568d75effSDimitry Andric };
224668d75effSDimitry Andric 
224768d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
224868d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
224968d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
225068d75effSDimitry Andric // the return value vsnprintf would return.
225168d75effSDimitry Andric //
225268d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
225368d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
225468d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
225568d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
225668d75effSDimitry Andric // propagate labels more precisely.
225768d75effSDimitry Andric //
225868d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
225968d75effSDimitry Andric // positional arguments.
226068d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
226168d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
2262fe6060f1SDimitry Andric                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
226368d75effSDimitry Andric                          va_list ap) {
226468d75effSDimitry Andric   Formatter formatter(str, fmt, size);
226568d75effSDimitry Andric 
226668d75effSDimitry Andric   while (*formatter.fmt_cur) {
226768d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
226868d75effSDimitry Andric     formatter.width = -1;
226968d75effSDimitry Andric     int retval = 0;
227068d75effSDimitry Andric 
227168d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
227268d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
227368d75effSDimitry Andric       // of the string.
227468d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
227568d75effSDimitry Andric            ++formatter.fmt_cur) {}
227668d75effSDimitry Andric       retval = formatter.format();
227768d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
227868d75effSDimitry Andric                       formatter.num_written_bytes(retval));
227968d75effSDimitry Andric     } else {
228068d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
228168d75effSDimitry Andric       // specifier or the end of the string.
228268d75effSDimitry Andric       bool end_fmt = false;
228368d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
228468d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
228568d75effSDimitry Andric         case 'd':
228668d75effSDimitry Andric         case 'i':
228768d75effSDimitry Andric         case 'o':
228868d75effSDimitry Andric         case 'u':
228968d75effSDimitry Andric         case 'x':
229068d75effSDimitry Andric         case 'X':
229168d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
229268d75effSDimitry Andric           case 'h':
229368d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
229468d75effSDimitry Andric             // an int).
229568d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
229668d75effSDimitry Andric             break;
229768d75effSDimitry Andric           case 'l':
229868d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
229968d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
230068d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
230168d75effSDimitry Andric             } else {
230268d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
230368d75effSDimitry Andric             }
230468d75effSDimitry Andric             break;
230568d75effSDimitry Andric           case 'q':
230668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
230768d75effSDimitry Andric             break;
230868d75effSDimitry Andric           case 'j':
230968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
231068d75effSDimitry Andric             break;
231168d75effSDimitry Andric           case 'z':
231268d75effSDimitry Andric           case 't':
231368d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
231468d75effSDimitry Andric             break;
231568d75effSDimitry Andric           default:
231668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
231768d75effSDimitry Andric           }
2318fe6060f1SDimitry Andric           if (va_origins == nullptr)
231968d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
232068d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2321fe6060f1SDimitry Andric           else
2322fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2323fe6060f1SDimitry Andric                                    formatter.str_cur(),
2324fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
232568d75effSDimitry Andric           end_fmt = true;
232668d75effSDimitry Andric           break;
232768d75effSDimitry Andric 
232868d75effSDimitry Andric         case 'a':
232968d75effSDimitry Andric         case 'A':
233068d75effSDimitry Andric         case 'e':
233168d75effSDimitry Andric         case 'E':
233268d75effSDimitry Andric         case 'f':
233368d75effSDimitry Andric         case 'F':
233468d75effSDimitry Andric         case 'g':
233568d75effSDimitry Andric         case 'G':
233668d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
233768d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
233868d75effSDimitry Andric           } else {
233968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
234068d75effSDimitry Andric           }
2341fe6060f1SDimitry Andric           if (va_origins == nullptr)
234268d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
234368d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2344fe6060f1SDimitry Andric           else
2345fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2346fe6060f1SDimitry Andric                                    formatter.str_cur(),
2347fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
234868d75effSDimitry Andric           end_fmt = true;
234968d75effSDimitry Andric           break;
235068d75effSDimitry Andric 
235168d75effSDimitry Andric         case 'c':
235268d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
2353fe6060f1SDimitry Andric           if (va_origins == nullptr)
235468d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
235568d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2356fe6060f1SDimitry Andric           else
2357fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2358fe6060f1SDimitry Andric                                    formatter.str_cur(),
2359fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
236068d75effSDimitry Andric           end_fmt = true;
236168d75effSDimitry Andric           break;
236268d75effSDimitry Andric 
236368d75effSDimitry Andric         case 's': {
236468d75effSDimitry Andric           char *arg = va_arg(ap, char *);
236568d75effSDimitry Andric           retval = formatter.format(arg);
2366fe6060f1SDimitry Andric           if (va_origins) {
2367fe6060f1SDimitry Andric             va_origins++;
2368fe6060f1SDimitry Andric             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
2369fe6060f1SDimitry Andric                                       formatter.num_written_bytes(retval));
2370fe6060f1SDimitry Andric           }
237168d75effSDimitry Andric           va_labels++;
237268d75effSDimitry Andric           internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
237368d75effSDimitry Andric                           sizeof(dfsan_label) *
237468d75effSDimitry Andric                               formatter.num_written_bytes(retval));
237568d75effSDimitry Andric           end_fmt = true;
237668d75effSDimitry Andric           break;
237768d75effSDimitry Andric         }
237868d75effSDimitry Andric 
237968d75effSDimitry Andric         case 'p':
238068d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
2381fe6060f1SDimitry Andric           if (va_origins == nullptr)
238268d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
238368d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2384fe6060f1SDimitry Andric           else
2385fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2386fe6060f1SDimitry Andric                                    formatter.str_cur(),
2387fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
238868d75effSDimitry Andric           end_fmt = true;
238968d75effSDimitry Andric           break;
239068d75effSDimitry Andric 
239168d75effSDimitry Andric         case 'n': {
239268d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
239368d75effSDimitry Andric           *ptr = (int)formatter.str_off;
239468d75effSDimitry Andric           va_labels++;
2395fe6060f1SDimitry Andric           if (va_origins)
2396fe6060f1SDimitry Andric             va_origins++;
239768d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
239868d75effSDimitry Andric           end_fmt = true;
239968d75effSDimitry Andric           break;
240068d75effSDimitry Andric         }
240168d75effSDimitry Andric 
240268d75effSDimitry Andric         case '%':
240368d75effSDimitry Andric           retval = formatter.format();
240468d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
240568d75effSDimitry Andric                           formatter.num_written_bytes(retval));
240668d75effSDimitry Andric           end_fmt = true;
240768d75effSDimitry Andric           break;
240868d75effSDimitry Andric 
240968d75effSDimitry Andric         case '*':
241068d75effSDimitry Andric           formatter.width = va_arg(ap, int);
241168d75effSDimitry Andric           va_labels++;
2412fe6060f1SDimitry Andric           if (va_origins)
2413fe6060f1SDimitry Andric             va_origins++;
241468d75effSDimitry Andric           break;
241568d75effSDimitry Andric 
241668d75effSDimitry Andric         default:
241768d75effSDimitry Andric           break;
241868d75effSDimitry Andric         }
241968d75effSDimitry Andric       }
242068d75effSDimitry Andric     }
242168d75effSDimitry Andric 
242268d75effSDimitry Andric     if (retval < 0) {
242368d75effSDimitry Andric       return retval;
242468d75effSDimitry Andric     }
242568d75effSDimitry Andric 
242668d75effSDimitry Andric     formatter.fmt_cur++;
242768d75effSDimitry Andric     formatter.str_off += retval;
242868d75effSDimitry Andric   }
242968d75effSDimitry Andric 
243068d75effSDimitry Andric   *ret_label = 0;
2431fe6060f1SDimitry Andric   if (ret_origin)
2432fe6060f1SDimitry Andric     *ret_origin = 0;
243368d75effSDimitry Andric 
243468d75effSDimitry Andric   // Number of bytes written in total.
243568d75effSDimitry Andric   return formatter.str_off;
243668d75effSDimitry Andric }
243768d75effSDimitry Andric 
243868d75effSDimitry Andric extern "C" {
243968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
244068d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
244168d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
244268d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
244368d75effSDimitry Andric   va_list ap;
244468d75effSDimitry Andric   va_start(ap, ret_label);
2445fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
2446fe6060f1SDimitry Andric                           nullptr, ap);
2447fe6060f1SDimitry Andric   va_end(ap);
2448fe6060f1SDimitry Andric   return ret;
2449fe6060f1SDimitry Andric }
2450fe6060f1SDimitry Andric 
2451fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2452fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
2453fe6060f1SDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
2454fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin str_origin,
2455fe6060f1SDimitry Andric                    dfsan_origin format_origin, dfsan_origin *va_origins,
2456fe6060f1SDimitry Andric                    dfsan_origin *ret_origin, ...) {
2457fe6060f1SDimitry Andric   va_list ap;
2458fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2459fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, va_origins,
2460fe6060f1SDimitry Andric                           ret_origin, ap);
246168d75effSDimitry Andric   va_end(ap);
246268d75effSDimitry Andric   return ret;
246368d75effSDimitry Andric }
246468d75effSDimitry Andric 
246568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
246668d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
246768d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
246868d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
246968d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
247068d75effSDimitry Andric   va_list ap;
247168d75effSDimitry Andric   va_start(ap, ret_label);
2472fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
2473fe6060f1SDimitry Andric                           nullptr, ap);
247468d75effSDimitry Andric   va_end(ap);
247568d75effSDimitry Andric   return ret;
247668d75effSDimitry Andric }
247768d75effSDimitry Andric 
2478fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2479fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format,
2480fe6060f1SDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
2481fe6060f1SDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
2482fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin str_origin,
2483fe6060f1SDimitry Andric                     dfsan_origin size_origin, dfsan_origin format_origin,
2484fe6060f1SDimitry Andric                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
2485fe6060f1SDimitry Andric   va_list ap;
2486fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2487fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
2488fe6060f1SDimitry Andric                           ret_origin, ap);
2489fe6060f1SDimitry Andric   va_end(ap);
2490fe6060f1SDimitry Andric   return ret;
2491fe6060f1SDimitry Andric }
2492fe6060f1SDimitry Andric 
2493fe6060f1SDimitry Andric static void BeforeFork() {
2494fe6060f1SDimitry Andric   StackDepotLockAll();
2495fe6060f1SDimitry Andric   GetChainedOriginDepot()->LockAll();
2496fe6060f1SDimitry Andric }
2497fe6060f1SDimitry Andric 
2498fe6060f1SDimitry Andric static void AfterFork() {
2499fe6060f1SDimitry Andric   GetChainedOriginDepot()->UnlockAll();
2500fe6060f1SDimitry Andric   StackDepotUnlockAll();
2501fe6060f1SDimitry Andric }
2502fe6060f1SDimitry Andric 
2503fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2504fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) {
2505fe6060f1SDimitry Andric   pid_t pid = fork();
2506fe6060f1SDimitry Andric   *ret_label = 0;
2507fe6060f1SDimitry Andric   return pid;
2508fe6060f1SDimitry Andric }
2509fe6060f1SDimitry Andric 
2510fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2511fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
2512fe6060f1SDimitry Andric   BeforeFork();
2513fe6060f1SDimitry Andric   pid_t pid = __dfsw_fork(ret_label);
2514fe6060f1SDimitry Andric   AfterFork();
2515fe6060f1SDimitry Andric   return pid;
2516fe6060f1SDimitry Andric }
2517fe6060f1SDimitry Andric 
251868d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
251968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
252068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
252168d75effSDimitry Andric                              u32 *) {}
2522*349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
2523*349cc55cSDimitry Andric                              const uptr *end) {}
252468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
252568d75effSDimitry Andric 
252668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
252768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
252868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
252968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
253068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
253168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
253268d75effSDimitry Andric                              void) {}
253368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
253468d75effSDimitry Andric                              void) {}
253568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
253668d75effSDimitry Andric                              void) {}
253768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
253868d75effSDimitry Andric                              void) {}
253968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
254068d75effSDimitry Andric }  // extern "C"
2541