xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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) {
50004eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest, src, n);
50168d75effSDimitry Andric   return internal_memcpy(dest, src, n);
50268d75effSDimitry Andric }
50368d75effSDimitry Andric 
504fe6060f1SDimitry Andric static void *dfsan_memcpy_with_origin(void *dest, const void *src, size_t n) {
505fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest, src, n);
506fe6060f1SDimitry Andric   return dfsan_memcpy(dest, src, n);
507fe6060f1SDimitry Andric }
508fe6060f1SDimitry Andric 
50968d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
51068d75effSDimitry Andric   internal_memset(s, c, n);
51168d75effSDimitry Andric   dfsan_set_label(c_label, s, n);
51268d75effSDimitry Andric }
51368d75effSDimitry Andric 
514fe6060f1SDimitry Andric static void dfsan_memset_with_origin(void *s, int c, dfsan_label c_label,
515fe6060f1SDimitry Andric                                      dfsan_origin c_origin, size_t n) {
516fe6060f1SDimitry Andric   internal_memset(s, c, n);
517fe6060f1SDimitry Andric   dfsan_set_label_origin(c_label, c_origin, s, n);
518fe6060f1SDimitry Andric }
519fe6060f1SDimitry Andric 
52068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
52168d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n,
52268d75effSDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
52368d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
52468d75effSDimitry Andric   *ret_label = dest_label;
52568d75effSDimitry Andric   return dfsan_memcpy(dest, src, n);
52668d75effSDimitry Andric }
52768d75effSDimitry Andric 
52868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
529fe6060f1SDimitry Andric void *__dfso_memcpy(void *dest, const void *src, size_t n,
530fe6060f1SDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
531fe6060f1SDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label,
532fe6060f1SDimitry Andric                     dfsan_origin dest_origin, dfsan_origin src_origin,
533fe6060f1SDimitry Andric                     dfsan_origin n_origin, dfsan_origin *ret_origin) {
534fe6060f1SDimitry Andric   *ret_label = dest_label;
535fe6060f1SDimitry Andric   *ret_origin = dest_origin;
536fe6060f1SDimitry Andric   return dfsan_memcpy_with_origin(dest, src, n);
537fe6060f1SDimitry Andric }
538fe6060f1SDimitry Andric 
539fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
540fe6060f1SDimitry Andric void *__dfsw_memmove(void *dest, const void *src, size_t n,
541fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
542fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label) {
543fe6060f1SDimitry Andric   *ret_label = dest_label;
544fe6060f1SDimitry Andric   return dfsan_memmove(dest, src, n);
545fe6060f1SDimitry Andric }
546fe6060f1SDimitry Andric 
547fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
548fe6060f1SDimitry Andric void *__dfso_memmove(void *dest, const void *src, size_t n,
549fe6060f1SDimitry Andric                      dfsan_label dest_label, dfsan_label src_label,
550fe6060f1SDimitry Andric                      dfsan_label n_label, dfsan_label *ret_label,
551fe6060f1SDimitry Andric                      dfsan_origin dest_origin, dfsan_origin src_origin,
552fe6060f1SDimitry Andric                      dfsan_origin n_origin, dfsan_origin *ret_origin) {
553fe6060f1SDimitry Andric   *ret_label = dest_label;
554fe6060f1SDimitry Andric   *ret_origin = dest_origin;
555fe6060f1SDimitry Andric   return dfsan_memmove_with_origin(dest, src, n);
556fe6060f1SDimitry Andric }
557fe6060f1SDimitry Andric 
558fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
55968d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n,
56068d75effSDimitry Andric                     dfsan_label s_label, dfsan_label c_label,
56168d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
56268d75effSDimitry Andric   dfsan_memset(s, c, c_label, n);
56368d75effSDimitry Andric   *ret_label = s_label;
56468d75effSDimitry Andric   return s;
56568d75effSDimitry Andric }
56668d75effSDimitry Andric 
567fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
568fe6060f1SDimitry Andric void *__dfso_memset(void *s, int c, size_t n, dfsan_label s_label,
569fe6060f1SDimitry Andric                     dfsan_label c_label, dfsan_label n_label,
570fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin s_origin,
571fe6060f1SDimitry Andric                     dfsan_origin c_origin, dfsan_origin n_origin,
572fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
573fe6060f1SDimitry Andric   dfsan_memset_with_origin(s, c, c_label, c_origin, n);
574fe6060f1SDimitry Andric   *ret_label = s_label;
575fe6060f1SDimitry Andric   *ret_origin = s_origin;
576fe6060f1SDimitry Andric   return s;
577fe6060f1SDimitry Andric }
578fe6060f1SDimitry Andric 
579fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src,
580fe6060f1SDimitry Andric                                                   dfsan_label dest_label,
581fe6060f1SDimitry Andric                                                   dfsan_label src_label,
582fe6060f1SDimitry Andric                                                   dfsan_label *ret_label) {
583fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
584349cc55cSDimitry Andric   char *ret = strcat(dest, src);
58504eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, strlen(src));
586fe6060f1SDimitry Andric   *ret_label = dest_label;
587fe6060f1SDimitry Andric   return ret;
588fe6060f1SDimitry Andric }
589fe6060f1SDimitry Andric 
590fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat(
591fe6060f1SDimitry Andric     char *dest, const char *src, dfsan_label dest_label, dfsan_label src_label,
592fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin,
593fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
594fe6060f1SDimitry Andric   size_t dest_len = strlen(dest);
595349cc55cSDimitry Andric   char *ret = strcat(dest, src);
596fe6060f1SDimitry Andric   size_t src_len = strlen(src);
597fe6060f1SDimitry Andric   dfsan_mem_origin_transfer(dest + dest_len, src, src_len);
59804eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dest + dest_len, src, src_len);
599fe6060f1SDimitry Andric   *ret_label = dest_label;
600fe6060f1SDimitry Andric   *ret_origin = dest_origin;
601fe6060f1SDimitry Andric   return ret;
602fe6060f1SDimitry Andric }
603fe6060f1SDimitry Andric 
60468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
60568d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
60668d75effSDimitry Andric   size_t len = strlen(s);
60768d75effSDimitry Andric   void *p = malloc(len+1);
60868d75effSDimitry Andric   dfsan_memcpy(p, s, len+1);
60968d75effSDimitry Andric   *ret_label = 0;
61068d75effSDimitry Andric   return static_cast<char *>(p);
61168d75effSDimitry Andric }
61268d75effSDimitry Andric 
613fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strdup(const char *s,
614fe6060f1SDimitry Andric                                                   dfsan_label s_label,
615fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
616fe6060f1SDimitry Andric                                                   dfsan_origin s_origin,
617fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
618fe6060f1SDimitry Andric   size_t len = strlen(s);
619fe6060f1SDimitry Andric   void *p = malloc(len + 1);
620fe6060f1SDimitry Andric   dfsan_memcpy_with_origin(p, s, len + 1);
621fe6060f1SDimitry Andric   *ret_label = 0;
622fe6060f1SDimitry Andric   return static_cast<char *>(p);
623fe6060f1SDimitry Andric }
624fe6060f1SDimitry Andric 
62568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
62668d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
62768d75effSDimitry Andric                dfsan_label s2_label, dfsan_label n_label,
62868d75effSDimitry Andric                dfsan_label *ret_label) {
62968d75effSDimitry Andric   size_t len = strlen(s2);
63068d75effSDimitry Andric   if (len < n) {
63168d75effSDimitry Andric     dfsan_memcpy(s1, s2, len+1);
63268d75effSDimitry Andric     dfsan_memset(s1+len+1, 0, 0, n-len-1);
63368d75effSDimitry Andric   } else {
63468d75effSDimitry Andric     dfsan_memcpy(s1, s2, n);
63568d75effSDimitry Andric   }
63668d75effSDimitry Andric 
63768d75effSDimitry Andric   *ret_label = s1_label;
63868d75effSDimitry Andric   return s1;
63968d75effSDimitry Andric }
64068d75effSDimitry Andric 
641fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncpy(
642fe6060f1SDimitry Andric     char *s1, const char *s2, size_t n, dfsan_label s1_label,
643fe6060f1SDimitry Andric     dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label,
644fe6060f1SDimitry Andric     dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin,
645fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
646fe6060f1SDimitry Andric   size_t len = strlen(s2);
647fe6060f1SDimitry Andric   if (len < n) {
648fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, len + 1);
649fe6060f1SDimitry Andric     dfsan_memset_with_origin(s1 + len + 1, 0, 0, 0, n - len - 1);
650fe6060f1SDimitry Andric   } else {
651fe6060f1SDimitry Andric     dfsan_memcpy_with_origin(s1, s2, n);
652fe6060f1SDimitry Andric   }
653fe6060f1SDimitry Andric 
654fe6060f1SDimitry Andric   *ret_label = s1_label;
655fe6060f1SDimitry Andric   *ret_origin = s1_origin;
656fe6060f1SDimitry Andric   return s1;
657fe6060f1SDimitry Andric }
658fe6060f1SDimitry Andric 
65968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
66068d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
66168d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
66268d75effSDimitry Andric              dfsan_label count_label, dfsan_label offset_label,
66368d75effSDimitry Andric              dfsan_label *ret_label) {
66468d75effSDimitry Andric   ssize_t ret = pread(fd, buf, count, offset);
66568d75effSDimitry Andric   if (ret > 0)
66668d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
66768d75effSDimitry Andric   *ret_label = 0;
66868d75effSDimitry Andric   return ret;
66968d75effSDimitry Andric }
67068d75effSDimitry Andric 
671fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_pread(
672fe6060f1SDimitry Andric     int fd, void *buf, size_t count, off_t offset, dfsan_label fd_label,
673fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label offset_label,
674fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin,
675fe6060f1SDimitry Andric     dfsan_origin count_origin, dfsan_label offset_origin,
676fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
677fe6060f1SDimitry Andric   return __dfsw_pread(fd, buf, count, offset, fd_label, buf_label, count_label,
678fe6060f1SDimitry Andric                       offset_label, ret_label);
679fe6060f1SDimitry Andric }
680fe6060f1SDimitry Andric 
68168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
68268d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count,
68368d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
68468d75effSDimitry Andric              dfsan_label count_label,
68568d75effSDimitry Andric              dfsan_label *ret_label) {
68668d75effSDimitry Andric   ssize_t ret = read(fd, buf, count);
68768d75effSDimitry Andric   if (ret > 0)
68868d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
68968d75effSDimitry Andric   *ret_label = 0;
69068d75effSDimitry Andric   return ret;
69168d75effSDimitry Andric }
69268d75effSDimitry Andric 
693fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_read(
694fe6060f1SDimitry Andric     int fd, void *buf, size_t count, dfsan_label fd_label,
695fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
696fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
697fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
698fe6060f1SDimitry Andric   return __dfsw_read(fd, buf, count, fd_label, buf_label, count_label,
699fe6060f1SDimitry Andric                      ret_label);
700fe6060f1SDimitry Andric }
701fe6060f1SDimitry Andric 
70268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
70368d75effSDimitry Andric                                                        struct timespec *tp,
70468d75effSDimitry Andric                                                        dfsan_label clk_id_label,
70568d75effSDimitry Andric                                                        dfsan_label tp_label,
70668d75effSDimitry Andric                                                        dfsan_label *ret_label) {
70768d75effSDimitry Andric   int ret = clock_gettime(clk_id, tp);
70868d75effSDimitry Andric   if (ret == 0)
70968d75effSDimitry Andric     dfsan_set_label(0, tp, sizeof(struct timespec));
71068d75effSDimitry Andric   *ret_label = 0;
71168d75effSDimitry Andric   return ret;
71268d75effSDimitry Andric }
71368d75effSDimitry Andric 
714fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_clock_gettime(
715fe6060f1SDimitry Andric     clockid_t clk_id, struct timespec *tp, dfsan_label clk_id_label,
716fe6060f1SDimitry Andric     dfsan_label tp_label, dfsan_label *ret_label, dfsan_origin clk_id_origin,
717fe6060f1SDimitry Andric     dfsan_origin tp_origin, dfsan_origin *ret_origin) {
718fe6060f1SDimitry Andric   return __dfsw_clock_gettime(clk_id, tp, clk_id_label, tp_label, ret_label);
719fe6060f1SDimitry Andric }
720fe6060f1SDimitry Andric 
721fe6060f1SDimitry Andric static void dfsan_set_zero_label(const void *ptr, uptr size) {
72268d75effSDimitry Andric   dfsan_set_label(0, const_cast<void *>(ptr), size);
72368d75effSDimitry Andric }
72468d75effSDimitry Andric 
72568d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally
72668d75effSDimitry Andric // doesn't participate in dynamic symbol resolution.  Therefore we won't
72768d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here.
72868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *
72968d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
73068d75effSDimitry Andric               dfsan_label flag_label, dfsan_label *ret_label) {
73168d75effSDimitry Andric   void *handle = dlopen(filename, flag);
73268d75effSDimitry Andric   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
73368d75effSDimitry Andric   if (map)
734fe6060f1SDimitry Andric     ForEachMappedRegion(map, dfsan_set_zero_label);
73568d75effSDimitry Andric   *ret_label = 0;
73668d75effSDimitry Andric   return handle;
73768d75effSDimitry Andric }
73868d75effSDimitry Andric 
739fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen(
740fe6060f1SDimitry Andric     const char *filename, int flag, dfsan_label filename_label,
741fe6060f1SDimitry Andric     dfsan_label flag_label, dfsan_label *ret_label,
742fe6060f1SDimitry Andric     dfsan_origin filename_origin, dfsan_origin flag_origin,
743fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
744fe6060f1SDimitry Andric   return __dfsw_dlopen(filename, flag, filename_label, flag_label, ret_label);
745fe6060f1SDimitry Andric }
74668d75effSDimitry Andric 
747fe6060f1SDimitry Andric static void *DFsanThreadStartFunc(void *arg) {
748fe6060f1SDimitry Andric   DFsanThread *t = (DFsanThread *)arg;
749fe6060f1SDimitry Andric   SetCurrentThread(t);
750349cc55cSDimitry Andric   t->Init();
751349cc55cSDimitry Andric   SetSigProcMask(&t->starting_sigset_, nullptr);
752fe6060f1SDimitry Andric   return t->ThreadStart();
753fe6060f1SDimitry Andric }
754fe6060f1SDimitry Andric 
755fe6060f1SDimitry Andric static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
756fe6060f1SDimitry Andric                                 void *start_routine, void *arg,
757fe6060f1SDimitry Andric                                 dfsan_label *ret_label,
758fe6060f1SDimitry Andric                                 bool track_origins = false) {
759fe6060f1SDimitry Andric   pthread_attr_t myattr;
760fe6060f1SDimitry Andric   if (!attr) {
761fe6060f1SDimitry Andric     pthread_attr_init(&myattr);
762fe6060f1SDimitry Andric     attr = &myattr;
763fe6060f1SDimitry Andric   }
764fe6060f1SDimitry Andric 
765fe6060f1SDimitry Andric   // Ensure that the thread stack is large enough to hold all TLS data.
766fe6060f1SDimitry Andric   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
767fe6060f1SDimitry Andric 
768fe6060f1SDimitry Andric   DFsanThread *t =
769*81ad6265SDimitry Andric       DFsanThread::Create((thread_callback_t)start_routine, arg, track_origins);
770349cc55cSDimitry Andric   ScopedBlockSignals block(&t->starting_sigset_);
771fe6060f1SDimitry Andric   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
772fe6060f1SDimitry Andric 
773fe6060f1SDimitry Andric   if (attr == &myattr)
774fe6060f1SDimitry Andric     pthread_attr_destroy(&myattr);
775fe6060f1SDimitry Andric   *ret_label = 0;
776fe6060f1SDimitry Andric   return res;
77768d75effSDimitry Andric }
77868d75effSDimitry Andric 
77968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
780*81ad6265SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
781*81ad6265SDimitry Andric     void *arg, dfsan_label thread_label, dfsan_label attr_label,
782*81ad6265SDimitry Andric     dfsan_label start_routine_label, dfsan_label arg_label,
783*81ad6265SDimitry Andric     dfsan_label *ret_label) {
784*81ad6265SDimitry Andric   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label);
785fe6060f1SDimitry Andric }
786fe6060f1SDimitry Andric 
787fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
788*81ad6265SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr, void *start_routine,
789*81ad6265SDimitry Andric     void *arg, dfsan_label thread_label, dfsan_label attr_label,
790*81ad6265SDimitry Andric     dfsan_label start_routine_label, dfsan_label arg_label,
791*81ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin thread_origin,
792fe6060f1SDimitry Andric     dfsan_origin attr_origin, dfsan_origin start_routine_origin,
793fe6060f1SDimitry Andric     dfsan_origin arg_origin, dfsan_origin *ret_origin) {
794*81ad6265SDimitry Andric   return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label,
795*81ad6265SDimitry Andric                               true);
79668d75effSDimitry Andric }
79768d75effSDimitry Andric 
798e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
799e8d8bef9SDimitry Andric                                                       void **retval,
800e8d8bef9SDimitry Andric                                                       dfsan_label thread_label,
801e8d8bef9SDimitry Andric                                                       dfsan_label retval_label,
802e8d8bef9SDimitry Andric                                                       dfsan_label *ret_label) {
803e8d8bef9SDimitry Andric   int ret = pthread_join(thread, retval);
804e8d8bef9SDimitry Andric   if (ret == 0 && retval)
805e8d8bef9SDimitry Andric     dfsan_set_label(0, retval, sizeof(*retval));
806e8d8bef9SDimitry Andric   *ret_label = 0;
807e8d8bef9SDimitry Andric   return ret;
808e8d8bef9SDimitry Andric }
809e8d8bef9SDimitry Andric 
810fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
811fe6060f1SDimitry Andric     pthread_t thread, void **retval, dfsan_label thread_label,
812fe6060f1SDimitry Andric     dfsan_label retval_label, dfsan_label *ret_label,
813fe6060f1SDimitry Andric     dfsan_origin thread_origin, dfsan_origin retval_origin,
814fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
815fe6060f1SDimitry Andric   return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
816fe6060f1SDimitry Andric                              ret_label);
817fe6060f1SDimitry Andric }
818fe6060f1SDimitry Andric 
81968d75effSDimitry Andric struct dl_iterate_phdr_info {
820*81ad6265SDimitry Andric   int (*callback)(struct dl_phdr_info *info, size_t size, void *data);
821fe6060f1SDimitry Andric   void *data;
822fe6060f1SDimitry Andric };
823fe6060f1SDimitry Andric 
82468d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
82568d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
82668d75effSDimitry Andric   dfsan_set_label(0, *info);
82768d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
82868d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
82968d75effSDimitry Andric   dfsan_set_label(
83068d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
83168d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
83268d75effSDimitry Andric 
833*81ad6265SDimitry Andric   dfsan_clear_thread_local_state();
834*81ad6265SDimitry Andric   return dipi->callback(info, size, dipi->data);
835fe6060f1SDimitry Andric }
836fe6060f1SDimitry Andric 
83768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
838*81ad6265SDimitry Andric     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
839*81ad6265SDimitry Andric     void *data, dfsan_label callback_label, dfsan_label data_label,
840*81ad6265SDimitry Andric     dfsan_label *ret_label) {
841*81ad6265SDimitry Andric   dl_iterate_phdr_info dipi = {callback, data};
84268d75effSDimitry Andric   *ret_label = 0;
84368d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
84468d75effSDimitry Andric }
84568d75effSDimitry Andric 
846fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr(
847*81ad6265SDimitry Andric     int (*callback)(struct dl_phdr_info *info, size_t size, void *data),
848*81ad6265SDimitry Andric     void *data, dfsan_label callback_label, dfsan_label data_label,
849*81ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin callback_origin,
850*81ad6265SDimitry Andric     dfsan_origin data_origin, dfsan_origin *ret_origin) {
851*81ad6265SDimitry Andric   dl_iterate_phdr_info dipi = {callback, data};
852fe6060f1SDimitry Andric   *ret_label = 0;
853*81ad6265SDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
854fe6060f1SDimitry Andric }
855fe6060f1SDimitry Andric 
856e8d8bef9SDimitry Andric // This function is only available for glibc 2.27 or newer.  Mark it weak so
857e8d8bef9SDimitry Andric // linking succeeds with older glibcs.
858e8d8bef9SDimitry Andric SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep,
859e8d8bef9SDimitry Andric                                                       size_t *alignp);
860e8d8bef9SDimitry Andric 
861e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info(
862e8d8bef9SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
863e8d8bef9SDimitry Andric     dfsan_label alignp_label) {
864e8d8bef9SDimitry Andric   assert(_dl_get_tls_static_info);
865e8d8bef9SDimitry Andric   _dl_get_tls_static_info(sizep, alignp);
866e8d8bef9SDimitry Andric   dfsan_set_label(0, sizep, sizeof(*sizep));
867e8d8bef9SDimitry Andric   dfsan_set_label(0, alignp, sizeof(*alignp));
868e8d8bef9SDimitry Andric }
869e8d8bef9SDimitry Andric 
870fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info(
871fe6060f1SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
872fe6060f1SDimitry Andric     dfsan_label alignp_label, dfsan_origin sizep_origin,
873fe6060f1SDimitry Andric     dfsan_origin alignp_origin) {
874fe6060f1SDimitry Andric   __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label);
875fe6060f1SDimitry Andric }
876fe6060f1SDimitry Andric 
87768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
87868d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
87968d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
88068d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
88168d75effSDimitry Andric   if (ret) {
88268d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
88368d75effSDimitry Andric                     strlen(buf) + 1);
88468d75effSDimitry Andric     *ret_label = buf_label;
88568d75effSDimitry Andric   } else {
88668d75effSDimitry Andric     *ret_label = 0;
88768d75effSDimitry Andric   }
88868d75effSDimitry Andric   return ret;
88968d75effSDimitry Andric }
89068d75effSDimitry Andric 
89168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
892fe6060f1SDimitry Andric char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
893fe6060f1SDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label,
894fe6060f1SDimitry Andric                      dfsan_origin timep_origin, dfsan_origin buf_origin,
895fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
896fe6060f1SDimitry Andric   char *ret = ctime_r(timep, buf);
897fe6060f1SDimitry Andric   if (ret) {
898fe6060f1SDimitry Andric     dfsan_set_label_origin(
899fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
900fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf,
901fe6060f1SDimitry Andric         strlen(buf) + 1);
902fe6060f1SDimitry Andric     *ret_label = buf_label;
903fe6060f1SDimitry Andric     *ret_origin = buf_origin;
904fe6060f1SDimitry Andric   } else {
905fe6060f1SDimitry Andric     *ret_label = 0;
906fe6060f1SDimitry Andric   }
907fe6060f1SDimitry Andric   return ret;
908fe6060f1SDimitry Andric }
909fe6060f1SDimitry Andric 
910fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
91168d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
91268d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
91368d75effSDimitry Andric                    dfsan_label *ret_label) {
91468d75effSDimitry Andric   char *ret = fgets(s, size, stream);
91568d75effSDimitry Andric   if (ret) {
91668d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
91768d75effSDimitry Andric     *ret_label = s_label;
91868d75effSDimitry Andric   } else {
91968d75effSDimitry Andric     *ret_label = 0;
92068d75effSDimitry Andric   }
92168d75effSDimitry Andric   return ret;
92268d75effSDimitry Andric }
92368d75effSDimitry Andric 
92468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
925fe6060f1SDimitry Andric char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
926fe6060f1SDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
927fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin s_origin,
928fe6060f1SDimitry Andric                    dfsan_origin size_origin, dfsan_origin stream_origin,
929fe6060f1SDimitry Andric                    dfsan_origin *ret_origin) {
930fe6060f1SDimitry Andric   char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label,
931fe6060f1SDimitry Andric                            ret_label);
932fe6060f1SDimitry Andric   if (ret)
933fe6060f1SDimitry Andric     *ret_origin = s_origin;
934fe6060f1SDimitry Andric   return ret;
935fe6060f1SDimitry Andric }
936fe6060f1SDimitry Andric 
937fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
93868d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
93968d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
94068d75effSDimitry Andric   char *ret = getcwd(buf, size);
94168d75effSDimitry Andric   if (ret) {
94268d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
94368d75effSDimitry Andric     *ret_label = buf_label;
94468d75effSDimitry Andric   } else {
94568d75effSDimitry Andric     *ret_label = 0;
94668d75effSDimitry Andric   }
94768d75effSDimitry Andric   return ret;
94868d75effSDimitry Andric }
94968d75effSDimitry Andric 
95068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
951fe6060f1SDimitry Andric char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label,
952fe6060f1SDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label,
953fe6060f1SDimitry Andric                     dfsan_origin buf_origin, dfsan_origin size_origin,
954fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
955fe6060f1SDimitry Andric   char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label);
956fe6060f1SDimitry Andric   if (ret)
957fe6060f1SDimitry Andric     *ret_origin = buf_origin;
958fe6060f1SDimitry Andric   return ret;
959fe6060f1SDimitry Andric }
960fe6060f1SDimitry Andric 
961fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
96268d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
96368d75effSDimitry Andric   char *ret = get_current_dir_name();
964fe6060f1SDimitry Andric   if (ret)
96568d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
96668d75effSDimitry Andric   *ret_label = 0;
96768d75effSDimitry Andric   return ret;
96868d75effSDimitry Andric }
96968d75effSDimitry Andric 
97068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
971fe6060f1SDimitry Andric char *__dfso_get_current_dir_name(dfsan_label *ret_label,
972fe6060f1SDimitry Andric                                   dfsan_origin *ret_origin) {
973fe6060f1SDimitry Andric   return __dfsw_get_current_dir_name(ret_label);
974fe6060f1SDimitry Andric }
975fe6060f1SDimitry Andric 
976349cc55cSDimitry Andric // This function is only available for glibc 2.25 or newer.  Mark it weak so
977349cc55cSDimitry Andric // linking succeeds with older glibcs.
978349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length);
979349cc55cSDimitry Andric 
980349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length,
981349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
982349cc55cSDimitry Andric                                                     dfsan_label length_label,
983349cc55cSDimitry Andric                                                     dfsan_label *ret_label) {
984349cc55cSDimitry Andric   int ret = getentropy(buffer, length);
985349cc55cSDimitry Andric   if (ret == 0) {
986349cc55cSDimitry Andric     dfsan_set_label(0, buffer, length);
987349cc55cSDimitry Andric   }
988349cc55cSDimitry Andric   *ret_label = 0;
989349cc55cSDimitry Andric   return ret;
990349cc55cSDimitry Andric }
991349cc55cSDimitry Andric 
992349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length,
993349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
994349cc55cSDimitry Andric                                                     dfsan_label length_label,
995349cc55cSDimitry Andric                                                     dfsan_label *ret_label,
996349cc55cSDimitry Andric                                                     dfsan_origin buffer_origin,
997349cc55cSDimitry Andric                                                     dfsan_origin length_origin,
998349cc55cSDimitry Andric                                                     dfsan_origin *ret_origin) {
999349cc55cSDimitry Andric   return __dfsw_getentropy(buffer, length, buffer_label, length_label,
1000349cc55cSDimitry Andric                            ret_label);
1001349cc55cSDimitry Andric }
1002349cc55cSDimitry Andric 
1003fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
100468d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
100568d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
100668d75effSDimitry Andric   int ret = gethostname(name, len);
100768d75effSDimitry Andric   if (ret == 0) {
100868d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
100968d75effSDimitry Andric   }
101068d75effSDimitry Andric   *ret_label = 0;
101168d75effSDimitry Andric   return ret;
101268d75effSDimitry Andric }
101368d75effSDimitry Andric 
101468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1015fe6060f1SDimitry Andric int __dfso_gethostname(char *name, size_t len, dfsan_label name_label,
1016fe6060f1SDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label,
1017fe6060f1SDimitry Andric                        dfsan_origin name_origin, dfsan_origin len_origin,
1018fe6060f1SDimitry Andric                        dfsan_label *ret_origin) {
1019fe6060f1SDimitry Andric   return __dfsw_gethostname(name, len, name_label, len_label, ret_label);
1020fe6060f1SDimitry Andric }
1021fe6060f1SDimitry Andric 
1022fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
102368d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
102468d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
102568d75effSDimitry Andric                      dfsan_label *ret_label) {
102668d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
102768d75effSDimitry Andric   if (ret == 0) {
102868d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
102968d75effSDimitry Andric   }
103068d75effSDimitry Andric   *ret_label = 0;
103168d75effSDimitry Andric   return ret;
103268d75effSDimitry Andric }
103368d75effSDimitry Andric 
103468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1035fe6060f1SDimitry Andric int __dfso_getrlimit(int resource, struct rlimit *rlim,
1036fe6060f1SDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
1037fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin resource_origin,
1038fe6060f1SDimitry Andric                      dfsan_origin rlim_origin, dfsan_origin *ret_origin) {
1039fe6060f1SDimitry Andric   return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label,
1040fe6060f1SDimitry Andric                           ret_label);
1041fe6060f1SDimitry Andric }
1042fe6060f1SDimitry Andric 
1043fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
104468d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
104568d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
104668d75effSDimitry Andric   int ret = getrusage(who, usage);
104768d75effSDimitry Andric   if (ret == 0) {
104868d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
104968d75effSDimitry Andric   }
105068d75effSDimitry Andric   *ret_label = 0;
105168d75effSDimitry Andric   return ret;
105268d75effSDimitry Andric }
105368d75effSDimitry Andric 
105468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1055fe6060f1SDimitry Andric int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label,
1056fe6060f1SDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label,
1057fe6060f1SDimitry Andric                      dfsan_origin who_origin, dfsan_origin usage_origin,
1058fe6060f1SDimitry Andric                      dfsan_label *ret_origin) {
1059fe6060f1SDimitry Andric   return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label);
1060fe6060f1SDimitry Andric }
1061fe6060f1SDimitry Andric 
1062fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
106368d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
106468d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
1065349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
106668d75effSDimitry Andric   if (ret) {
106704eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, strlen(src) + 1);
106868d75effSDimitry Andric   }
106968d75effSDimitry Andric   *ret_label = dst_label;
107068d75effSDimitry Andric   return ret;
107168d75effSDimitry Andric }
107268d75effSDimitry Andric 
107368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1074fe6060f1SDimitry Andric char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label,
1075fe6060f1SDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label,
1076fe6060f1SDimitry Andric                     dfsan_origin dst_origin, dfsan_origin src_origin,
1077fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1078349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
1079fe6060f1SDimitry Andric   if (ret) {
1080fe6060f1SDimitry Andric     size_t str_len = strlen(src) + 1;
1081fe6060f1SDimitry Andric     dfsan_mem_origin_transfer(dest, src, str_len);
108204eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, str_len);
108368d75effSDimitry Andric   }
1084fe6060f1SDimitry Andric   *ret_label = dst_label;
1085fe6060f1SDimitry Andric   *ret_origin = dst_origin;
1086fe6060f1SDimitry Andric   return ret;
1087fe6060f1SDimitry Andric }
1088fe6060f1SDimitry Andric 
1089fe6060f1SDimitry Andric static long int dfsan_strtol(const char *nptr, char **endptr, int base,
1090fe6060f1SDimitry Andric                              char **tmp_endptr) {
1091fe6060f1SDimitry Andric   assert(tmp_endptr);
1092fe6060f1SDimitry Andric   long int ret = strtol(nptr, tmp_endptr, base);
1093fe6060f1SDimitry Andric   if (endptr)
1094fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1095fe6060f1SDimitry Andric   return ret;
1096fe6060f1SDimitry Andric }
1097fe6060f1SDimitry Andric 
1098fe6060f1SDimitry Andric static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr,
1099fe6060f1SDimitry Andric                                   dfsan_label base_label,
1100fe6060f1SDimitry Andric                                   dfsan_label *ret_label) {
110168d75effSDimitry Andric   if (tmp_endptr > nptr) {
110268d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
110368d75effSDimitry Andric     *ret_label = dfsan_union(
110468d75effSDimitry Andric         base_label,
110568d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
110668d75effSDimitry Andric   } else {
110768d75effSDimitry Andric     *ret_label = 0;
110868d75effSDimitry Andric   }
1109fe6060f1SDimitry Andric }
1110fe6060f1SDimitry Andric 
1111fe6060f1SDimitry Andric static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr,
1112fe6060f1SDimitry Andric                                    dfsan_label base_label,
1113fe6060f1SDimitry Andric                                    dfsan_label *ret_label,
1114fe6060f1SDimitry Andric                                    dfsan_origin base_origin,
1115fe6060f1SDimitry Andric                                    dfsan_origin *ret_origin) {
1116fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1117fe6060f1SDimitry Andric     // When multiple inputs are tainted, we propagate one of its origins.
1118fe6060f1SDimitry Andric     // Because checking if base_label is tainted does not need additional
1119fe6060f1SDimitry Andric     // computation, we prefer to propagating base_origin.
1120fe6060f1SDimitry Andric     *ret_origin = base_label
1121fe6060f1SDimitry Andric                       ? base_origin
1122fe6060f1SDimitry Andric                       : dfsan_read_origin_of_first_taint(
1123fe6060f1SDimitry Andric                             nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1124fe6060f1SDimitry Andric   }
1125fe6060f1SDimitry Andric }
1126fe6060f1SDimitry Andric 
1127fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1128fe6060f1SDimitry Andric long int __dfsw_strtol(const char *nptr, char **endptr, int base,
1129fe6060f1SDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1130fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
1131fe6060f1SDimitry Andric   char *tmp_endptr;
1132fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1133fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
113468d75effSDimitry Andric   return ret;
113568d75effSDimitry Andric }
113668d75effSDimitry Andric 
113768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1138fe6060f1SDimitry Andric long int __dfso_strtol(const char *nptr, char **endptr, int base,
113968d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1140fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label,
1141fe6060f1SDimitry Andric                        dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1142fe6060f1SDimitry Andric                        dfsan_origin base_origin, dfsan_origin *ret_origin) {
114368d75effSDimitry Andric   char *tmp_endptr;
1144fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1145fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1146fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1147fe6060f1SDimitry Andric                          ret_origin);
1148fe6060f1SDimitry Andric   return ret;
114968d75effSDimitry Andric }
1150fe6060f1SDimitry Andric 
1151fe6060f1SDimitry Andric static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) {
1152fe6060f1SDimitry Andric   assert(tmp_endptr);
1153fe6060f1SDimitry Andric   double ret = strtod(nptr, tmp_endptr);
1154fe6060f1SDimitry Andric   if (endptr)
1155fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1156fe6060f1SDimitry Andric   return ret;
1157fe6060f1SDimitry Andric }
1158fe6060f1SDimitry Andric 
1159fe6060f1SDimitry Andric static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr,
1160fe6060f1SDimitry Andric                                dfsan_label *ret_label) {
116168d75effSDimitry Andric   if (tmp_endptr > nptr) {
116268d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
116368d75effSDimitry Andric     *ret_label = dfsan_read_label(
116468d75effSDimitry Andric         nptr,
116568d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
116668d75effSDimitry Andric   } else {
116768d75effSDimitry Andric     *ret_label = 0;
116868d75effSDimitry Andric   }
1169fe6060f1SDimitry Andric }
1170fe6060f1SDimitry Andric 
1171fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1172fe6060f1SDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1173fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label) {
1174fe6060f1SDimitry Andric   char *tmp_endptr;
1175fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1176fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1177fe6060f1SDimitry Andric   return ret;
1178fe6060f1SDimitry Andric }
1179fe6060f1SDimitry Andric 
1180fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1181fe6060f1SDimitry Andric double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1182fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label,
1183fe6060f1SDimitry Andric                      dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1184fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1185fe6060f1SDimitry Andric   char *tmp_endptr;
1186fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1187fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1188fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1189fe6060f1SDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
1190fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(
1191fe6060f1SDimitry Andric         nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1192fe6060f1SDimitry Andric   } else {
1193fe6060f1SDimitry Andric     *ret_origin = 0;
1194fe6060f1SDimitry Andric   }
1195fe6060f1SDimitry Andric   return ret;
1196fe6060f1SDimitry Andric }
1197fe6060f1SDimitry Andric 
1198fe6060f1SDimitry Andric static long long int dfsan_strtoll(const char *nptr, char **endptr, int base,
1199fe6060f1SDimitry Andric                                    char **tmp_endptr) {
1200fe6060f1SDimitry Andric   assert(tmp_endptr);
1201fe6060f1SDimitry Andric   long long int ret = strtoll(nptr, tmp_endptr, base);
1202fe6060f1SDimitry Andric   if (endptr)
1203fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
120468d75effSDimitry Andric   return ret;
120568d75effSDimitry Andric }
120668d75effSDimitry Andric 
120768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
120868d75effSDimitry Andric long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
120968d75effSDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
121068d75effSDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label) {
121168d75effSDimitry Andric   char *tmp_endptr;
1212fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1213fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1214fe6060f1SDimitry Andric   return ret;
121568d75effSDimitry Andric }
1216fe6060f1SDimitry Andric 
1217fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1218fe6060f1SDimitry Andric long long int __dfso_strtoll(const char *nptr, char **endptr, int base,
1219fe6060f1SDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
1220fe6060f1SDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label,
1221fe6060f1SDimitry Andric                              dfsan_origin nptr_origin,
1222fe6060f1SDimitry Andric                              dfsan_origin endptr_origin,
1223fe6060f1SDimitry Andric                              dfsan_origin base_origin,
1224fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1225fe6060f1SDimitry Andric   char *tmp_endptr;
1226fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1227fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1228fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1229fe6060f1SDimitry Andric                          ret_origin);
1230fe6060f1SDimitry Andric   return ret;
123168d75effSDimitry Andric }
1232fe6060f1SDimitry Andric 
1233fe6060f1SDimitry Andric static unsigned long int dfsan_strtoul(const char *nptr, char **endptr,
1234fe6060f1SDimitry Andric                                        int base, char **tmp_endptr) {
1235fe6060f1SDimitry Andric   assert(tmp_endptr);
1236fe6060f1SDimitry Andric   unsigned long int ret = strtoul(nptr, tmp_endptr, base);
1237fe6060f1SDimitry Andric   if (endptr)
1238fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
123968d75effSDimitry Andric   return ret;
124068d75effSDimitry Andric }
124168d75effSDimitry Andric 
124268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
124368d75effSDimitry Andric unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
124468d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
124568d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
124668d75effSDimitry Andric   char *tmp_endptr;
1247fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1248fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1249fe6060f1SDimitry Andric   return ret;
125068d75effSDimitry Andric }
1251fe6060f1SDimitry Andric 
1252fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1253fe6060f1SDimitry Andric unsigned long int __dfso_strtoul(
1254fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1255fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1256fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1257fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1258fe6060f1SDimitry Andric   char *tmp_endptr;
1259fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1260fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1261fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1262fe6060f1SDimitry Andric                          ret_origin);
1263fe6060f1SDimitry Andric   return ret;
126468d75effSDimitry Andric }
1265fe6060f1SDimitry Andric 
1266fe6060f1SDimitry Andric static long long unsigned int dfsan_strtoull(const char *nptr, char **endptr,
1267fe6060f1SDimitry Andric                                              int base, char **tmp_endptr) {
1268fe6060f1SDimitry Andric   assert(tmp_endptr);
1269fe6060f1SDimitry Andric   long long unsigned int ret = strtoull(nptr, tmp_endptr, base);
1270fe6060f1SDimitry Andric   if (endptr)
1271fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
127268d75effSDimitry Andric   return ret;
127368d75effSDimitry Andric }
127468d75effSDimitry Andric 
127568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
127668d75effSDimitry Andric long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
1277e8d8bef9SDimitry Andric                                        int base, dfsan_label nptr_label,
1278e8d8bef9SDimitry Andric                                        dfsan_label endptr_label,
127968d75effSDimitry Andric                                        dfsan_label base_label,
128068d75effSDimitry Andric                                        dfsan_label *ret_label) {
128168d75effSDimitry Andric   char *tmp_endptr;
1282fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1283fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1284fe6060f1SDimitry Andric   return ret;
128568d75effSDimitry Andric }
1286fe6060f1SDimitry Andric 
1287fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1288fe6060f1SDimitry Andric long long unsigned int __dfso_strtoull(
1289fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1290fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1291fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1292fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1293fe6060f1SDimitry Andric   char *tmp_endptr;
1294fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1295fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1296fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1297fe6060f1SDimitry Andric                          ret_origin);
129868d75effSDimitry Andric   return ret;
129968d75effSDimitry Andric }
130068d75effSDimitry Andric 
130168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
130268d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
130368d75effSDimitry Andric   time_t ret = time(t);
130468d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
130568d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
130668d75effSDimitry Andric   }
130768d75effSDimitry Andric   *ret_label = 0;
130868d75effSDimitry Andric   return ret;
130968d75effSDimitry Andric }
131068d75effSDimitry Andric 
131168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1312fe6060f1SDimitry Andric time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label,
1313fe6060f1SDimitry Andric                    dfsan_origin t_origin, dfsan_origin *ret_origin) {
1314fe6060f1SDimitry Andric   return __dfsw_time(t, t_label, ret_label);
1315fe6060f1SDimitry Andric }
1316fe6060f1SDimitry Andric 
1317fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
131868d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
131968d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
132068d75effSDimitry Andric                      dfsan_label *ret_label) {
132168d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
132268d75effSDimitry Andric   if (ret == 1) {
132368d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
132468d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
132568d75effSDimitry Andric   }
132668d75effSDimitry Andric   *ret_label = 0;
132768d75effSDimitry Andric   return ret;
132868d75effSDimitry Andric }
132968d75effSDimitry Andric 
133068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1331fe6060f1SDimitry Andric int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
1332fe6060f1SDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
1333fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin af_origin,
1334fe6060f1SDimitry Andric                      dfsan_origin src_origin, dfsan_origin dst_origin,
1335fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1336fe6060f1SDimitry Andric   int ret = inet_pton(af, src, dst);
1337fe6060f1SDimitry Andric   if (ret == 1) {
1338fe6060f1SDimitry Andric     int src_len = strlen(src) + 1;
1339fe6060f1SDimitry Andric     dfsan_set_label_origin(
1340fe6060f1SDimitry Andric         dfsan_read_label(src, src_len),
1341fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(src, src_len), dst,
1342fe6060f1SDimitry Andric         af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
1343fe6060f1SDimitry Andric   }
1344fe6060f1SDimitry Andric   *ret_label = 0;
1345fe6060f1SDimitry Andric   return ret;
1346fe6060f1SDimitry Andric }
1347fe6060f1SDimitry Andric 
1348fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
134968d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
135068d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
135168d75effSDimitry Andric                               dfsan_label *ret_label) {
135268d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
135368d75effSDimitry Andric   if (ret) {
135468d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
135568d75effSDimitry Andric                     sizeof(struct tm));
135668d75effSDimitry Andric     *ret_label = result_label;
135768d75effSDimitry Andric   } else {
135868d75effSDimitry Andric     *ret_label = 0;
135968d75effSDimitry Andric   }
136068d75effSDimitry Andric   return ret;
136168d75effSDimitry Andric }
136268d75effSDimitry Andric 
136368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1364fe6060f1SDimitry Andric struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result,
1365fe6060f1SDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
1366fe6060f1SDimitry Andric                               dfsan_label *ret_label, dfsan_origin timep_origin,
1367fe6060f1SDimitry Andric                               dfsan_origin result_origin,
1368fe6060f1SDimitry Andric                               dfsan_origin *ret_origin) {
1369fe6060f1SDimitry Andric   struct tm *ret = localtime_r(timep, result);
1370fe6060f1SDimitry Andric   if (ret) {
1371fe6060f1SDimitry Andric     dfsan_set_label_origin(
1372fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1373fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result,
1374fe6060f1SDimitry Andric         sizeof(struct tm));
1375fe6060f1SDimitry Andric     *ret_label = result_label;
1376fe6060f1SDimitry Andric     *ret_origin = result_origin;
1377fe6060f1SDimitry Andric   } else {
1378fe6060f1SDimitry Andric     *ret_label = 0;
1379fe6060f1SDimitry Andric   }
1380fe6060f1SDimitry Andric   return ret;
1381fe6060f1SDimitry Andric }
1382fe6060f1SDimitry Andric 
1383fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
138468d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
138568d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
138668d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
138768d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
138868d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
138968d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
139068d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
139168d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
139268d75effSDimitry Andric   if (ret == 0) {
139368d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
139468d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
139568d75effSDimitry Andric   }
139668d75effSDimitry Andric   *ret_label = 0;
139768d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
139868d75effSDimitry Andric   return ret;
139968d75effSDimitry Andric }
140068d75effSDimitry Andric 
140168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1402fe6060f1SDimitry Andric int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen,
1403fe6060f1SDimitry Andric                       struct passwd **result, dfsan_label uid_label,
1404fe6060f1SDimitry Andric                       dfsan_label pwd_label, dfsan_label buf_label,
1405fe6060f1SDimitry Andric                       dfsan_label buflen_label, dfsan_label result_label,
1406fe6060f1SDimitry Andric                       dfsan_label *ret_label, dfsan_origin uid_origin,
1407fe6060f1SDimitry Andric                       dfsan_origin pwd_origin, dfsan_origin buf_origin,
1408fe6060f1SDimitry Andric                       dfsan_origin buflen_origin, dfsan_origin result_origin,
1409fe6060f1SDimitry Andric                       dfsan_origin *ret_origin) {
1410fe6060f1SDimitry Andric   return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label,
1411fe6060f1SDimitry Andric                            buf_label, buflen_label, result_label, ret_label);
1412fe6060f1SDimitry Andric }
1413fe6060f1SDimitry Andric 
1414fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1415e8d8bef9SDimitry Andric int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1416e8d8bef9SDimitry Andric                       int timeout, dfsan_label epfd_label,
1417e8d8bef9SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1418e8d8bef9SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label) {
1419e8d8bef9SDimitry Andric   int ret = epoll_wait(epfd, events, maxevents, timeout);
1420e8d8bef9SDimitry Andric   if (ret > 0)
1421e8d8bef9SDimitry Andric     dfsan_set_label(0, events, ret * sizeof(*events));
1422e8d8bef9SDimitry Andric   *ret_label = 0;
1423e8d8bef9SDimitry Andric   return ret;
1424e8d8bef9SDimitry Andric }
1425e8d8bef9SDimitry Andric 
1426e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1427fe6060f1SDimitry Andric int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1428fe6060f1SDimitry Andric                       int timeout, dfsan_label epfd_label,
1429fe6060f1SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1430fe6060f1SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label,
1431fe6060f1SDimitry Andric                       dfsan_origin epfd_origin, dfsan_origin events_origin,
1432fe6060f1SDimitry Andric                       dfsan_origin maxevents_origin,
1433fe6060f1SDimitry Andric                       dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1434fe6060f1SDimitry Andric   return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label,
1435fe6060f1SDimitry Andric                            events_label, maxevents_label, timeout_label,
1436fe6060f1SDimitry Andric                            ret_label);
1437fe6060f1SDimitry Andric }
1438fe6060f1SDimitry Andric 
1439fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
144068d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
144168d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
144268d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
144368d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
144468d75effSDimitry Andric   if (ret >= 0) {
144568d75effSDimitry Andric     for (; nfds > 0; --nfds) {
144668d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
144768d75effSDimitry Andric     }
144868d75effSDimitry Andric   }
144968d75effSDimitry Andric   *ret_label = 0;
145068d75effSDimitry Andric   return ret;
145168d75effSDimitry Andric }
145268d75effSDimitry Andric 
145368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1454fe6060f1SDimitry Andric int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout,
1455fe6060f1SDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
1456fe6060f1SDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label,
1457fe6060f1SDimitry Andric                 dfsan_origin dfs_origin, dfsan_origin nfds_origin,
1458fe6060f1SDimitry Andric                 dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1459fe6060f1SDimitry Andric   return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label,
1460fe6060f1SDimitry Andric                      ret_label);
1461fe6060f1SDimitry Andric }
1462fe6060f1SDimitry Andric 
1463fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
146468d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
146568d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
146668d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
146768d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
146868d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
146968d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
147068d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
147168d75effSDimitry Andric   // undefined.
147268d75effSDimitry Andric   if (readfds) {
147368d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
147468d75effSDimitry Andric   }
147568d75effSDimitry Andric   if (writefds) {
147668d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
147768d75effSDimitry Andric   }
147868d75effSDimitry Andric   if (exceptfds) {
147968d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
148068d75effSDimitry Andric   }
148168d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
148268d75effSDimitry Andric   *ret_label = 0;
148368d75effSDimitry Andric   return ret;
148468d75effSDimitry Andric }
148568d75effSDimitry Andric 
148668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1487fe6060f1SDimitry Andric int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds,
1488fe6060f1SDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
1489fe6060f1SDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
1490fe6060f1SDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
1491fe6060f1SDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label,
1492fe6060f1SDimitry Andric                   dfsan_origin nfds_origin, dfsan_origin readfds_origin,
1493fe6060f1SDimitry Andric                   dfsan_origin writefds_origin, dfsan_origin exceptfds_origin,
1494fe6060f1SDimitry Andric                   dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1495fe6060f1SDimitry Andric   return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label,
1496fe6060f1SDimitry Andric                        readfds_label, writefds_label, exceptfds_label,
1497fe6060f1SDimitry Andric                        timeout_label, ret_label);
1498fe6060f1SDimitry Andric }
1499fe6060f1SDimitry Andric 
1500fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
150168d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
150268d75effSDimitry Andric                              dfsan_label pid_label,
150368d75effSDimitry Andric                              dfsan_label cpusetsize_label,
150468d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
150568d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
150668d75effSDimitry Andric   if (ret == 0) {
150768d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
150868d75effSDimitry Andric   }
150968d75effSDimitry Andric   *ret_label = 0;
151068d75effSDimitry Andric   return ret;
151168d75effSDimitry Andric }
151268d75effSDimitry Andric 
151368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1514fe6060f1SDimitry Andric int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
1515fe6060f1SDimitry Andric                              dfsan_label pid_label,
1516fe6060f1SDimitry Andric                              dfsan_label cpusetsize_label,
1517fe6060f1SDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label,
1518fe6060f1SDimitry Andric                              dfsan_origin pid_origin,
1519fe6060f1SDimitry Andric                              dfsan_origin cpusetsize_origin,
1520fe6060f1SDimitry Andric                              dfsan_origin mask_origin,
1521fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1522fe6060f1SDimitry Andric   return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label,
1523fe6060f1SDimitry Andric                                   cpusetsize_label, mask_label, ret_label);
1524fe6060f1SDimitry Andric }
1525fe6060f1SDimitry Andric 
1526fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
152768d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
152868d75effSDimitry Andric                        dfsan_label *ret_label) {
152968d75effSDimitry Andric   int ret = sigemptyset(set);
153068d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
1531fe6060f1SDimitry Andric   *ret_label = 0;
153268d75effSDimitry Andric   return ret;
153368d75effSDimitry Andric }
153468d75effSDimitry Andric 
153568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1536fe6060f1SDimitry Andric int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
1537fe6060f1SDimitry Andric                        dfsan_label *ret_label, dfsan_origin set_origin,
1538fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1539fe6060f1SDimitry Andric   return __dfsw_sigemptyset(set, set_label, ret_label);
1540fe6060f1SDimitry Andric }
1541fe6060f1SDimitry Andric 
1542fe6060f1SDimitry Andric class SignalHandlerScope {
1543fe6060f1SDimitry Andric  public:
1544fe6060f1SDimitry Andric   SignalHandlerScope() {
1545fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1546fe6060f1SDimitry Andric       t->EnterSignalHandler();
1547fe6060f1SDimitry Andric   }
1548fe6060f1SDimitry Andric   ~SignalHandlerScope() {
1549fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1550fe6060f1SDimitry Andric       t->LeaveSignalHandler();
1551fe6060f1SDimitry Andric   }
1552fe6060f1SDimitry Andric };
1553fe6060f1SDimitry Andric 
1554fe6060f1SDimitry Andric // Clear DFSan runtime TLS state at the end of a scope.
1555fe6060f1SDimitry Andric //
1556fe6060f1SDimitry Andric // Implementation must be async-signal-safe and use small data size, because
1557fe6060f1SDimitry Andric // instances of this class may live on the signal handler stack.
1558fe6060f1SDimitry Andric //
1559fe6060f1SDimitry Andric // DFSan uses TLS to pass metadata of arguments and return values. When an
1560fe6060f1SDimitry Andric // instrumented function accesses the TLS, if a signal callback happens, and the
1561fe6060f1SDimitry Andric // callback calls other instrumented functions with updating the same TLS, the
1562fe6060f1SDimitry Andric // TLS is in an inconsistent state after the callback ends. This may cause
1563fe6060f1SDimitry Andric // either under-tainting or over-tainting.
1564fe6060f1SDimitry Andric //
1565fe6060f1SDimitry Andric // The current implementation simply resets TLS at restore. This prevents from
1566fe6060f1SDimitry Andric // over-tainting. Although under-tainting may still happen, a taint flow can be
1567fe6060f1SDimitry Andric // found eventually if we run a DFSan-instrumented program multiple times. The
1568fe6060f1SDimitry Andric // alternative option is saving the entire TLS. However the TLS storage takes
1569fe6060f1SDimitry Andric // 2k bytes, and signal calls could be nested. So it does not seem worth.
1570fe6060f1SDimitry Andric class ScopedClearThreadLocalState {
1571fe6060f1SDimitry Andric  public:
1572fe6060f1SDimitry Andric   ScopedClearThreadLocalState() {}
1573fe6060f1SDimitry Andric   ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); }
1574fe6060f1SDimitry Andric };
1575fe6060f1SDimitry Andric 
1576fe6060f1SDimitry Andric // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls.
1577fe6060f1SDimitry Andric const int kMaxSignals = 1024;
1578fe6060f1SDimitry Andric static atomic_uintptr_t sigactions[kMaxSignals];
1579fe6060f1SDimitry Andric 
1580fe6060f1SDimitry Andric static void SignalHandler(int signo) {
1581fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1582fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1583fe6060f1SDimitry Andric 
1584*81ad6265SDimitry Andric   // Clear shadows for all inputs provided by system.
1585fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, sizeof(dfsan_label));
1586fe6060f1SDimitry Andric 
1587fe6060f1SDimitry Andric   typedef void (*signal_cb)(int x);
1588fe6060f1SDimitry Andric   signal_cb cb =
1589fe6060f1SDimitry Andric       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1590fe6060f1SDimitry Andric   cb(signo);
1591fe6060f1SDimitry Andric }
1592fe6060f1SDimitry Andric 
1593fe6060f1SDimitry Andric static void SignalAction(int signo, siginfo_t *si, void *uc) {
1594fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1595fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1596fe6060f1SDimitry Andric 
1597fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. Similar to SignalHandler.
1598fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label));
1599fe6060f1SDimitry Andric   dfsan_set_label(0, si, sizeof(*si));
1600fe6060f1SDimitry Andric   dfsan_set_label(0, uc, sizeof(ucontext_t));
1601fe6060f1SDimitry Andric 
1602fe6060f1SDimitry Andric   typedef void (*sigaction_cb)(int, siginfo_t *, void *);
1603fe6060f1SDimitry Andric   sigaction_cb cb =
1604fe6060f1SDimitry Andric       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1605fe6060f1SDimitry Andric   cb(signo, si, uc);
1606fe6060f1SDimitry Andric }
1607fe6060f1SDimitry Andric 
1608fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
160968d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
161068d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
161168d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
161268d75effSDimitry Andric                      dfsan_label *ret_label) {
1613fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1614fe6060f1SDimitry Andric   SignalSpinLocker lock;
1615fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1616fe6060f1SDimitry Andric   struct sigaction new_act;
1617fe6060f1SDimitry Andric   struct sigaction *pnew_act = act ? &new_act : nullptr;
1618fe6060f1SDimitry Andric   if (act) {
1619fe6060f1SDimitry Andric     internal_memcpy(pnew_act, act, sizeof(struct sigaction));
1620fe6060f1SDimitry Andric     if (pnew_act->sa_flags & SA_SIGINFO) {
1621fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_sigaction);
1622fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1623fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1624fe6060f1SDimitry Andric         pnew_act->sa_sigaction = SignalAction;
1625fe6060f1SDimitry Andric       }
1626fe6060f1SDimitry Andric     } else {
1627fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_handler);
1628fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1629fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1630fe6060f1SDimitry Andric         pnew_act->sa_handler = SignalHandler;
1631fe6060f1SDimitry Andric       }
1632fe6060f1SDimitry Andric     }
1633fe6060f1SDimitry Andric   }
1634fe6060f1SDimitry Andric 
1635fe6060f1SDimitry Andric   int ret = sigaction(signum, pnew_act, oldact);
1636fe6060f1SDimitry Andric 
1637fe6060f1SDimitry Andric   if (ret == 0 && oldact) {
1638fe6060f1SDimitry Andric     if (oldact->sa_flags & SA_SIGINFO) {
1639fe6060f1SDimitry Andric       if (oldact->sa_sigaction == SignalAction)
1640fe6060f1SDimitry Andric         oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb;
1641fe6060f1SDimitry Andric     } else {
1642fe6060f1SDimitry Andric       if (oldact->sa_handler == SignalHandler)
1643fe6060f1SDimitry Andric         oldact->sa_handler = (decltype(oldact->sa_handler))old_cb;
1644fe6060f1SDimitry Andric     }
1645fe6060f1SDimitry Andric   }
1646fe6060f1SDimitry Andric 
164768d75effSDimitry Andric   if (oldact) {
164868d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
164968d75effSDimitry Andric   }
165068d75effSDimitry Andric   *ret_label = 0;
165168d75effSDimitry Andric   return ret;
165268d75effSDimitry Andric }
165368d75effSDimitry Andric 
165468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1655fe6060f1SDimitry Andric int __dfso_sigaction(int signum, const struct sigaction *act,
1656fe6060f1SDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
1657fe6060f1SDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
1658fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin signum_origin,
1659fe6060f1SDimitry Andric                      dfsan_origin act_origin, dfsan_origin oldact_origin,
1660fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1661fe6060f1SDimitry Andric   return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
1662fe6060f1SDimitry Andric                           oldact_label, ret_label);
1663fe6060f1SDimitry Andric }
1664fe6060f1SDimitry Andric 
1665fe6060f1SDimitry Andric static sighandler_t dfsan_signal(int signum, sighandler_t handler,
1666fe6060f1SDimitry Andric                                  dfsan_label *ret_label) {
1667fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1668fe6060f1SDimitry Andric   SignalSpinLocker lock;
1669fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1670fe6060f1SDimitry Andric   if (handler != SIG_IGN && handler != SIG_DFL) {
1671fe6060f1SDimitry Andric     atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
1672fe6060f1SDimitry Andric     handler = &SignalHandler;
1673fe6060f1SDimitry Andric   }
1674fe6060f1SDimitry Andric 
1675fe6060f1SDimitry Andric   sighandler_t ret = signal(signum, handler);
1676fe6060f1SDimitry Andric 
1677fe6060f1SDimitry Andric   if (ret == SignalHandler)
1678fe6060f1SDimitry Andric     ret = (sighandler_t)old_cb;
1679fe6060f1SDimitry Andric 
1680fe6060f1SDimitry Andric   *ret_label = 0;
1681fe6060f1SDimitry Andric   return ret;
1682fe6060f1SDimitry Andric }
1683fe6060f1SDimitry Andric 
1684fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1685*81ad6265SDimitry Andric sighandler_t __dfsw_signal(int signum, sighandler_t handler,
1686*81ad6265SDimitry Andric                            dfsan_label signum_label, dfsan_label handler_label,
1687*81ad6265SDimitry Andric                            dfsan_label *ret_label) {
1688fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1689fe6060f1SDimitry Andric }
1690fe6060f1SDimitry Andric 
1691fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1692*81ad6265SDimitry Andric sighandler_t __dfso_signal(int signum, sighandler_t handler,
1693*81ad6265SDimitry Andric                            dfsan_label signum_label, dfsan_label handler_label,
1694fe6060f1SDimitry Andric                            dfsan_label *ret_label, dfsan_origin signum_origin,
1695*81ad6265SDimitry Andric                            dfsan_origin handler_origin,
1696*81ad6265SDimitry Andric                            dfsan_origin *ret_origin) {
1697fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1698fe6060f1SDimitry Andric }
1699fe6060f1SDimitry Andric 
1700fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1701e8d8bef9SDimitry Andric int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1702e8d8bef9SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label) {
1703e8d8bef9SDimitry Andric   int ret = sigaltstack(ss, old_ss);
1704e8d8bef9SDimitry Andric   if (ret != -1 && old_ss)
1705e8d8bef9SDimitry Andric     dfsan_set_label(0, old_ss, sizeof(*old_ss));
1706e8d8bef9SDimitry Andric   *ret_label = 0;
1707e8d8bef9SDimitry Andric   return ret;
1708e8d8bef9SDimitry Andric }
1709e8d8bef9SDimitry Andric 
1710e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1711fe6060f1SDimitry Andric int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1712fe6060f1SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label,
1713fe6060f1SDimitry Andric                        dfsan_origin ss_origin, dfsan_origin old_ss_origin,
1714fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1715fe6060f1SDimitry Andric   return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
1716fe6060f1SDimitry Andric }
1717fe6060f1SDimitry Andric 
1718fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
171968d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
172068d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
172168d75effSDimitry Andric                         dfsan_label *ret_label) {
172268d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
172368d75effSDimitry Andric   if (tv) {
172468d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
172568d75effSDimitry Andric   }
172668d75effSDimitry Andric   if (tz) {
172768d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
172868d75effSDimitry Andric   }
172968d75effSDimitry Andric   *ret_label = 0;
173068d75effSDimitry Andric   return ret;
173168d75effSDimitry Andric }
173268d75effSDimitry Andric 
1733fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1734fe6060f1SDimitry Andric int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz,
1735fe6060f1SDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
1736fe6060f1SDimitry Andric                         dfsan_label *ret_label, dfsan_origin tv_origin,
1737fe6060f1SDimitry Andric                         dfsan_origin tz_origin, dfsan_origin *ret_origin) {
1738fe6060f1SDimitry Andric   return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label);
1739fe6060f1SDimitry Andric }
1740fe6060f1SDimitry Andric 
174168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
174268d75effSDimitry Andric                                                   dfsan_label s_label,
174368d75effSDimitry Andric                                                   dfsan_label c_label,
174468d75effSDimitry Andric                                                   dfsan_label n_label,
174568d75effSDimitry Andric                                                   dfsan_label *ret_label) {
174668d75effSDimitry Andric   void *ret = memchr(s, c, n);
174768d75effSDimitry Andric   if (flags().strict_data_dependencies) {
174868d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
174968d75effSDimitry Andric   } else {
175068d75effSDimitry Andric     size_t len =
175168d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
175268d75effSDimitry Andric             : n;
175368d75effSDimitry Andric     *ret_label =
175468d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
175568d75effSDimitry Andric   }
175668d75effSDimitry Andric   return ret;
175768d75effSDimitry Andric }
175868d75effSDimitry Andric 
1759fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr(
1760fe6060f1SDimitry Andric     void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label,
1761fe6060f1SDimitry Andric     dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin,
1762fe6060f1SDimitry Andric     dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) {
1763fe6060f1SDimitry Andric   void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label);
1764fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1765fe6060f1SDimitry Andric     if (ret)
1766fe6060f1SDimitry Andric       *ret_origin = s_origin;
1767fe6060f1SDimitry Andric   } else {
1768fe6060f1SDimitry Andric     size_t len =
1769fe6060f1SDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
1770fe6060f1SDimitry Andric             : n;
1771fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, len);
1772fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1773fe6060f1SDimitry Andric   }
1774fe6060f1SDimitry Andric   return ret;
1775fe6060f1SDimitry Andric }
1776fe6060f1SDimitry Andric 
177768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
177868d75effSDimitry Andric                                                    dfsan_label s_label,
177968d75effSDimitry Andric                                                    dfsan_label c_label,
178068d75effSDimitry Andric                                                    dfsan_label *ret_label) {
178168d75effSDimitry Andric   char *ret = strrchr(s, c);
178268d75effSDimitry Andric   if (flags().strict_data_dependencies) {
178368d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
178468d75effSDimitry Andric   } else {
178568d75effSDimitry Andric     *ret_label =
178668d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
178768d75effSDimitry Andric                     dfsan_union(s_label, c_label));
178868d75effSDimitry Andric   }
178968d75effSDimitry Andric 
179068d75effSDimitry Andric   return ret;
179168d75effSDimitry Andric }
179268d75effSDimitry Andric 
1793fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr(
1794fe6060f1SDimitry Andric     char *s, int c, dfsan_label s_label, dfsan_label c_label,
1795fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
1796fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
1797fe6060f1SDimitry Andric   char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label);
1798fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1799fe6060f1SDimitry Andric     if (ret)
1800fe6060f1SDimitry Andric       *ret_origin = s_origin;
1801fe6060f1SDimitry Andric   } else {
1802fe6060f1SDimitry Andric     size_t s_len = strlen(s) + 1;
1803fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len);
1804fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1805fe6060f1SDimitry Andric   }
1806fe6060f1SDimitry Andric 
1807fe6060f1SDimitry Andric   return ret;
1808fe6060f1SDimitry Andric }
1809fe6060f1SDimitry Andric 
181068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
181168d75effSDimitry Andric                                                   dfsan_label haystack_label,
181268d75effSDimitry Andric                                                   dfsan_label needle_label,
181368d75effSDimitry Andric                                                   dfsan_label *ret_label) {
181468d75effSDimitry Andric   char *ret = strstr(haystack, needle);
181568d75effSDimitry Andric   if (flags().strict_data_dependencies) {
181668d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
181768d75effSDimitry Andric   } else {
181868d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
181968d75effSDimitry Andric     *ret_label =
182068d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
182168d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
182268d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
182368d75effSDimitry Andric   }
182468d75effSDimitry Andric 
182568d75effSDimitry Andric   return ret;
182668d75effSDimitry Andric }
182768d75effSDimitry Andric 
1828fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle,
1829fe6060f1SDimitry Andric                                                   dfsan_label haystack_label,
1830fe6060f1SDimitry Andric                                                   dfsan_label needle_label,
1831fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
1832fe6060f1SDimitry Andric                                                   dfsan_origin haystack_origin,
1833fe6060f1SDimitry Andric                                                   dfsan_origin needle_origin,
1834fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
1835fe6060f1SDimitry Andric   char *ret =
1836fe6060f1SDimitry Andric       __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label);
1837fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1838fe6060f1SDimitry Andric     if (ret)
1839fe6060f1SDimitry Andric       *ret_origin = haystack_origin;
1840fe6060f1SDimitry Andric   } else {
1841fe6060f1SDimitry Andric     size_t needle_len = strlen(needle);
1842fe6060f1SDimitry Andric     size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1;
1843fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len);
1844fe6060f1SDimitry Andric     if (o) {
1845fe6060f1SDimitry Andric       *ret_origin = o;
1846fe6060f1SDimitry Andric     } else {
1847fe6060f1SDimitry Andric       o = dfsan_read_origin_of_first_taint(needle, needle_len + 1);
1848fe6060f1SDimitry Andric       *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin);
1849fe6060f1SDimitry Andric     }
1850fe6060f1SDimitry Andric   }
1851fe6060f1SDimitry Andric 
1852fe6060f1SDimitry Andric   return ret;
1853fe6060f1SDimitry Andric }
1854fe6060f1SDimitry Andric 
185568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
185668d75effSDimitry Andric                                                    struct timespec *rem,
185768d75effSDimitry Andric                                                    dfsan_label req_label,
185868d75effSDimitry Andric                                                    dfsan_label rem_label,
185968d75effSDimitry Andric                                                    dfsan_label *ret_label) {
186068d75effSDimitry Andric   int ret = nanosleep(req, rem);
186168d75effSDimitry Andric   *ret_label = 0;
186268d75effSDimitry Andric   if (ret == -1) {
186368d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
186468d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
186568d75effSDimitry Andric   }
186668d75effSDimitry Andric   return ret;
186768d75effSDimitry Andric }
186868d75effSDimitry Andric 
1869fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
1870fe6060f1SDimitry Andric     const struct timespec *req, struct timespec *rem, dfsan_label req_label,
1871fe6060f1SDimitry Andric     dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin,
1872fe6060f1SDimitry Andric     dfsan_origin rem_origin, dfsan_origin *ret_origin) {
1873fe6060f1SDimitry Andric   return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
1874fe6060f1SDimitry Andric }
1875fe6060f1SDimitry Andric 
1876e8d8bef9SDimitry Andric static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) {
1877e8d8bef9SDimitry Andric   dfsan_set_label(0, msg, sizeof(*msg));
1878e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
1879e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
1880e8d8bef9SDimitry Andric   for (size_t i = 0; bytes_written > 0; ++i) {
1881e8d8bef9SDimitry Andric     assert(i < msg->msg_iovlen);
1882e8d8bef9SDimitry Andric     struct iovec *iov = &msg->msg_iov[i];
1883e8d8bef9SDimitry Andric     size_t iov_written =
1884e8d8bef9SDimitry Andric         bytes_written < iov->iov_len ? bytes_written : iov->iov_len;
1885e8d8bef9SDimitry Andric     dfsan_set_label(0, iov->iov_base, iov_written);
1886e8d8bef9SDimitry Andric     bytes_written -= iov_written;
1887e8d8bef9SDimitry Andric   }
1888e8d8bef9SDimitry Andric }
1889e8d8bef9SDimitry Andric 
1890e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
1891e8d8bef9SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1892e8d8bef9SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1893e8d8bef9SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1894e8d8bef9SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label) {
1895e8d8bef9SDimitry Andric   int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
1896e8d8bef9SDimitry Andric   for (int i = 0; i < ret; ++i) {
1897e8d8bef9SDimitry Andric     dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
1898e8d8bef9SDimitry Andric     clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr);
1899e8d8bef9SDimitry Andric   }
1900e8d8bef9SDimitry Andric   *ret_label = 0;
1901e8d8bef9SDimitry Andric   return ret;
1902e8d8bef9SDimitry Andric }
1903e8d8bef9SDimitry Andric 
1904fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg(
1905fe6060f1SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1906fe6060f1SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1907fe6060f1SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1908fe6060f1SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label,
1909fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msgvec_origin,
1910fe6060f1SDimitry Andric     dfsan_origin vlen_origin, dfsan_origin flags_origin,
1911fe6060f1SDimitry Andric     dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1912fe6060f1SDimitry Andric   return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label,
1913fe6060f1SDimitry Andric                          msgvec_label, vlen_label, flags_label, timeout_label,
1914fe6060f1SDimitry Andric                          ret_label);
1915fe6060f1SDimitry Andric }
1916fe6060f1SDimitry Andric 
1917e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
1918e8d8bef9SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1919e8d8bef9SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
1920e8d8bef9SDimitry Andric   ssize_t ret = recvmsg(sockfd, msg, flags);
1921e8d8bef9SDimitry Andric   if (ret >= 0)
1922e8d8bef9SDimitry Andric     clear_msghdr_labels(ret, msg);
1923e8d8bef9SDimitry Andric   *ret_label = 0;
1924e8d8bef9SDimitry Andric   return ret;
1925e8d8bef9SDimitry Andric }
1926e8d8bef9SDimitry Andric 
1927fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg(
1928fe6060f1SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1929fe6060f1SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label,
1930fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msg_origin,
1931fe6060f1SDimitry Andric     dfsan_origin flags_origin, dfsan_origin *ret_origin) {
1932fe6060f1SDimitry Andric   return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label,
1933fe6060f1SDimitry Andric                         flags_label, ret_label);
1934fe6060f1SDimitry Andric }
1935fe6060f1SDimitry Andric 
193668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
193768d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
193868d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
193968d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
194068d75effSDimitry Andric                   dfsan_label *ret_label) {
194168d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
194268d75effSDimitry Andric   *ret_label = 0;
194368d75effSDimitry Andric   if (ret == 0) {
194468d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
194568d75effSDimitry Andric   }
194668d75effSDimitry Andric   return ret;
194768d75effSDimitry Andric }
194868d75effSDimitry Andric 
1949fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair(
1950fe6060f1SDimitry Andric     int domain, int type, int protocol, int sv[2], dfsan_label domain_label,
1951fe6060f1SDimitry Andric     dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label,
1952fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin domain_origin,
1953fe6060f1SDimitry Andric     dfsan_origin type_origin, dfsan_origin protocol_origin,
1954fe6060f1SDimitry Andric     dfsan_origin sv_origin, dfsan_origin *ret_origin) {
1955fe6060f1SDimitry Andric   return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label,
1956fe6060f1SDimitry Andric                            protocol_label, sv_label, ret_label);
1957fe6060f1SDimitry Andric }
1958fe6060f1SDimitry Andric 
1959e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt(
1960e8d8bef9SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
1961e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
1962e8d8bef9SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
1963e8d8bef9SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label) {
1964e8d8bef9SDimitry Andric   int ret = getsockopt(sockfd, level, optname, optval, optlen);
1965e8d8bef9SDimitry Andric   if (ret != -1 && optval && optlen) {
1966e8d8bef9SDimitry Andric     dfsan_set_label(0, optlen, sizeof(*optlen));
1967e8d8bef9SDimitry Andric     dfsan_set_label(0, optval, *optlen);
1968e8d8bef9SDimitry Andric   }
1969e8d8bef9SDimitry Andric   *ret_label = 0;
1970e8d8bef9SDimitry Andric   return ret;
1971e8d8bef9SDimitry Andric }
1972e8d8bef9SDimitry Andric 
1973fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt(
1974fe6060f1SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
1975fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
1976fe6060f1SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
1977fe6060f1SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label,
1978fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin level_origin,
1979fe6060f1SDimitry Andric     dfsan_origin optname_origin, dfsan_origin optval_origin,
1980fe6060f1SDimitry Andric     dfsan_origin optlen_origin, dfsan_origin *ret_origin) {
1981fe6060f1SDimitry Andric   return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label,
1982fe6060f1SDimitry Andric                            level_label, optname_label, optval_label,
1983fe6060f1SDimitry Andric                            optlen_label, ret_label);
1984fe6060f1SDimitry Andric }
1985fe6060f1SDimitry Andric 
1986e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname(
1987e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
1988e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
1989e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
1990e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
1991e8d8bef9SDimitry Andric   int ret = getsockname(sockfd, addr, addrlen);
1992e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
1993e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
1994e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
1995e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
1996e8d8bef9SDimitry Andric   }
1997e8d8bef9SDimitry Andric   *ret_label = 0;
1998e8d8bef9SDimitry Andric   return ret;
1999e8d8bef9SDimitry Andric }
2000e8d8bef9SDimitry Andric 
2001fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname(
2002fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2003fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2004fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2005fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2006fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2007fe6060f1SDimitry Andric   return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label,
2008fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2009fe6060f1SDimitry Andric }
2010fe6060f1SDimitry Andric 
2011e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername(
2012e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2013e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2014e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2015e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2016e8d8bef9SDimitry Andric   int ret = getpeername(sockfd, addr, addrlen);
2017e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2018e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2019e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2020e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2021e8d8bef9SDimitry Andric   }
2022e8d8bef9SDimitry Andric   *ret_label = 0;
2023e8d8bef9SDimitry Andric   return ret;
2024e8d8bef9SDimitry Andric }
2025e8d8bef9SDimitry Andric 
2026fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername(
2027fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2028fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2029fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2030fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2031fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2032fe6060f1SDimitry Andric   return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label,
2033fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2034fe6060f1SDimitry Andric }
2035fe6060f1SDimitry Andric 
2036*81ad6265SDimitry Andric // Type of the function passed to dfsan_set_write_callback.
2037*81ad6265SDimitry Andric typedef void (*write_dfsan_callback_t)(int fd, const void *buf, ssize_t count);
2038fe6060f1SDimitry Andric 
203968d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
204068d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
204168d75effSDimitry Andric static struct {
2042*81ad6265SDimitry Andric   write_dfsan_callback_t write_callback = nullptr;
204368d75effSDimitry Andric } write_callback_info;
204468d75effSDimitry Andric 
2045*81ad6265SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_dfsan_set_write_callback(
2046*81ad6265SDimitry Andric     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
204768d75effSDimitry Andric     dfsan_label *ret_label) {
204868d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
204968d75effSDimitry Andric }
205068d75effSDimitry Andric 
2051fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
2052*81ad6265SDimitry Andric     write_dfsan_callback_t write_callback, dfsan_label write_callback_label,
2053*81ad6265SDimitry Andric     dfsan_label *ret_label, dfsan_origin write_callback_origin,
2054*81ad6265SDimitry Andric     dfsan_origin *ret_origin) {
2055*81ad6265SDimitry Andric   write_callback_info.write_callback = write_callback;
2056*81ad6265SDimitry Andric }
2057*81ad6265SDimitry Andric 
2058*81ad6265SDimitry Andric static inline void setup_tls_args_for_write_callback(
2059*81ad6265SDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
2060*81ad6265SDimitry Andric     bool origins, dfsan_origin fd_origin, dfsan_origin buf_origin,
2061*81ad6265SDimitry Andric     dfsan_origin count_origin) {
2062*81ad6265SDimitry Andric   // The callback code will expect argument shadow labels in the args TLS,
2063*81ad6265SDimitry Andric   // and origin labels in the origin args TLS.
2064*81ad6265SDimitry Andric   // Previously this was done by a trampoline, but we want to remove this:
2065*81ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/issues/54172
2066*81ad6265SDimitry Andric   //
2067*81ad6265SDimitry Andric   // Instead, this code is manually setting up the args TLS data.
2068*81ad6265SDimitry Andric   //
2069*81ad6265SDimitry Andric   // The offsets used need to correspond with the instrumentation code,
2070*81ad6265SDimitry Andric   // see llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
2071*81ad6265SDimitry Andric   // DFSanFunction::getShadowForTLSArgument.
2072*81ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L1684
2073*81ad6265SDimitry Andric   // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L125
2074*81ad6265SDimitry Andric   //
2075*81ad6265SDimitry Andric   // Here the arguments are all primitives, but it can be more complex
2076*81ad6265SDimitry Andric   // to compute offsets for array/aggregate type arguments.
2077*81ad6265SDimitry Andric   //
2078*81ad6265SDimitry Andric   // TODO(browneee): Consider a builtin to improve maintainabliity.
2079*81ad6265SDimitry Andric   // With a builtin, we would provide the argument labels via builtin,
2080*81ad6265SDimitry Andric   // and the builtin would reuse parts of the instrumentation code to ensure
2081*81ad6265SDimitry Andric   // that this code and the instrumentation can never be out of sync.
2082*81ad6265SDimitry Andric   // Note: Currently DFSan instrumentation does not run on this code, so
2083*81ad6265SDimitry Andric   // the builtin may need to be handled outside DFSan instrumentation.
2084*81ad6265SDimitry Andric   dfsan_set_arg_tls(0, fd_label);
2085*81ad6265SDimitry Andric   dfsan_set_arg_tls(1, buf_label);
2086*81ad6265SDimitry Andric   dfsan_set_arg_tls(2, count_label);
2087*81ad6265SDimitry Andric   if (origins) {
2088*81ad6265SDimitry Andric     dfsan_set_arg_origin_tls(0, fd_origin);
2089*81ad6265SDimitry Andric     dfsan_set_arg_origin_tls(1, buf_origin);
2090*81ad6265SDimitry Andric     dfsan_set_arg_origin_tls(2, count_origin);
2091*81ad6265SDimitry Andric   }
2092fe6060f1SDimitry Andric }
2093fe6060f1SDimitry Andric 
209468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
209568d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
209668d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
209768d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
209868d75effSDimitry Andric   if (write_callback_info.write_callback) {
2099*81ad6265SDimitry Andric     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, false,
2100*81ad6265SDimitry Andric                                       0, 0, 0);
2101*81ad6265SDimitry Andric     write_callback_info.write_callback(fd, buf, count);
210268d75effSDimitry Andric   }
210368d75effSDimitry Andric 
210468d75effSDimitry Andric   *ret_label = 0;
210568d75effSDimitry Andric   return write(fd, buf, count);
210668d75effSDimitry Andric }
2107fe6060f1SDimitry Andric 
2108fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
2109fe6060f1SDimitry Andric     int fd, const void *buf, size_t count, dfsan_label fd_label,
2110fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
2111fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
2112fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2113*81ad6265SDimitry Andric   if (write_callback_info.write_callback) {
2114*81ad6265SDimitry Andric     setup_tls_args_for_write_callback(fd_label, buf_label, count_label, true,
2115*81ad6265SDimitry Andric                                       fd_origin, buf_origin, count_origin);
2116*81ad6265SDimitry Andric     write_callback_info.write_callback(fd, buf, count);
2117fe6060f1SDimitry Andric   }
2118fe6060f1SDimitry Andric 
2119fe6060f1SDimitry Andric   *ret_label = 0;
2120fe6060f1SDimitry Andric   return write(fd, buf, count);
2121fe6060f1SDimitry Andric }
212268d75effSDimitry Andric } // namespace __dfsan
212368d75effSDimitry Andric 
212468d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
212568d75effSDimitry Andric typedef int dfsan_label_va;
212668d75effSDimitry Andric 
212768d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
212868d75effSDimitry Andric // '%.3f').
212968d75effSDimitry Andric struct Formatter {
213068d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
213168d75effSDimitry Andric       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
213268d75effSDimitry Andric         width(-1) {}
213368d75effSDimitry Andric 
213468d75effSDimitry Andric   int format() {
213568d75effSDimitry Andric     char *tmp_fmt = build_format_string();
213668d75effSDimitry Andric     int retval =
213768d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
213868d75effSDimitry Andric                  0 /* used only to avoid warnings */);
213968d75effSDimitry Andric     free(tmp_fmt);
214068d75effSDimitry Andric     return retval;
214168d75effSDimitry Andric   }
214268d75effSDimitry Andric 
214368d75effSDimitry Andric   template <typename T> int format(T arg) {
214468d75effSDimitry Andric     char *tmp_fmt = build_format_string();
214568d75effSDimitry Andric     int retval;
214668d75effSDimitry Andric     if (width >= 0) {
214768d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
214868d75effSDimitry Andric                         tmp_fmt, width, arg);
214968d75effSDimitry Andric     } else {
215068d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
215168d75effSDimitry Andric                         tmp_fmt, arg);
215268d75effSDimitry Andric     }
215368d75effSDimitry Andric     free(tmp_fmt);
215468d75effSDimitry Andric     return retval;
215568d75effSDimitry Andric   }
215668d75effSDimitry Andric 
215768d75effSDimitry Andric   char *build_format_string() {
215868d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
215968d75effSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1);
216068d75effSDimitry Andric     assert(new_fmt);
216168d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
216268d75effSDimitry Andric     new_fmt[fmt_size] = '\0';
216368d75effSDimitry Andric     return new_fmt;
216468d75effSDimitry Andric   }
216568d75effSDimitry Andric 
216668d75effSDimitry Andric   char *str_cur() { return str + str_off; }
216768d75effSDimitry Andric 
216868d75effSDimitry Andric   size_t num_written_bytes(int retval) {
216968d75effSDimitry Andric     if (retval < 0) {
217068d75effSDimitry Andric       return 0;
217168d75effSDimitry Andric     }
217268d75effSDimitry Andric 
217368d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
217468d75effSDimitry Andric     if (num_avail == 0) {
217568d75effSDimitry Andric       return 0;
217668d75effSDimitry Andric     }
217768d75effSDimitry Andric 
217868d75effSDimitry Andric     size_t num_written = retval;
217968d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
218068d75effSDimitry Andric     // truncated.
218168d75effSDimitry Andric     if (num_written >= num_avail) {
218268d75effSDimitry Andric       num_written -= num_avail;
218368d75effSDimitry Andric     }
218468d75effSDimitry Andric 
218568d75effSDimitry Andric     return num_written;
218668d75effSDimitry Andric   }
218768d75effSDimitry Andric 
218868d75effSDimitry Andric   char *str;
218968d75effSDimitry Andric   size_t str_off;
219068d75effSDimitry Andric   size_t size;
219168d75effSDimitry Andric   const char *fmt_start;
219268d75effSDimitry Andric   const char *fmt_cur;
219368d75effSDimitry Andric   int width;
219468d75effSDimitry Andric };
219568d75effSDimitry Andric 
219668d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
219768d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
219868d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
219968d75effSDimitry Andric // the return value vsnprintf would return.
220068d75effSDimitry Andric //
220168d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
220268d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
220368d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
220468d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
220568d75effSDimitry Andric // propagate labels more precisely.
220668d75effSDimitry Andric //
220768d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
220868d75effSDimitry Andric // positional arguments.
220968d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
221068d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
2211fe6060f1SDimitry Andric                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
221268d75effSDimitry Andric                          va_list ap) {
221368d75effSDimitry Andric   Formatter formatter(str, fmt, size);
221468d75effSDimitry Andric 
221568d75effSDimitry Andric   while (*formatter.fmt_cur) {
221668d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
221768d75effSDimitry Andric     formatter.width = -1;
221868d75effSDimitry Andric     int retval = 0;
221968d75effSDimitry Andric 
222068d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
222168d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
222268d75effSDimitry Andric       // of the string.
222368d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
222468d75effSDimitry Andric            ++formatter.fmt_cur) {}
222568d75effSDimitry Andric       retval = formatter.format();
222668d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
222768d75effSDimitry Andric                       formatter.num_written_bytes(retval));
222868d75effSDimitry Andric     } else {
222968d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
223068d75effSDimitry Andric       // specifier or the end of the string.
223168d75effSDimitry Andric       bool end_fmt = false;
223268d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
223368d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
223468d75effSDimitry Andric         case 'd':
223568d75effSDimitry Andric         case 'i':
223668d75effSDimitry Andric         case 'o':
223768d75effSDimitry Andric         case 'u':
223868d75effSDimitry Andric         case 'x':
223968d75effSDimitry Andric         case 'X':
224068d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
224168d75effSDimitry Andric           case 'h':
224268d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
224368d75effSDimitry Andric             // an int).
224468d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
224568d75effSDimitry Andric             break;
224668d75effSDimitry Andric           case 'l':
224768d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
224868d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
224968d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
225068d75effSDimitry Andric             } else {
225168d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
225268d75effSDimitry Andric             }
225368d75effSDimitry Andric             break;
225468d75effSDimitry Andric           case 'q':
225568d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
225668d75effSDimitry Andric             break;
225768d75effSDimitry Andric           case 'j':
225868d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
225968d75effSDimitry Andric             break;
226068d75effSDimitry Andric           case 'z':
226168d75effSDimitry Andric           case 't':
226268d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
226368d75effSDimitry Andric             break;
226468d75effSDimitry Andric           default:
226568d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
226668d75effSDimitry Andric           }
2267fe6060f1SDimitry Andric           if (va_origins == nullptr)
226868d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
226968d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2270fe6060f1SDimitry Andric           else
2271fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2272fe6060f1SDimitry Andric                                    formatter.str_cur(),
2273fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
227468d75effSDimitry Andric           end_fmt = true;
227568d75effSDimitry Andric           break;
227668d75effSDimitry Andric 
227768d75effSDimitry Andric         case 'a':
227868d75effSDimitry Andric         case 'A':
227968d75effSDimitry Andric         case 'e':
228068d75effSDimitry Andric         case 'E':
228168d75effSDimitry Andric         case 'f':
228268d75effSDimitry Andric         case 'F':
228368d75effSDimitry Andric         case 'g':
228468d75effSDimitry Andric         case 'G':
228568d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
228668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
228768d75effSDimitry Andric           } else {
228868d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
228968d75effSDimitry Andric           }
2290fe6060f1SDimitry Andric           if (va_origins == nullptr)
229168d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
229268d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2293fe6060f1SDimitry Andric           else
2294fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2295fe6060f1SDimitry Andric                                    formatter.str_cur(),
2296fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
229768d75effSDimitry Andric           end_fmt = true;
229868d75effSDimitry Andric           break;
229968d75effSDimitry Andric 
230068d75effSDimitry Andric         case 'c':
230168d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
2302fe6060f1SDimitry Andric           if (va_origins == nullptr)
230368d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
230468d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2305fe6060f1SDimitry Andric           else
2306fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2307fe6060f1SDimitry Andric                                    formatter.str_cur(),
2308fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
230968d75effSDimitry Andric           end_fmt = true;
231068d75effSDimitry Andric           break;
231168d75effSDimitry Andric 
231268d75effSDimitry Andric         case 's': {
231368d75effSDimitry Andric           char *arg = va_arg(ap, char *);
231468d75effSDimitry Andric           retval = formatter.format(arg);
2315fe6060f1SDimitry Andric           if (va_origins) {
2316fe6060f1SDimitry Andric             va_origins++;
2317fe6060f1SDimitry Andric             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
2318fe6060f1SDimitry Andric                                       formatter.num_written_bytes(retval));
2319fe6060f1SDimitry Andric           }
232068d75effSDimitry Andric           va_labels++;
232104eeddc0SDimitry Andric           dfsan_mem_shadow_transfer(formatter.str_cur(), arg,
232268d75effSDimitry Andric                                     formatter.num_written_bytes(retval));
232368d75effSDimitry Andric           end_fmt = true;
232468d75effSDimitry Andric           break;
232568d75effSDimitry Andric         }
232668d75effSDimitry Andric 
232768d75effSDimitry Andric         case 'p':
232868d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
2329fe6060f1SDimitry Andric           if (va_origins == nullptr)
233068d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
233168d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2332fe6060f1SDimitry Andric           else
2333fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2334fe6060f1SDimitry Andric                                    formatter.str_cur(),
2335fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
233668d75effSDimitry Andric           end_fmt = true;
233768d75effSDimitry Andric           break;
233868d75effSDimitry Andric 
233968d75effSDimitry Andric         case 'n': {
234068d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
234168d75effSDimitry Andric           *ptr = (int)formatter.str_off;
234268d75effSDimitry Andric           va_labels++;
2343fe6060f1SDimitry Andric           if (va_origins)
2344fe6060f1SDimitry Andric             va_origins++;
234568d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
234668d75effSDimitry Andric           end_fmt = true;
234768d75effSDimitry Andric           break;
234868d75effSDimitry Andric         }
234968d75effSDimitry Andric 
235068d75effSDimitry Andric         case '%':
235168d75effSDimitry Andric           retval = formatter.format();
235268d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
235368d75effSDimitry Andric                           formatter.num_written_bytes(retval));
235468d75effSDimitry Andric           end_fmt = true;
235568d75effSDimitry Andric           break;
235668d75effSDimitry Andric 
235768d75effSDimitry Andric         case '*':
235868d75effSDimitry Andric           formatter.width = va_arg(ap, int);
235968d75effSDimitry Andric           va_labels++;
2360fe6060f1SDimitry Andric           if (va_origins)
2361fe6060f1SDimitry Andric             va_origins++;
236268d75effSDimitry Andric           break;
236368d75effSDimitry Andric 
236468d75effSDimitry Andric         default:
236568d75effSDimitry Andric           break;
236668d75effSDimitry Andric         }
236768d75effSDimitry Andric       }
236868d75effSDimitry Andric     }
236968d75effSDimitry Andric 
237068d75effSDimitry Andric     if (retval < 0) {
237168d75effSDimitry Andric       return retval;
237268d75effSDimitry Andric     }
237368d75effSDimitry Andric 
237468d75effSDimitry Andric     formatter.fmt_cur++;
237568d75effSDimitry Andric     formatter.str_off += retval;
237668d75effSDimitry Andric   }
237768d75effSDimitry Andric 
237868d75effSDimitry Andric   *ret_label = 0;
2379fe6060f1SDimitry Andric   if (ret_origin)
2380fe6060f1SDimitry Andric     *ret_origin = 0;
238168d75effSDimitry Andric 
238268d75effSDimitry Andric   // Number of bytes written in total.
238368d75effSDimitry Andric   return formatter.str_off;
238468d75effSDimitry Andric }
238568d75effSDimitry Andric 
238668d75effSDimitry Andric extern "C" {
238768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
238868d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
238968d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
239068d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
239168d75effSDimitry Andric   va_list ap;
239268d75effSDimitry Andric   va_start(ap, ret_label);
2393fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
2394fe6060f1SDimitry Andric                           nullptr, ap);
2395fe6060f1SDimitry Andric   va_end(ap);
2396fe6060f1SDimitry Andric   return ret;
2397fe6060f1SDimitry Andric }
2398fe6060f1SDimitry Andric 
2399fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2400fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
2401fe6060f1SDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
2402fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin str_origin,
2403fe6060f1SDimitry Andric                    dfsan_origin format_origin, dfsan_origin *va_origins,
2404fe6060f1SDimitry Andric                    dfsan_origin *ret_origin, ...) {
2405fe6060f1SDimitry Andric   va_list ap;
2406fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2407fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, va_origins,
2408fe6060f1SDimitry Andric                           ret_origin, ap);
240968d75effSDimitry Andric   va_end(ap);
241068d75effSDimitry Andric   return ret;
241168d75effSDimitry Andric }
241268d75effSDimitry Andric 
241368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
241468d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
241568d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
241668d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
241768d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
241868d75effSDimitry Andric   va_list ap;
241968d75effSDimitry Andric   va_start(ap, ret_label);
2420fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
2421fe6060f1SDimitry Andric                           nullptr, ap);
242268d75effSDimitry Andric   va_end(ap);
242368d75effSDimitry Andric   return ret;
242468d75effSDimitry Andric }
242568d75effSDimitry Andric 
2426fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2427fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format,
2428fe6060f1SDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
2429fe6060f1SDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
2430fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin str_origin,
2431fe6060f1SDimitry Andric                     dfsan_origin size_origin, dfsan_origin format_origin,
2432fe6060f1SDimitry Andric                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
2433fe6060f1SDimitry Andric   va_list ap;
2434fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2435fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
2436fe6060f1SDimitry Andric                           ret_origin, ap);
2437fe6060f1SDimitry Andric   va_end(ap);
2438fe6060f1SDimitry Andric   return ret;
2439fe6060f1SDimitry Andric }
2440fe6060f1SDimitry Andric 
2441fe6060f1SDimitry Andric static void BeforeFork() {
2442fe6060f1SDimitry Andric   StackDepotLockAll();
2443fe6060f1SDimitry Andric   GetChainedOriginDepot()->LockAll();
2444fe6060f1SDimitry Andric }
2445fe6060f1SDimitry Andric 
2446fe6060f1SDimitry Andric static void AfterFork() {
2447fe6060f1SDimitry Andric   GetChainedOriginDepot()->UnlockAll();
2448fe6060f1SDimitry Andric   StackDepotUnlockAll();
2449fe6060f1SDimitry Andric }
2450fe6060f1SDimitry Andric 
2451fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2452fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) {
2453fe6060f1SDimitry Andric   pid_t pid = fork();
2454fe6060f1SDimitry Andric   *ret_label = 0;
2455fe6060f1SDimitry Andric   return pid;
2456fe6060f1SDimitry Andric }
2457fe6060f1SDimitry Andric 
2458fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2459fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
2460fe6060f1SDimitry Andric   BeforeFork();
2461fe6060f1SDimitry Andric   pid_t pid = __dfsw_fork(ret_label);
2462fe6060f1SDimitry Andric   AfterFork();
2463fe6060f1SDimitry Andric   return pid;
2464fe6060f1SDimitry Andric }
2465fe6060f1SDimitry Andric 
246668d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
246768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
246868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
246968d75effSDimitry Andric                              u32 *) {}
2470349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
2471349cc55cSDimitry Andric                              const uptr *end) {}
247268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
247368d75effSDimitry Andric 
247468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
247568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
247668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
247768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
247868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
247968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
248068d75effSDimitry Andric                              void) {}
248168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
248268d75effSDimitry Andric                              void) {}
248368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
248468d75effSDimitry Andric                              void) {}
248568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
248668d75effSDimitry Andric                              void) {}
248768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
248868d75effSDimitry Andric }  // extern "C"
2489