xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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) {
500*04eeddc0SDimitry 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);
585*04eeddc0SDimitry 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);
598*04eeddc0SDimitry 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_trampoline,
757fe6060f1SDimitry Andric                                 void *start_routine, void *arg,
758fe6060f1SDimitry Andric                                 dfsan_label *ret_label,
759fe6060f1SDimitry Andric                                 bool track_origins = false) {
760fe6060f1SDimitry Andric   pthread_attr_t myattr;
761fe6060f1SDimitry Andric   if (!attr) {
762fe6060f1SDimitry Andric     pthread_attr_init(&myattr);
763fe6060f1SDimitry Andric     attr = &myattr;
764fe6060f1SDimitry Andric   }
765fe6060f1SDimitry Andric 
766fe6060f1SDimitry Andric   // Ensure that the thread stack is large enough to hold all TLS data.
767fe6060f1SDimitry Andric   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
768fe6060f1SDimitry Andric 
769fe6060f1SDimitry Andric   DFsanThread *t =
770fe6060f1SDimitry Andric       DFsanThread::Create(start_routine_trampoline,
771fe6060f1SDimitry Andric                           (thread_callback_t)start_routine, arg, track_origins);
772349cc55cSDimitry Andric   ScopedBlockSignals block(&t->starting_sigset_);
773fe6060f1SDimitry Andric   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
774fe6060f1SDimitry Andric 
775fe6060f1SDimitry Andric   if (attr == &myattr)
776fe6060f1SDimitry Andric     pthread_attr_destroy(&myattr);
777fe6060f1SDimitry Andric   *ret_label = 0;
778fe6060f1SDimitry Andric   return res;
77968d75effSDimitry Andric }
78068d75effSDimitry Andric 
78168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
78268d75effSDimitry Andric     pthread_t *thread, const pthread_attr_t *attr,
78368d75effSDimitry Andric     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
78468d75effSDimitry Andric                                       dfsan_label *),
78568d75effSDimitry Andric     void *start_routine, void *arg, dfsan_label thread_label,
78668d75effSDimitry Andric     dfsan_label attr_label, dfsan_label start_routine_label,
78768d75effSDimitry Andric     dfsan_label arg_label, dfsan_label *ret_label) {
788fe6060f1SDimitry Andric   return dfsan_pthread_create(thread, attr, (void *)start_routine_trampoline,
789fe6060f1SDimitry Andric                               start_routine, arg, ret_label);
790fe6060f1SDimitry Andric }
791fe6060f1SDimitry Andric 
792fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
793fe6060f1SDimitry Andric     pthread_t *thread, const pthread_attr_t *attr,
794fe6060f1SDimitry Andric     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
795fe6060f1SDimitry Andric                                       dfsan_label *, dfsan_origin,
796fe6060f1SDimitry Andric                                       dfsan_origin *),
797fe6060f1SDimitry Andric     void *start_routine, void *arg, dfsan_label thread_label,
798fe6060f1SDimitry Andric     dfsan_label attr_label, dfsan_label start_routine_label,
799fe6060f1SDimitry Andric     dfsan_label arg_label, dfsan_label *ret_label, dfsan_origin thread_origin,
800fe6060f1SDimitry Andric     dfsan_origin attr_origin, dfsan_origin start_routine_origin,
801fe6060f1SDimitry Andric     dfsan_origin arg_origin, dfsan_origin *ret_origin) {
802fe6060f1SDimitry Andric   return dfsan_pthread_create(thread, attr, (void *)start_routine_trampoline,
803fe6060f1SDimitry Andric                               start_routine, arg, ret_label, true);
80468d75effSDimitry Andric }
80568d75effSDimitry Andric 
806e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
807e8d8bef9SDimitry Andric                                                       void **retval,
808e8d8bef9SDimitry Andric                                                       dfsan_label thread_label,
809e8d8bef9SDimitry Andric                                                       dfsan_label retval_label,
810e8d8bef9SDimitry Andric                                                       dfsan_label *ret_label) {
811e8d8bef9SDimitry Andric   int ret = pthread_join(thread, retval);
812e8d8bef9SDimitry Andric   if (ret == 0 && retval)
813e8d8bef9SDimitry Andric     dfsan_set_label(0, retval, sizeof(*retval));
814e8d8bef9SDimitry Andric   *ret_label = 0;
815e8d8bef9SDimitry Andric   return ret;
816e8d8bef9SDimitry Andric }
817e8d8bef9SDimitry Andric 
818fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
819fe6060f1SDimitry Andric     pthread_t thread, void **retval, dfsan_label thread_label,
820fe6060f1SDimitry Andric     dfsan_label retval_label, dfsan_label *ret_label,
821fe6060f1SDimitry Andric     dfsan_origin thread_origin, dfsan_origin retval_origin,
822fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
823fe6060f1SDimitry Andric   return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
824fe6060f1SDimitry Andric                              ret_label);
825fe6060f1SDimitry Andric }
826fe6060f1SDimitry Andric 
82768d75effSDimitry Andric struct dl_iterate_phdr_info {
82868d75effSDimitry Andric   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
82968d75effSDimitry Andric                              size_t size, void *data, dfsan_label info_label,
83068d75effSDimitry Andric                              dfsan_label size_label, dfsan_label data_label,
83168d75effSDimitry Andric                              dfsan_label *ret_label);
83268d75effSDimitry Andric   void *callback;
83368d75effSDimitry Andric   void *data;
83468d75effSDimitry Andric };
83568d75effSDimitry Andric 
836fe6060f1SDimitry Andric struct dl_iterate_phdr_origin_info {
837fe6060f1SDimitry Andric   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
838fe6060f1SDimitry Andric                              size_t size, void *data, dfsan_label info_label,
839fe6060f1SDimitry Andric                              dfsan_label size_label, dfsan_label data_label,
840fe6060f1SDimitry Andric                              dfsan_label *ret_label, dfsan_origin info_origin,
841fe6060f1SDimitry Andric                              dfsan_origin size_origin, dfsan_origin data_origin,
842fe6060f1SDimitry Andric                              dfsan_origin *ret_origin);
843fe6060f1SDimitry Andric   void *callback;
844fe6060f1SDimitry Andric   void *data;
845fe6060f1SDimitry Andric };
846fe6060f1SDimitry Andric 
84768d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
84868d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
84968d75effSDimitry Andric   dfsan_set_label(0, *info);
85068d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
85168d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
85268d75effSDimitry Andric   dfsan_set_label(
85368d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
85468d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
85568d75effSDimitry Andric   dfsan_label ret_label;
85668d75effSDimitry Andric   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
85768d75effSDimitry Andric                                    0, &ret_label);
85868d75effSDimitry Andric }
85968d75effSDimitry Andric 
860fe6060f1SDimitry Andric int dl_iterate_phdr_origin_cb(struct dl_phdr_info *info, size_t size,
861fe6060f1SDimitry Andric                               void *data) {
862fe6060f1SDimitry Andric   dl_iterate_phdr_origin_info *dipi = (dl_iterate_phdr_origin_info *)data;
863fe6060f1SDimitry Andric   dfsan_set_label(0, *info);
864fe6060f1SDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
865fe6060f1SDimitry Andric                   strlen(info->dlpi_name) + 1);
866fe6060f1SDimitry Andric   dfsan_set_label(
867fe6060f1SDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
868fe6060f1SDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
869fe6060f1SDimitry Andric   dfsan_label ret_label;
870fe6060f1SDimitry Andric   dfsan_origin ret_origin;
871fe6060f1SDimitry Andric   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
872fe6060f1SDimitry Andric                                    0, &ret_label, 0, 0, 0, &ret_origin);
873fe6060f1SDimitry Andric }
874fe6060f1SDimitry Andric 
87568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
87668d75effSDimitry Andric     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
87768d75effSDimitry Andric                                size_t size, void *data, dfsan_label info_label,
87868d75effSDimitry Andric                                dfsan_label size_label, dfsan_label data_label,
87968d75effSDimitry Andric                                dfsan_label *ret_label),
88068d75effSDimitry Andric     void *callback, void *data, dfsan_label callback_label,
88168d75effSDimitry Andric     dfsan_label data_label, dfsan_label *ret_label) {
88268d75effSDimitry Andric   dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
88368d75effSDimitry Andric   *ret_label = 0;
88468d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
88568d75effSDimitry Andric }
88668d75effSDimitry Andric 
887fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr(
888fe6060f1SDimitry Andric     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
889fe6060f1SDimitry Andric                                size_t size, void *data, dfsan_label info_label,
890fe6060f1SDimitry Andric                                dfsan_label size_label, dfsan_label data_label,
891fe6060f1SDimitry Andric                                dfsan_label *ret_label, dfsan_origin info_origin,
892fe6060f1SDimitry Andric                                dfsan_origin size_origin,
893fe6060f1SDimitry Andric                                dfsan_origin data_origin,
894fe6060f1SDimitry Andric                                dfsan_origin *ret_origin),
895fe6060f1SDimitry Andric     void *callback, void *data, dfsan_label callback_label,
896fe6060f1SDimitry Andric     dfsan_label data_label, dfsan_label *ret_label,
897fe6060f1SDimitry Andric     dfsan_origin callback_origin, dfsan_origin data_origin,
898fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
899fe6060f1SDimitry Andric   dl_iterate_phdr_origin_info dipi = {callback_trampoline, callback, data};
900fe6060f1SDimitry Andric   *ret_label = 0;
901fe6060f1SDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_origin_cb, &dipi);
902fe6060f1SDimitry Andric }
903fe6060f1SDimitry Andric 
904e8d8bef9SDimitry Andric // This function is only available for glibc 2.27 or newer.  Mark it weak so
905e8d8bef9SDimitry Andric // linking succeeds with older glibcs.
906e8d8bef9SDimitry Andric SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep,
907e8d8bef9SDimitry Andric                                                       size_t *alignp);
908e8d8bef9SDimitry Andric 
909e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info(
910e8d8bef9SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
911e8d8bef9SDimitry Andric     dfsan_label alignp_label) {
912e8d8bef9SDimitry Andric   assert(_dl_get_tls_static_info);
913e8d8bef9SDimitry Andric   _dl_get_tls_static_info(sizep, alignp);
914e8d8bef9SDimitry Andric   dfsan_set_label(0, sizep, sizeof(*sizep));
915e8d8bef9SDimitry Andric   dfsan_set_label(0, alignp, sizeof(*alignp));
916e8d8bef9SDimitry Andric }
917e8d8bef9SDimitry Andric 
918fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info(
919fe6060f1SDimitry Andric     size_t *sizep, size_t *alignp, dfsan_label sizep_label,
920fe6060f1SDimitry Andric     dfsan_label alignp_label, dfsan_origin sizep_origin,
921fe6060f1SDimitry Andric     dfsan_origin alignp_origin) {
922fe6060f1SDimitry Andric   __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label);
923fe6060f1SDimitry Andric }
924fe6060f1SDimitry Andric 
92568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
92668d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
92768d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
92868d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
92968d75effSDimitry Andric   if (ret) {
93068d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
93168d75effSDimitry Andric                     strlen(buf) + 1);
93268d75effSDimitry Andric     *ret_label = buf_label;
93368d75effSDimitry Andric   } else {
93468d75effSDimitry Andric     *ret_label = 0;
93568d75effSDimitry Andric   }
93668d75effSDimitry Andric   return ret;
93768d75effSDimitry Andric }
93868d75effSDimitry Andric 
93968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
940fe6060f1SDimitry Andric char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
941fe6060f1SDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label,
942fe6060f1SDimitry Andric                      dfsan_origin timep_origin, dfsan_origin buf_origin,
943fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
944fe6060f1SDimitry Andric   char *ret = ctime_r(timep, buf);
945fe6060f1SDimitry Andric   if (ret) {
946fe6060f1SDimitry Andric     dfsan_set_label_origin(
947fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
948fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf,
949fe6060f1SDimitry Andric         strlen(buf) + 1);
950fe6060f1SDimitry Andric     *ret_label = buf_label;
951fe6060f1SDimitry Andric     *ret_origin = buf_origin;
952fe6060f1SDimitry Andric   } else {
953fe6060f1SDimitry Andric     *ret_label = 0;
954fe6060f1SDimitry Andric   }
955fe6060f1SDimitry Andric   return ret;
956fe6060f1SDimitry Andric }
957fe6060f1SDimitry Andric 
958fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
95968d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
96068d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
96168d75effSDimitry Andric                    dfsan_label *ret_label) {
96268d75effSDimitry Andric   char *ret = fgets(s, size, stream);
96368d75effSDimitry Andric   if (ret) {
96468d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
96568d75effSDimitry Andric     *ret_label = s_label;
96668d75effSDimitry Andric   } else {
96768d75effSDimitry Andric     *ret_label = 0;
96868d75effSDimitry Andric   }
96968d75effSDimitry Andric   return ret;
97068d75effSDimitry Andric }
97168d75effSDimitry Andric 
97268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
973fe6060f1SDimitry Andric char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
974fe6060f1SDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
975fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin s_origin,
976fe6060f1SDimitry Andric                    dfsan_origin size_origin, dfsan_origin stream_origin,
977fe6060f1SDimitry Andric                    dfsan_origin *ret_origin) {
978fe6060f1SDimitry Andric   char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label,
979fe6060f1SDimitry Andric                            ret_label);
980fe6060f1SDimitry Andric   if (ret)
981fe6060f1SDimitry Andric     *ret_origin = s_origin;
982fe6060f1SDimitry Andric   return ret;
983fe6060f1SDimitry Andric }
984fe6060f1SDimitry Andric 
985fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
98668d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
98768d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
98868d75effSDimitry Andric   char *ret = getcwd(buf, size);
98968d75effSDimitry Andric   if (ret) {
99068d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
99168d75effSDimitry Andric     *ret_label = buf_label;
99268d75effSDimitry Andric   } else {
99368d75effSDimitry Andric     *ret_label = 0;
99468d75effSDimitry Andric   }
99568d75effSDimitry Andric   return ret;
99668d75effSDimitry Andric }
99768d75effSDimitry Andric 
99868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
999fe6060f1SDimitry Andric char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label,
1000fe6060f1SDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label,
1001fe6060f1SDimitry Andric                     dfsan_origin buf_origin, dfsan_origin size_origin,
1002fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1003fe6060f1SDimitry Andric   char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label);
1004fe6060f1SDimitry Andric   if (ret)
1005fe6060f1SDimitry Andric     *ret_origin = buf_origin;
1006fe6060f1SDimitry Andric   return ret;
1007fe6060f1SDimitry Andric }
1008fe6060f1SDimitry Andric 
1009fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
101068d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
101168d75effSDimitry Andric   char *ret = get_current_dir_name();
1012fe6060f1SDimitry Andric   if (ret)
101368d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
101468d75effSDimitry Andric   *ret_label = 0;
101568d75effSDimitry Andric   return ret;
101668d75effSDimitry Andric }
101768d75effSDimitry Andric 
101868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1019fe6060f1SDimitry Andric char *__dfso_get_current_dir_name(dfsan_label *ret_label,
1020fe6060f1SDimitry Andric                                   dfsan_origin *ret_origin) {
1021fe6060f1SDimitry Andric   return __dfsw_get_current_dir_name(ret_label);
1022fe6060f1SDimitry Andric }
1023fe6060f1SDimitry Andric 
1024349cc55cSDimitry Andric // This function is only available for glibc 2.25 or newer.  Mark it weak so
1025349cc55cSDimitry Andric // linking succeeds with older glibcs.
1026349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length);
1027349cc55cSDimitry Andric 
1028349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length,
1029349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1030349cc55cSDimitry Andric                                                     dfsan_label length_label,
1031349cc55cSDimitry Andric                                                     dfsan_label *ret_label) {
1032349cc55cSDimitry Andric   int ret = getentropy(buffer, length);
1033349cc55cSDimitry Andric   if (ret == 0) {
1034349cc55cSDimitry Andric     dfsan_set_label(0, buffer, length);
1035349cc55cSDimitry Andric   }
1036349cc55cSDimitry Andric   *ret_label = 0;
1037349cc55cSDimitry Andric   return ret;
1038349cc55cSDimitry Andric }
1039349cc55cSDimitry Andric 
1040349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length,
1041349cc55cSDimitry Andric                                                     dfsan_label buffer_label,
1042349cc55cSDimitry Andric                                                     dfsan_label length_label,
1043349cc55cSDimitry Andric                                                     dfsan_label *ret_label,
1044349cc55cSDimitry Andric                                                     dfsan_origin buffer_origin,
1045349cc55cSDimitry Andric                                                     dfsan_origin length_origin,
1046349cc55cSDimitry Andric                                                     dfsan_origin *ret_origin) {
1047349cc55cSDimitry Andric   return __dfsw_getentropy(buffer, length, buffer_label, length_label,
1048349cc55cSDimitry Andric                            ret_label);
1049349cc55cSDimitry Andric }
1050349cc55cSDimitry Andric 
1051fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
105268d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
105368d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
105468d75effSDimitry Andric   int ret = gethostname(name, len);
105568d75effSDimitry Andric   if (ret == 0) {
105668d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
105768d75effSDimitry Andric   }
105868d75effSDimitry Andric   *ret_label = 0;
105968d75effSDimitry Andric   return ret;
106068d75effSDimitry Andric }
106168d75effSDimitry Andric 
106268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1063fe6060f1SDimitry Andric int __dfso_gethostname(char *name, size_t len, dfsan_label name_label,
1064fe6060f1SDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label,
1065fe6060f1SDimitry Andric                        dfsan_origin name_origin, dfsan_origin len_origin,
1066fe6060f1SDimitry Andric                        dfsan_label *ret_origin) {
1067fe6060f1SDimitry Andric   return __dfsw_gethostname(name, len, name_label, len_label, ret_label);
1068fe6060f1SDimitry Andric }
1069fe6060f1SDimitry Andric 
1070fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
107168d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
107268d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
107368d75effSDimitry Andric                      dfsan_label *ret_label) {
107468d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
107568d75effSDimitry Andric   if (ret == 0) {
107668d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
107768d75effSDimitry Andric   }
107868d75effSDimitry Andric   *ret_label = 0;
107968d75effSDimitry Andric   return ret;
108068d75effSDimitry Andric }
108168d75effSDimitry Andric 
108268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1083fe6060f1SDimitry Andric int __dfso_getrlimit(int resource, struct rlimit *rlim,
1084fe6060f1SDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
1085fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin resource_origin,
1086fe6060f1SDimitry Andric                      dfsan_origin rlim_origin, dfsan_origin *ret_origin) {
1087fe6060f1SDimitry Andric   return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label,
1088fe6060f1SDimitry Andric                           ret_label);
1089fe6060f1SDimitry Andric }
1090fe6060f1SDimitry Andric 
1091fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
109268d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
109368d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
109468d75effSDimitry Andric   int ret = getrusage(who, usage);
109568d75effSDimitry Andric   if (ret == 0) {
109668d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
109768d75effSDimitry Andric   }
109868d75effSDimitry Andric   *ret_label = 0;
109968d75effSDimitry Andric   return ret;
110068d75effSDimitry Andric }
110168d75effSDimitry Andric 
110268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1103fe6060f1SDimitry Andric int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label,
1104fe6060f1SDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label,
1105fe6060f1SDimitry Andric                      dfsan_origin who_origin, dfsan_origin usage_origin,
1106fe6060f1SDimitry Andric                      dfsan_label *ret_origin) {
1107fe6060f1SDimitry Andric   return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label);
1108fe6060f1SDimitry Andric }
1109fe6060f1SDimitry Andric 
1110fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
111168d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
111268d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
1113349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
111468d75effSDimitry Andric   if (ret) {
1115*04eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, strlen(src) + 1);
111668d75effSDimitry Andric   }
111768d75effSDimitry Andric   *ret_label = dst_label;
111868d75effSDimitry Andric   return ret;
111968d75effSDimitry Andric }
112068d75effSDimitry Andric 
112168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1122fe6060f1SDimitry Andric char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label,
1123fe6060f1SDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label,
1124fe6060f1SDimitry Andric                     dfsan_origin dst_origin, dfsan_origin src_origin,
1125fe6060f1SDimitry Andric                     dfsan_origin *ret_origin) {
1126349cc55cSDimitry Andric   char *ret = strcpy(dest, src);
1127fe6060f1SDimitry Andric   if (ret) {
1128fe6060f1SDimitry Andric     size_t str_len = strlen(src) + 1;
1129fe6060f1SDimitry Andric     dfsan_mem_origin_transfer(dest, src, str_len);
1130*04eeddc0SDimitry Andric     dfsan_mem_shadow_transfer(dest, src, str_len);
113168d75effSDimitry Andric   }
1132fe6060f1SDimitry Andric   *ret_label = dst_label;
1133fe6060f1SDimitry Andric   *ret_origin = dst_origin;
1134fe6060f1SDimitry Andric   return ret;
1135fe6060f1SDimitry Andric }
1136fe6060f1SDimitry Andric 
1137fe6060f1SDimitry Andric static long int dfsan_strtol(const char *nptr, char **endptr, int base,
1138fe6060f1SDimitry Andric                              char **tmp_endptr) {
1139fe6060f1SDimitry Andric   assert(tmp_endptr);
1140fe6060f1SDimitry Andric   long int ret = strtol(nptr, tmp_endptr, base);
1141fe6060f1SDimitry Andric   if (endptr)
1142fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1143fe6060f1SDimitry Andric   return ret;
1144fe6060f1SDimitry Andric }
1145fe6060f1SDimitry Andric 
1146fe6060f1SDimitry Andric static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr,
1147fe6060f1SDimitry Andric                                   dfsan_label base_label,
1148fe6060f1SDimitry Andric                                   dfsan_label *ret_label) {
114968d75effSDimitry Andric   if (tmp_endptr > nptr) {
115068d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
115168d75effSDimitry Andric     *ret_label = dfsan_union(
115268d75effSDimitry Andric         base_label,
115368d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
115468d75effSDimitry Andric   } else {
115568d75effSDimitry Andric     *ret_label = 0;
115668d75effSDimitry Andric   }
1157fe6060f1SDimitry Andric }
1158fe6060f1SDimitry Andric 
1159fe6060f1SDimitry Andric static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr,
1160fe6060f1SDimitry Andric                                    dfsan_label base_label,
1161fe6060f1SDimitry Andric                                    dfsan_label *ret_label,
1162fe6060f1SDimitry Andric                                    dfsan_origin base_origin,
1163fe6060f1SDimitry Andric                                    dfsan_origin *ret_origin) {
1164fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1165fe6060f1SDimitry Andric     // When multiple inputs are tainted, we propagate one of its origins.
1166fe6060f1SDimitry Andric     // Because checking if base_label is tainted does not need additional
1167fe6060f1SDimitry Andric     // computation, we prefer to propagating base_origin.
1168fe6060f1SDimitry Andric     *ret_origin = base_label
1169fe6060f1SDimitry Andric                       ? base_origin
1170fe6060f1SDimitry Andric                       : dfsan_read_origin_of_first_taint(
1171fe6060f1SDimitry Andric                             nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1172fe6060f1SDimitry Andric   }
1173fe6060f1SDimitry Andric }
1174fe6060f1SDimitry Andric 
1175fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1176fe6060f1SDimitry Andric long int __dfsw_strtol(const char *nptr, char **endptr, int base,
1177fe6060f1SDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1178fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
1179fe6060f1SDimitry Andric   char *tmp_endptr;
1180fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1181fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
118268d75effSDimitry Andric   return ret;
118368d75effSDimitry Andric }
118468d75effSDimitry Andric 
118568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1186fe6060f1SDimitry Andric long int __dfso_strtol(const char *nptr, char **endptr, int base,
118768d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
1188fe6060f1SDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label,
1189fe6060f1SDimitry Andric                        dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1190fe6060f1SDimitry Andric                        dfsan_origin base_origin, dfsan_origin *ret_origin) {
119168d75effSDimitry Andric   char *tmp_endptr;
1192fe6060f1SDimitry Andric   long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr);
1193fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1194fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1195fe6060f1SDimitry Andric                          ret_origin);
1196fe6060f1SDimitry Andric   return ret;
119768d75effSDimitry Andric }
1198fe6060f1SDimitry Andric 
1199fe6060f1SDimitry Andric static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) {
1200fe6060f1SDimitry Andric   assert(tmp_endptr);
1201fe6060f1SDimitry Andric   double ret = strtod(nptr, tmp_endptr);
1202fe6060f1SDimitry Andric   if (endptr)
1203fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
1204fe6060f1SDimitry Andric   return ret;
1205fe6060f1SDimitry Andric }
1206fe6060f1SDimitry Andric 
1207fe6060f1SDimitry Andric static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr,
1208fe6060f1SDimitry Andric                                dfsan_label *ret_label) {
120968d75effSDimitry Andric   if (tmp_endptr > nptr) {
121068d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
121168d75effSDimitry Andric     *ret_label = dfsan_read_label(
121268d75effSDimitry Andric         nptr,
121368d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
121468d75effSDimitry Andric   } else {
121568d75effSDimitry Andric     *ret_label = 0;
121668d75effSDimitry Andric   }
1217fe6060f1SDimitry Andric }
1218fe6060f1SDimitry Andric 
1219fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1220fe6060f1SDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1221fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label) {
1222fe6060f1SDimitry Andric   char *tmp_endptr;
1223fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1224fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1225fe6060f1SDimitry Andric   return ret;
1226fe6060f1SDimitry Andric }
1227fe6060f1SDimitry Andric 
1228fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1229fe6060f1SDimitry Andric double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label,
1230fe6060f1SDimitry Andric                      dfsan_label endptr_label, dfsan_label *ret_label,
1231fe6060f1SDimitry Andric                      dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1232fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1233fe6060f1SDimitry Andric   char *tmp_endptr;
1234fe6060f1SDimitry Andric   double ret = dfsan_strtod(nptr, endptr, &tmp_endptr);
1235fe6060f1SDimitry Andric   dfsan_strtod_label(nptr, tmp_endptr, ret_label);
1236fe6060f1SDimitry Andric   if (tmp_endptr > nptr) {
1237fe6060f1SDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
1238fe6060f1SDimitry Andric     *ret_origin = dfsan_read_origin_of_first_taint(
1239fe6060f1SDimitry Andric         nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
1240fe6060f1SDimitry Andric   } else {
1241fe6060f1SDimitry Andric     *ret_origin = 0;
1242fe6060f1SDimitry Andric   }
1243fe6060f1SDimitry Andric   return ret;
1244fe6060f1SDimitry Andric }
1245fe6060f1SDimitry Andric 
1246fe6060f1SDimitry Andric static long long int dfsan_strtoll(const char *nptr, char **endptr, int base,
1247fe6060f1SDimitry Andric                                    char **tmp_endptr) {
1248fe6060f1SDimitry Andric   assert(tmp_endptr);
1249fe6060f1SDimitry Andric   long long int ret = strtoll(nptr, tmp_endptr, base);
1250fe6060f1SDimitry Andric   if (endptr)
1251fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
125268d75effSDimitry Andric   return ret;
125368d75effSDimitry Andric }
125468d75effSDimitry Andric 
125568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
125668d75effSDimitry Andric long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
125768d75effSDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
125868d75effSDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label) {
125968d75effSDimitry Andric   char *tmp_endptr;
1260fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1261fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1262fe6060f1SDimitry Andric   return ret;
126368d75effSDimitry Andric }
1264fe6060f1SDimitry Andric 
1265fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1266fe6060f1SDimitry Andric long long int __dfso_strtoll(const char *nptr, char **endptr, int base,
1267fe6060f1SDimitry Andric                              dfsan_label nptr_label, dfsan_label endptr_label,
1268fe6060f1SDimitry Andric                              dfsan_label base_label, dfsan_label *ret_label,
1269fe6060f1SDimitry Andric                              dfsan_origin nptr_origin,
1270fe6060f1SDimitry Andric                              dfsan_origin endptr_origin,
1271fe6060f1SDimitry Andric                              dfsan_origin base_origin,
1272fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1273fe6060f1SDimitry Andric   char *tmp_endptr;
1274fe6060f1SDimitry Andric   long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr);
1275fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1276fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1277fe6060f1SDimitry Andric                          ret_origin);
1278fe6060f1SDimitry Andric   return ret;
127968d75effSDimitry Andric }
1280fe6060f1SDimitry Andric 
1281fe6060f1SDimitry Andric static unsigned long int dfsan_strtoul(const char *nptr, char **endptr,
1282fe6060f1SDimitry Andric                                        int base, char **tmp_endptr) {
1283fe6060f1SDimitry Andric   assert(tmp_endptr);
1284fe6060f1SDimitry Andric   unsigned long int ret = strtoul(nptr, tmp_endptr, base);
1285fe6060f1SDimitry Andric   if (endptr)
1286fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
128768d75effSDimitry Andric   return ret;
128868d75effSDimitry Andric }
128968d75effSDimitry Andric 
129068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
129168d75effSDimitry Andric unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
129268d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
129368d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
129468d75effSDimitry Andric   char *tmp_endptr;
1295fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1296fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1297fe6060f1SDimitry Andric   return ret;
129868d75effSDimitry Andric }
1299fe6060f1SDimitry Andric 
1300fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1301fe6060f1SDimitry Andric unsigned long int __dfso_strtoul(
1302fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1303fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1304fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1305fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1306fe6060f1SDimitry Andric   char *tmp_endptr;
1307fe6060f1SDimitry Andric   unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr);
1308fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1309fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1310fe6060f1SDimitry Andric                          ret_origin);
1311fe6060f1SDimitry Andric   return ret;
131268d75effSDimitry Andric }
1313fe6060f1SDimitry Andric 
1314fe6060f1SDimitry Andric static long long unsigned int dfsan_strtoull(const char *nptr, char **endptr,
1315fe6060f1SDimitry Andric                                              int base, char **tmp_endptr) {
1316fe6060f1SDimitry Andric   assert(tmp_endptr);
1317fe6060f1SDimitry Andric   long long unsigned int ret = strtoull(nptr, tmp_endptr, base);
1318fe6060f1SDimitry Andric   if (endptr)
1319fe6060f1SDimitry Andric     *endptr = *tmp_endptr;
132068d75effSDimitry Andric   return ret;
132168d75effSDimitry Andric }
132268d75effSDimitry Andric 
132368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
132468d75effSDimitry Andric long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
1325e8d8bef9SDimitry Andric                                        int base, dfsan_label nptr_label,
1326e8d8bef9SDimitry Andric                                        dfsan_label endptr_label,
132768d75effSDimitry Andric                                        dfsan_label base_label,
132868d75effSDimitry Andric                                        dfsan_label *ret_label) {
132968d75effSDimitry Andric   char *tmp_endptr;
1330fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1331fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1332fe6060f1SDimitry Andric   return ret;
133368d75effSDimitry Andric }
1334fe6060f1SDimitry Andric 
1335fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1336fe6060f1SDimitry Andric long long unsigned int __dfso_strtoull(
1337fe6060f1SDimitry Andric     const char *nptr, char **endptr, int base, dfsan_label nptr_label,
1338fe6060f1SDimitry Andric     dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label,
1339fe6060f1SDimitry Andric     dfsan_origin nptr_origin, dfsan_origin endptr_origin,
1340fe6060f1SDimitry Andric     dfsan_origin base_origin, dfsan_origin *ret_origin) {
1341fe6060f1SDimitry Andric   char *tmp_endptr;
1342fe6060f1SDimitry Andric   long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr);
1343fe6060f1SDimitry Andric   dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label);
1344fe6060f1SDimitry Andric   dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin,
1345fe6060f1SDimitry Andric                          ret_origin);
134668d75effSDimitry Andric   return ret;
134768d75effSDimitry Andric }
134868d75effSDimitry Andric 
134968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
135068d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
135168d75effSDimitry Andric   time_t ret = time(t);
135268d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
135368d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
135468d75effSDimitry Andric   }
135568d75effSDimitry Andric   *ret_label = 0;
135668d75effSDimitry Andric   return ret;
135768d75effSDimitry Andric }
135868d75effSDimitry Andric 
135968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1360fe6060f1SDimitry Andric time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label,
1361fe6060f1SDimitry Andric                    dfsan_origin t_origin, dfsan_origin *ret_origin) {
1362fe6060f1SDimitry Andric   return __dfsw_time(t, t_label, ret_label);
1363fe6060f1SDimitry Andric }
1364fe6060f1SDimitry Andric 
1365fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
136668d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
136768d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
136868d75effSDimitry Andric                      dfsan_label *ret_label) {
136968d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
137068d75effSDimitry Andric   if (ret == 1) {
137168d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
137268d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
137368d75effSDimitry Andric   }
137468d75effSDimitry Andric   *ret_label = 0;
137568d75effSDimitry Andric   return ret;
137668d75effSDimitry Andric }
137768d75effSDimitry Andric 
137868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1379fe6060f1SDimitry Andric int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
1380fe6060f1SDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
1381fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin af_origin,
1382fe6060f1SDimitry Andric                      dfsan_origin src_origin, dfsan_origin dst_origin,
1383fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1384fe6060f1SDimitry Andric   int ret = inet_pton(af, src, dst);
1385fe6060f1SDimitry Andric   if (ret == 1) {
1386fe6060f1SDimitry Andric     int src_len = strlen(src) + 1;
1387fe6060f1SDimitry Andric     dfsan_set_label_origin(
1388fe6060f1SDimitry Andric         dfsan_read_label(src, src_len),
1389fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(src, src_len), dst,
1390fe6060f1SDimitry Andric         af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
1391fe6060f1SDimitry Andric   }
1392fe6060f1SDimitry Andric   *ret_label = 0;
1393fe6060f1SDimitry Andric   return ret;
1394fe6060f1SDimitry Andric }
1395fe6060f1SDimitry Andric 
1396fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
139768d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
139868d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
139968d75effSDimitry Andric                               dfsan_label *ret_label) {
140068d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
140168d75effSDimitry Andric   if (ret) {
140268d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
140368d75effSDimitry Andric                     sizeof(struct tm));
140468d75effSDimitry Andric     *ret_label = result_label;
140568d75effSDimitry Andric   } else {
140668d75effSDimitry Andric     *ret_label = 0;
140768d75effSDimitry Andric   }
140868d75effSDimitry Andric   return ret;
140968d75effSDimitry Andric }
141068d75effSDimitry Andric 
141168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1412fe6060f1SDimitry Andric struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result,
1413fe6060f1SDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
1414fe6060f1SDimitry Andric                               dfsan_label *ret_label, dfsan_origin timep_origin,
1415fe6060f1SDimitry Andric                               dfsan_origin result_origin,
1416fe6060f1SDimitry Andric                               dfsan_origin *ret_origin) {
1417fe6060f1SDimitry Andric   struct tm *ret = localtime_r(timep, result);
1418fe6060f1SDimitry Andric   if (ret) {
1419fe6060f1SDimitry Andric     dfsan_set_label_origin(
1420fe6060f1SDimitry Andric         dfsan_read_label(timep, sizeof(time_t)),
1421fe6060f1SDimitry Andric         dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result,
1422fe6060f1SDimitry Andric         sizeof(struct tm));
1423fe6060f1SDimitry Andric     *ret_label = result_label;
1424fe6060f1SDimitry Andric     *ret_origin = result_origin;
1425fe6060f1SDimitry Andric   } else {
1426fe6060f1SDimitry Andric     *ret_label = 0;
1427fe6060f1SDimitry Andric   }
1428fe6060f1SDimitry Andric   return ret;
1429fe6060f1SDimitry Andric }
1430fe6060f1SDimitry Andric 
1431fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
143268d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
143368d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
143468d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
143568d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
143668d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
143768d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
143868d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
143968d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
144068d75effSDimitry Andric   if (ret == 0) {
144168d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
144268d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
144368d75effSDimitry Andric   }
144468d75effSDimitry Andric   *ret_label = 0;
144568d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
144668d75effSDimitry Andric   return ret;
144768d75effSDimitry Andric }
144868d75effSDimitry Andric 
144968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1450fe6060f1SDimitry Andric int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen,
1451fe6060f1SDimitry Andric                       struct passwd **result, dfsan_label uid_label,
1452fe6060f1SDimitry Andric                       dfsan_label pwd_label, dfsan_label buf_label,
1453fe6060f1SDimitry Andric                       dfsan_label buflen_label, dfsan_label result_label,
1454fe6060f1SDimitry Andric                       dfsan_label *ret_label, dfsan_origin uid_origin,
1455fe6060f1SDimitry Andric                       dfsan_origin pwd_origin, dfsan_origin buf_origin,
1456fe6060f1SDimitry Andric                       dfsan_origin buflen_origin, dfsan_origin result_origin,
1457fe6060f1SDimitry Andric                       dfsan_origin *ret_origin) {
1458fe6060f1SDimitry Andric   return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label,
1459fe6060f1SDimitry Andric                            buf_label, buflen_label, result_label, ret_label);
1460fe6060f1SDimitry Andric }
1461fe6060f1SDimitry Andric 
1462fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1463e8d8bef9SDimitry Andric int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1464e8d8bef9SDimitry Andric                       int timeout, dfsan_label epfd_label,
1465e8d8bef9SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1466e8d8bef9SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label) {
1467e8d8bef9SDimitry Andric   int ret = epoll_wait(epfd, events, maxevents, timeout);
1468e8d8bef9SDimitry Andric   if (ret > 0)
1469e8d8bef9SDimitry Andric     dfsan_set_label(0, events, ret * sizeof(*events));
1470e8d8bef9SDimitry Andric   *ret_label = 0;
1471e8d8bef9SDimitry Andric   return ret;
1472e8d8bef9SDimitry Andric }
1473e8d8bef9SDimitry Andric 
1474e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1475fe6060f1SDimitry Andric int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents,
1476fe6060f1SDimitry Andric                       int timeout, dfsan_label epfd_label,
1477fe6060f1SDimitry Andric                       dfsan_label events_label, dfsan_label maxevents_label,
1478fe6060f1SDimitry Andric                       dfsan_label timeout_label, dfsan_label *ret_label,
1479fe6060f1SDimitry Andric                       dfsan_origin epfd_origin, dfsan_origin events_origin,
1480fe6060f1SDimitry Andric                       dfsan_origin maxevents_origin,
1481fe6060f1SDimitry Andric                       dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1482fe6060f1SDimitry Andric   return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label,
1483fe6060f1SDimitry Andric                            events_label, maxevents_label, timeout_label,
1484fe6060f1SDimitry Andric                            ret_label);
1485fe6060f1SDimitry Andric }
1486fe6060f1SDimitry Andric 
1487fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
148868d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
148968d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
149068d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
149168d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
149268d75effSDimitry Andric   if (ret >= 0) {
149368d75effSDimitry Andric     for (; nfds > 0; --nfds) {
149468d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
149568d75effSDimitry Andric     }
149668d75effSDimitry Andric   }
149768d75effSDimitry Andric   *ret_label = 0;
149868d75effSDimitry Andric   return ret;
149968d75effSDimitry Andric }
150068d75effSDimitry Andric 
150168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1502fe6060f1SDimitry Andric int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout,
1503fe6060f1SDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
1504fe6060f1SDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label,
1505fe6060f1SDimitry Andric                 dfsan_origin dfs_origin, dfsan_origin nfds_origin,
1506fe6060f1SDimitry Andric                 dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1507fe6060f1SDimitry Andric   return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label,
1508fe6060f1SDimitry Andric                      ret_label);
1509fe6060f1SDimitry Andric }
1510fe6060f1SDimitry Andric 
1511fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
151268d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
151368d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
151468d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
151568d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
151668d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
151768d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
151868d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
151968d75effSDimitry Andric   // undefined.
152068d75effSDimitry Andric   if (readfds) {
152168d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
152268d75effSDimitry Andric   }
152368d75effSDimitry Andric   if (writefds) {
152468d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
152568d75effSDimitry Andric   }
152668d75effSDimitry Andric   if (exceptfds) {
152768d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
152868d75effSDimitry Andric   }
152968d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
153068d75effSDimitry Andric   *ret_label = 0;
153168d75effSDimitry Andric   return ret;
153268d75effSDimitry Andric }
153368d75effSDimitry Andric 
153468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1535fe6060f1SDimitry Andric int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds,
1536fe6060f1SDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
1537fe6060f1SDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
1538fe6060f1SDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
1539fe6060f1SDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label,
1540fe6060f1SDimitry Andric                   dfsan_origin nfds_origin, dfsan_origin readfds_origin,
1541fe6060f1SDimitry Andric                   dfsan_origin writefds_origin, dfsan_origin exceptfds_origin,
1542fe6060f1SDimitry Andric                   dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1543fe6060f1SDimitry Andric   return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label,
1544fe6060f1SDimitry Andric                        readfds_label, writefds_label, exceptfds_label,
1545fe6060f1SDimitry Andric                        timeout_label, ret_label);
1546fe6060f1SDimitry Andric }
1547fe6060f1SDimitry Andric 
1548fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
154968d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
155068d75effSDimitry Andric                              dfsan_label pid_label,
155168d75effSDimitry Andric                              dfsan_label cpusetsize_label,
155268d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
155368d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
155468d75effSDimitry Andric   if (ret == 0) {
155568d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
155668d75effSDimitry Andric   }
155768d75effSDimitry Andric   *ret_label = 0;
155868d75effSDimitry Andric   return ret;
155968d75effSDimitry Andric }
156068d75effSDimitry Andric 
156168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1562fe6060f1SDimitry Andric int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
1563fe6060f1SDimitry Andric                              dfsan_label pid_label,
1564fe6060f1SDimitry Andric                              dfsan_label cpusetsize_label,
1565fe6060f1SDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label,
1566fe6060f1SDimitry Andric                              dfsan_origin pid_origin,
1567fe6060f1SDimitry Andric                              dfsan_origin cpusetsize_origin,
1568fe6060f1SDimitry Andric                              dfsan_origin mask_origin,
1569fe6060f1SDimitry Andric                              dfsan_origin *ret_origin) {
1570fe6060f1SDimitry Andric   return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label,
1571fe6060f1SDimitry Andric                                   cpusetsize_label, mask_label, ret_label);
1572fe6060f1SDimitry Andric }
1573fe6060f1SDimitry Andric 
1574fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
157568d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
157668d75effSDimitry Andric                        dfsan_label *ret_label) {
157768d75effSDimitry Andric   int ret = sigemptyset(set);
157868d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
1579fe6060f1SDimitry Andric   *ret_label = 0;
158068d75effSDimitry Andric   return ret;
158168d75effSDimitry Andric }
158268d75effSDimitry Andric 
158368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1584fe6060f1SDimitry Andric int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
1585fe6060f1SDimitry Andric                        dfsan_label *ret_label, dfsan_origin set_origin,
1586fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1587fe6060f1SDimitry Andric   return __dfsw_sigemptyset(set, set_label, ret_label);
1588fe6060f1SDimitry Andric }
1589fe6060f1SDimitry Andric 
1590fe6060f1SDimitry Andric class SignalHandlerScope {
1591fe6060f1SDimitry Andric  public:
1592fe6060f1SDimitry Andric   SignalHandlerScope() {
1593fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1594fe6060f1SDimitry Andric       t->EnterSignalHandler();
1595fe6060f1SDimitry Andric   }
1596fe6060f1SDimitry Andric   ~SignalHandlerScope() {
1597fe6060f1SDimitry Andric     if (DFsanThread *t = GetCurrentThread())
1598fe6060f1SDimitry Andric       t->LeaveSignalHandler();
1599fe6060f1SDimitry Andric   }
1600fe6060f1SDimitry Andric };
1601fe6060f1SDimitry Andric 
1602fe6060f1SDimitry Andric // Clear DFSan runtime TLS state at the end of a scope.
1603fe6060f1SDimitry Andric //
1604fe6060f1SDimitry Andric // Implementation must be async-signal-safe and use small data size, because
1605fe6060f1SDimitry Andric // instances of this class may live on the signal handler stack.
1606fe6060f1SDimitry Andric //
1607fe6060f1SDimitry Andric // DFSan uses TLS to pass metadata of arguments and return values. When an
1608fe6060f1SDimitry Andric // instrumented function accesses the TLS, if a signal callback happens, and the
1609fe6060f1SDimitry Andric // callback calls other instrumented functions with updating the same TLS, the
1610fe6060f1SDimitry Andric // TLS is in an inconsistent state after the callback ends. This may cause
1611fe6060f1SDimitry Andric // either under-tainting or over-tainting.
1612fe6060f1SDimitry Andric //
1613fe6060f1SDimitry Andric // The current implementation simply resets TLS at restore. This prevents from
1614fe6060f1SDimitry Andric // over-tainting. Although under-tainting may still happen, a taint flow can be
1615fe6060f1SDimitry Andric // found eventually if we run a DFSan-instrumented program multiple times. The
1616fe6060f1SDimitry Andric // alternative option is saving the entire TLS. However the TLS storage takes
1617fe6060f1SDimitry Andric // 2k bytes, and signal calls could be nested. So it does not seem worth.
1618fe6060f1SDimitry Andric class ScopedClearThreadLocalState {
1619fe6060f1SDimitry Andric  public:
1620fe6060f1SDimitry Andric   ScopedClearThreadLocalState() {}
1621fe6060f1SDimitry Andric   ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); }
1622fe6060f1SDimitry Andric };
1623fe6060f1SDimitry Andric 
1624fe6060f1SDimitry Andric // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls.
1625fe6060f1SDimitry Andric const int kMaxSignals = 1024;
1626fe6060f1SDimitry Andric static atomic_uintptr_t sigactions[kMaxSignals];
1627fe6060f1SDimitry Andric 
1628fe6060f1SDimitry Andric static void SignalHandler(int signo) {
1629fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1630fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1631fe6060f1SDimitry Andric 
1632fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. This is why DFSan
1633fe6060f1SDimitry Andric   // instrumentation generates a trampoline function to each function pointer,
1634fe6060f1SDimitry Andric   // and uses the trampoline to clear shadows. However sigaction does not use
1635fe6060f1SDimitry Andric   // a function pointer directly, so we have to do this manually.
1636fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, sizeof(dfsan_label));
1637fe6060f1SDimitry Andric 
1638fe6060f1SDimitry Andric   typedef void (*signal_cb)(int x);
1639fe6060f1SDimitry Andric   signal_cb cb =
1640fe6060f1SDimitry Andric       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1641fe6060f1SDimitry Andric   cb(signo);
1642fe6060f1SDimitry Andric }
1643fe6060f1SDimitry Andric 
1644fe6060f1SDimitry Andric static void SignalAction(int signo, siginfo_t *si, void *uc) {
1645fe6060f1SDimitry Andric   SignalHandlerScope signal_handler_scope;
1646fe6060f1SDimitry Andric   ScopedClearThreadLocalState scoped_clear_tls;
1647fe6060f1SDimitry Andric 
1648fe6060f1SDimitry Andric   // Clear shadows for all inputs provided by system. Similar to SignalHandler.
1649fe6060f1SDimitry Andric   dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label));
1650fe6060f1SDimitry Andric   dfsan_set_label(0, si, sizeof(*si));
1651fe6060f1SDimitry Andric   dfsan_set_label(0, uc, sizeof(ucontext_t));
1652fe6060f1SDimitry Andric 
1653fe6060f1SDimitry Andric   typedef void (*sigaction_cb)(int, siginfo_t *, void *);
1654fe6060f1SDimitry Andric   sigaction_cb cb =
1655fe6060f1SDimitry Andric       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
1656fe6060f1SDimitry Andric   cb(signo, si, uc);
1657fe6060f1SDimitry Andric }
1658fe6060f1SDimitry Andric 
1659fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
166068d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
166168d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
166268d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
166368d75effSDimitry Andric                      dfsan_label *ret_label) {
1664fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1665fe6060f1SDimitry Andric   SignalSpinLocker lock;
1666fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1667fe6060f1SDimitry Andric   struct sigaction new_act;
1668fe6060f1SDimitry Andric   struct sigaction *pnew_act = act ? &new_act : nullptr;
1669fe6060f1SDimitry Andric   if (act) {
1670fe6060f1SDimitry Andric     internal_memcpy(pnew_act, act, sizeof(struct sigaction));
1671fe6060f1SDimitry Andric     if (pnew_act->sa_flags & SA_SIGINFO) {
1672fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_sigaction);
1673fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1674fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1675fe6060f1SDimitry Andric         pnew_act->sa_sigaction = SignalAction;
1676fe6060f1SDimitry Andric       }
1677fe6060f1SDimitry Andric     } else {
1678fe6060f1SDimitry Andric       uptr cb = (uptr)(pnew_act->sa_handler);
1679fe6060f1SDimitry Andric       if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) {
1680fe6060f1SDimitry Andric         atomic_store(&sigactions[signum], cb, memory_order_relaxed);
1681fe6060f1SDimitry Andric         pnew_act->sa_handler = SignalHandler;
1682fe6060f1SDimitry Andric       }
1683fe6060f1SDimitry Andric     }
1684fe6060f1SDimitry Andric   }
1685fe6060f1SDimitry Andric 
1686fe6060f1SDimitry Andric   int ret = sigaction(signum, pnew_act, oldact);
1687fe6060f1SDimitry Andric 
1688fe6060f1SDimitry Andric   if (ret == 0 && oldact) {
1689fe6060f1SDimitry Andric     if (oldact->sa_flags & SA_SIGINFO) {
1690fe6060f1SDimitry Andric       if (oldact->sa_sigaction == SignalAction)
1691fe6060f1SDimitry Andric         oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb;
1692fe6060f1SDimitry Andric     } else {
1693fe6060f1SDimitry Andric       if (oldact->sa_handler == SignalHandler)
1694fe6060f1SDimitry Andric         oldact->sa_handler = (decltype(oldact->sa_handler))old_cb;
1695fe6060f1SDimitry Andric     }
1696fe6060f1SDimitry Andric   }
1697fe6060f1SDimitry Andric 
169868d75effSDimitry Andric   if (oldact) {
169968d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
170068d75effSDimitry Andric   }
170168d75effSDimitry Andric   *ret_label = 0;
170268d75effSDimitry Andric   return ret;
170368d75effSDimitry Andric }
170468d75effSDimitry Andric 
170568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1706fe6060f1SDimitry Andric int __dfso_sigaction(int signum, const struct sigaction *act,
1707fe6060f1SDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
1708fe6060f1SDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
1709fe6060f1SDimitry Andric                      dfsan_label *ret_label, dfsan_origin signum_origin,
1710fe6060f1SDimitry Andric                      dfsan_origin act_origin, dfsan_origin oldact_origin,
1711fe6060f1SDimitry Andric                      dfsan_origin *ret_origin) {
1712fe6060f1SDimitry Andric   return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
1713fe6060f1SDimitry Andric                           oldact_label, ret_label);
1714fe6060f1SDimitry Andric }
1715fe6060f1SDimitry Andric 
1716fe6060f1SDimitry Andric static sighandler_t dfsan_signal(int signum, sighandler_t handler,
1717fe6060f1SDimitry Andric                                  dfsan_label *ret_label) {
1718fe6060f1SDimitry Andric   CHECK_LT(signum, kMaxSignals);
1719fe6060f1SDimitry Andric   SignalSpinLocker lock;
1720fe6060f1SDimitry Andric   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
1721fe6060f1SDimitry Andric   if (handler != SIG_IGN && handler != SIG_DFL) {
1722fe6060f1SDimitry Andric     atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed);
1723fe6060f1SDimitry Andric     handler = &SignalHandler;
1724fe6060f1SDimitry Andric   }
1725fe6060f1SDimitry Andric 
1726fe6060f1SDimitry Andric   sighandler_t ret = signal(signum, handler);
1727fe6060f1SDimitry Andric 
1728fe6060f1SDimitry Andric   if (ret == SignalHandler)
1729fe6060f1SDimitry Andric     ret = (sighandler_t)old_cb;
1730fe6060f1SDimitry Andric 
1731fe6060f1SDimitry Andric   *ret_label = 0;
1732fe6060f1SDimitry Andric   return ret;
1733fe6060f1SDimitry Andric }
1734fe6060f1SDimitry Andric 
1735fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1736fe6060f1SDimitry Andric sighandler_t __dfsw_signal(int signum,
1737fe6060f1SDimitry Andric                            void *(*handler_trampoline)(void *, int, dfsan_label,
1738fe6060f1SDimitry Andric                                                        dfsan_label *),
1739fe6060f1SDimitry Andric                            sighandler_t handler, dfsan_label signum_label,
1740fe6060f1SDimitry Andric                            dfsan_label handler_label, dfsan_label *ret_label) {
1741fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1742fe6060f1SDimitry Andric }
1743fe6060f1SDimitry Andric 
1744fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1745fe6060f1SDimitry Andric sighandler_t __dfso_signal(
1746fe6060f1SDimitry Andric     int signum,
1747fe6060f1SDimitry Andric     void *(*handler_trampoline)(void *, int, dfsan_label, dfsan_label *,
1748fe6060f1SDimitry Andric                                 dfsan_origin, dfsan_origin *),
1749fe6060f1SDimitry Andric     sighandler_t handler, dfsan_label signum_label, dfsan_label handler_label,
1750fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin signum_origin,
1751fe6060f1SDimitry Andric     dfsan_origin handler_origin, dfsan_origin *ret_origin) {
1752fe6060f1SDimitry Andric   return dfsan_signal(signum, handler, ret_label);
1753fe6060f1SDimitry Andric }
1754fe6060f1SDimitry Andric 
1755fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1756e8d8bef9SDimitry Andric int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1757e8d8bef9SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label) {
1758e8d8bef9SDimitry Andric   int ret = sigaltstack(ss, old_ss);
1759e8d8bef9SDimitry Andric   if (ret != -1 && old_ss)
1760e8d8bef9SDimitry Andric     dfsan_set_label(0, old_ss, sizeof(*old_ss));
1761e8d8bef9SDimitry Andric   *ret_label = 0;
1762e8d8bef9SDimitry Andric   return ret;
1763e8d8bef9SDimitry Andric }
1764e8d8bef9SDimitry Andric 
1765e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1766fe6060f1SDimitry Andric int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
1767fe6060f1SDimitry Andric                        dfsan_label old_ss_label, dfsan_label *ret_label,
1768fe6060f1SDimitry Andric                        dfsan_origin ss_origin, dfsan_origin old_ss_origin,
1769fe6060f1SDimitry Andric                        dfsan_origin *ret_origin) {
1770fe6060f1SDimitry Andric   return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
1771fe6060f1SDimitry Andric }
1772fe6060f1SDimitry Andric 
1773fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
177468d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
177568d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
177668d75effSDimitry Andric                         dfsan_label *ret_label) {
177768d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
177868d75effSDimitry Andric   if (tv) {
177968d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
178068d75effSDimitry Andric   }
178168d75effSDimitry Andric   if (tz) {
178268d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
178368d75effSDimitry Andric   }
178468d75effSDimitry Andric   *ret_label = 0;
178568d75effSDimitry Andric   return ret;
178668d75effSDimitry Andric }
178768d75effSDimitry Andric 
1788fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1789fe6060f1SDimitry Andric int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz,
1790fe6060f1SDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
1791fe6060f1SDimitry Andric                         dfsan_label *ret_label, dfsan_origin tv_origin,
1792fe6060f1SDimitry Andric                         dfsan_origin tz_origin, dfsan_origin *ret_origin) {
1793fe6060f1SDimitry Andric   return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label);
1794fe6060f1SDimitry Andric }
1795fe6060f1SDimitry Andric 
179668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
179768d75effSDimitry Andric                                                   dfsan_label s_label,
179868d75effSDimitry Andric                                                   dfsan_label c_label,
179968d75effSDimitry Andric                                                   dfsan_label n_label,
180068d75effSDimitry Andric                                                   dfsan_label *ret_label) {
180168d75effSDimitry Andric   void *ret = memchr(s, c, n);
180268d75effSDimitry Andric   if (flags().strict_data_dependencies) {
180368d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
180468d75effSDimitry Andric   } else {
180568d75effSDimitry Andric     size_t len =
180668d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
180768d75effSDimitry Andric             : n;
180868d75effSDimitry Andric     *ret_label =
180968d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
181068d75effSDimitry Andric   }
181168d75effSDimitry Andric   return ret;
181268d75effSDimitry Andric }
181368d75effSDimitry Andric 
1814fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr(
1815fe6060f1SDimitry Andric     void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label,
1816fe6060f1SDimitry Andric     dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin,
1817fe6060f1SDimitry Andric     dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) {
1818fe6060f1SDimitry Andric   void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label);
1819fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1820fe6060f1SDimitry Andric     if (ret)
1821fe6060f1SDimitry Andric       *ret_origin = s_origin;
1822fe6060f1SDimitry Andric   } else {
1823fe6060f1SDimitry Andric     size_t len =
1824fe6060f1SDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
1825fe6060f1SDimitry Andric             : n;
1826fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, len);
1827fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1828fe6060f1SDimitry Andric   }
1829fe6060f1SDimitry Andric   return ret;
1830fe6060f1SDimitry Andric }
1831fe6060f1SDimitry Andric 
183268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
183368d75effSDimitry Andric                                                    dfsan_label s_label,
183468d75effSDimitry Andric                                                    dfsan_label c_label,
183568d75effSDimitry Andric                                                    dfsan_label *ret_label) {
183668d75effSDimitry Andric   char *ret = strrchr(s, c);
183768d75effSDimitry Andric   if (flags().strict_data_dependencies) {
183868d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
183968d75effSDimitry Andric   } else {
184068d75effSDimitry Andric     *ret_label =
184168d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
184268d75effSDimitry Andric                     dfsan_union(s_label, c_label));
184368d75effSDimitry Andric   }
184468d75effSDimitry Andric 
184568d75effSDimitry Andric   return ret;
184668d75effSDimitry Andric }
184768d75effSDimitry Andric 
1848fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr(
1849fe6060f1SDimitry Andric     char *s, int c, dfsan_label s_label, dfsan_label c_label,
1850fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin,
1851fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
1852fe6060f1SDimitry Andric   char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label);
1853fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1854fe6060f1SDimitry Andric     if (ret)
1855fe6060f1SDimitry Andric       *ret_origin = s_origin;
1856fe6060f1SDimitry Andric   } else {
1857fe6060f1SDimitry Andric     size_t s_len = strlen(s) + 1;
1858fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len);
1859fe6060f1SDimitry Andric     *ret_origin = o ? o : (s_label ? s_origin : c_origin);
1860fe6060f1SDimitry Andric   }
1861fe6060f1SDimitry Andric 
1862fe6060f1SDimitry Andric   return ret;
1863fe6060f1SDimitry Andric }
1864fe6060f1SDimitry Andric 
186568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
186668d75effSDimitry Andric                                                   dfsan_label haystack_label,
186768d75effSDimitry Andric                                                   dfsan_label needle_label,
186868d75effSDimitry Andric                                                   dfsan_label *ret_label) {
186968d75effSDimitry Andric   char *ret = strstr(haystack, needle);
187068d75effSDimitry Andric   if (flags().strict_data_dependencies) {
187168d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
187268d75effSDimitry Andric   } else {
187368d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
187468d75effSDimitry Andric     *ret_label =
187568d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
187668d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
187768d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
187868d75effSDimitry Andric   }
187968d75effSDimitry Andric 
188068d75effSDimitry Andric   return ret;
188168d75effSDimitry Andric }
188268d75effSDimitry Andric 
1883fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle,
1884fe6060f1SDimitry Andric                                                   dfsan_label haystack_label,
1885fe6060f1SDimitry Andric                                                   dfsan_label needle_label,
1886fe6060f1SDimitry Andric                                                   dfsan_label *ret_label,
1887fe6060f1SDimitry Andric                                                   dfsan_origin haystack_origin,
1888fe6060f1SDimitry Andric                                                   dfsan_origin needle_origin,
1889fe6060f1SDimitry Andric                                                   dfsan_origin *ret_origin) {
1890fe6060f1SDimitry Andric   char *ret =
1891fe6060f1SDimitry Andric       __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label);
1892fe6060f1SDimitry Andric   if (flags().strict_data_dependencies) {
1893fe6060f1SDimitry Andric     if (ret)
1894fe6060f1SDimitry Andric       *ret_origin = haystack_origin;
1895fe6060f1SDimitry Andric   } else {
1896fe6060f1SDimitry Andric     size_t needle_len = strlen(needle);
1897fe6060f1SDimitry Andric     size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1;
1898fe6060f1SDimitry Andric     dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len);
1899fe6060f1SDimitry Andric     if (o) {
1900fe6060f1SDimitry Andric       *ret_origin = o;
1901fe6060f1SDimitry Andric     } else {
1902fe6060f1SDimitry Andric       o = dfsan_read_origin_of_first_taint(needle, needle_len + 1);
1903fe6060f1SDimitry Andric       *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin);
1904fe6060f1SDimitry Andric     }
1905fe6060f1SDimitry Andric   }
1906fe6060f1SDimitry Andric 
1907fe6060f1SDimitry Andric   return ret;
1908fe6060f1SDimitry Andric }
1909fe6060f1SDimitry Andric 
191068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
191168d75effSDimitry Andric                                                    struct timespec *rem,
191268d75effSDimitry Andric                                                    dfsan_label req_label,
191368d75effSDimitry Andric                                                    dfsan_label rem_label,
191468d75effSDimitry Andric                                                    dfsan_label *ret_label) {
191568d75effSDimitry Andric   int ret = nanosleep(req, rem);
191668d75effSDimitry Andric   *ret_label = 0;
191768d75effSDimitry Andric   if (ret == -1) {
191868d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
191968d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
192068d75effSDimitry Andric   }
192168d75effSDimitry Andric   return ret;
192268d75effSDimitry Andric }
192368d75effSDimitry Andric 
1924fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep(
1925fe6060f1SDimitry Andric     const struct timespec *req, struct timespec *rem, dfsan_label req_label,
1926fe6060f1SDimitry Andric     dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin,
1927fe6060f1SDimitry Andric     dfsan_origin rem_origin, dfsan_origin *ret_origin) {
1928fe6060f1SDimitry Andric   return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label);
1929fe6060f1SDimitry Andric }
1930fe6060f1SDimitry Andric 
1931e8d8bef9SDimitry Andric static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) {
1932e8d8bef9SDimitry Andric   dfsan_set_label(0, msg, sizeof(*msg));
1933e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_name, msg->msg_namelen);
1934e8d8bef9SDimitry Andric   dfsan_set_label(0, msg->msg_control, msg->msg_controllen);
1935e8d8bef9SDimitry Andric   for (size_t i = 0; bytes_written > 0; ++i) {
1936e8d8bef9SDimitry Andric     assert(i < msg->msg_iovlen);
1937e8d8bef9SDimitry Andric     struct iovec *iov = &msg->msg_iov[i];
1938e8d8bef9SDimitry Andric     size_t iov_written =
1939e8d8bef9SDimitry Andric         bytes_written < iov->iov_len ? bytes_written : iov->iov_len;
1940e8d8bef9SDimitry Andric     dfsan_set_label(0, iov->iov_base, iov_written);
1941e8d8bef9SDimitry Andric     bytes_written -= iov_written;
1942e8d8bef9SDimitry Andric   }
1943e8d8bef9SDimitry Andric }
1944e8d8bef9SDimitry Andric 
1945e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg(
1946e8d8bef9SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1947e8d8bef9SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1948e8d8bef9SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1949e8d8bef9SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label) {
1950e8d8bef9SDimitry Andric   int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout);
1951e8d8bef9SDimitry Andric   for (int i = 0; i < ret; ++i) {
1952e8d8bef9SDimitry Andric     dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len));
1953e8d8bef9SDimitry Andric     clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr);
1954e8d8bef9SDimitry Andric   }
1955e8d8bef9SDimitry Andric   *ret_label = 0;
1956e8d8bef9SDimitry Andric   return ret;
1957e8d8bef9SDimitry Andric }
1958e8d8bef9SDimitry Andric 
1959fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg(
1960fe6060f1SDimitry Andric     int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags,
1961fe6060f1SDimitry Andric     struct timespec *timeout, dfsan_label sockfd_label,
1962fe6060f1SDimitry Andric     dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label,
1963fe6060f1SDimitry Andric     dfsan_label timeout_label, dfsan_label *ret_label,
1964fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msgvec_origin,
1965fe6060f1SDimitry Andric     dfsan_origin vlen_origin, dfsan_origin flags_origin,
1966fe6060f1SDimitry Andric     dfsan_origin timeout_origin, dfsan_origin *ret_origin) {
1967fe6060f1SDimitry Andric   return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label,
1968fe6060f1SDimitry Andric                          msgvec_label, vlen_label, flags_label, timeout_label,
1969fe6060f1SDimitry Andric                          ret_label);
1970fe6060f1SDimitry Andric }
1971fe6060f1SDimitry Andric 
1972e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg(
1973e8d8bef9SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1974e8d8bef9SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) {
1975e8d8bef9SDimitry Andric   ssize_t ret = recvmsg(sockfd, msg, flags);
1976e8d8bef9SDimitry Andric   if (ret >= 0)
1977e8d8bef9SDimitry Andric     clear_msghdr_labels(ret, msg);
1978e8d8bef9SDimitry Andric   *ret_label = 0;
1979e8d8bef9SDimitry Andric   return ret;
1980e8d8bef9SDimitry Andric }
1981e8d8bef9SDimitry Andric 
1982fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg(
1983fe6060f1SDimitry Andric     int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label,
1984fe6060f1SDimitry Andric     dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label,
1985fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin msg_origin,
1986fe6060f1SDimitry Andric     dfsan_origin flags_origin, dfsan_origin *ret_origin) {
1987fe6060f1SDimitry Andric   return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label,
1988fe6060f1SDimitry Andric                         flags_label, ret_label);
1989fe6060f1SDimitry Andric }
1990fe6060f1SDimitry Andric 
199168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
199268d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
199368d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
199468d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
199568d75effSDimitry Andric                   dfsan_label *ret_label) {
199668d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
199768d75effSDimitry Andric   *ret_label = 0;
199868d75effSDimitry Andric   if (ret == 0) {
199968d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
200068d75effSDimitry Andric   }
200168d75effSDimitry Andric   return ret;
200268d75effSDimitry Andric }
200368d75effSDimitry Andric 
2004fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair(
2005fe6060f1SDimitry Andric     int domain, int type, int protocol, int sv[2], dfsan_label domain_label,
2006fe6060f1SDimitry Andric     dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label,
2007fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin domain_origin,
2008fe6060f1SDimitry Andric     dfsan_origin type_origin, dfsan_origin protocol_origin,
2009fe6060f1SDimitry Andric     dfsan_origin sv_origin, dfsan_origin *ret_origin) {
2010fe6060f1SDimitry Andric   return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label,
2011fe6060f1SDimitry Andric                            protocol_label, sv_label, ret_label);
2012fe6060f1SDimitry Andric }
2013fe6060f1SDimitry Andric 
2014e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt(
2015e8d8bef9SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2016e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2017e8d8bef9SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2018e8d8bef9SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label) {
2019e8d8bef9SDimitry Andric   int ret = getsockopt(sockfd, level, optname, optval, optlen);
2020e8d8bef9SDimitry Andric   if (ret != -1 && optval && optlen) {
2021e8d8bef9SDimitry Andric     dfsan_set_label(0, optlen, sizeof(*optlen));
2022e8d8bef9SDimitry Andric     dfsan_set_label(0, optval, *optlen);
2023e8d8bef9SDimitry Andric   }
2024e8d8bef9SDimitry Andric   *ret_label = 0;
2025e8d8bef9SDimitry Andric   return ret;
2026e8d8bef9SDimitry Andric }
2027e8d8bef9SDimitry Andric 
2028fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt(
2029fe6060f1SDimitry Andric     int sockfd, int level, int optname, void *optval, socklen_t *optlen,
2030fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label level_label,
2031fe6060f1SDimitry Andric     dfsan_label optname_label, dfsan_label optval_label,
2032fe6060f1SDimitry Andric     dfsan_label optlen_label, dfsan_label *ret_label,
2033fe6060f1SDimitry Andric     dfsan_origin sockfd_origin, dfsan_origin level_origin,
2034fe6060f1SDimitry Andric     dfsan_origin optname_origin, dfsan_origin optval_origin,
2035fe6060f1SDimitry Andric     dfsan_origin optlen_origin, dfsan_origin *ret_origin) {
2036fe6060f1SDimitry Andric   return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label,
2037fe6060f1SDimitry Andric                            level_label, optname_label, optval_label,
2038fe6060f1SDimitry Andric                            optlen_label, ret_label);
2039fe6060f1SDimitry Andric }
2040fe6060f1SDimitry Andric 
2041e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname(
2042e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2043e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2044e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2045e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2046e8d8bef9SDimitry Andric   int ret = getsockname(sockfd, addr, addrlen);
2047e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2048e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2049e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2050e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2051e8d8bef9SDimitry Andric   }
2052e8d8bef9SDimitry Andric   *ret_label = 0;
2053e8d8bef9SDimitry Andric   return ret;
2054e8d8bef9SDimitry Andric }
2055e8d8bef9SDimitry Andric 
2056fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname(
2057fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2058fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2059fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2060fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2061fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2062fe6060f1SDimitry Andric   return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label,
2063fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2064fe6060f1SDimitry Andric }
2065fe6060f1SDimitry Andric 
2066e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername(
2067e8d8bef9SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2068e8d8bef9SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2069e8d8bef9SDimitry Andric     dfsan_label *ret_label) {
2070e8d8bef9SDimitry Andric   socklen_t origlen = addrlen ? *addrlen : 0;
2071e8d8bef9SDimitry Andric   int ret = getpeername(sockfd, addr, addrlen);
2072e8d8bef9SDimitry Andric   if (ret != -1 && addr && addrlen) {
2073e8d8bef9SDimitry Andric     socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen;
2074e8d8bef9SDimitry Andric     dfsan_set_label(0, addrlen, sizeof(*addrlen));
2075e8d8bef9SDimitry Andric     dfsan_set_label(0, addr, written_bytes);
2076e8d8bef9SDimitry Andric   }
2077e8d8bef9SDimitry Andric   *ret_label = 0;
2078e8d8bef9SDimitry Andric   return ret;
2079e8d8bef9SDimitry Andric }
2080e8d8bef9SDimitry Andric 
2081fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername(
2082fe6060f1SDimitry Andric     int sockfd, struct sockaddr *addr, socklen_t *addrlen,
2083fe6060f1SDimitry Andric     dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label,
2084fe6060f1SDimitry Andric     dfsan_label *ret_label, dfsan_origin sockfd_origin,
2085fe6060f1SDimitry Andric     dfsan_origin addr_origin, dfsan_origin addrlen_origin,
2086fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2087fe6060f1SDimitry Andric   return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label,
2088fe6060f1SDimitry Andric                             addrlen_label, ret_label);
2089fe6060f1SDimitry Andric }
2090fe6060f1SDimitry Andric 
209168d75effSDimitry Andric // Type of the trampoline function passed to the custom version of
209268d75effSDimitry Andric // dfsan_set_write_callback.
209368d75effSDimitry Andric typedef void (*write_trampoline_t)(
209468d75effSDimitry Andric     void *callback,
209568d75effSDimitry Andric     int fd, const void *buf, ssize_t count,
209668d75effSDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
209768d75effSDimitry Andric 
2098fe6060f1SDimitry Andric typedef void (*write_origin_trampoline_t)(
2099fe6060f1SDimitry Andric     void *callback, int fd, const void *buf, ssize_t count,
2100fe6060f1SDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
2101fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin);
2102fe6060f1SDimitry Andric 
210368d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
210468d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
210568d75effSDimitry Andric static struct {
210668d75effSDimitry Andric   write_trampoline_t write_callback_trampoline = nullptr;
210768d75effSDimitry Andric   void *write_callback = nullptr;
210868d75effSDimitry Andric } write_callback_info;
210968d75effSDimitry Andric 
2110fe6060f1SDimitry Andric static struct {
2111fe6060f1SDimitry Andric   write_origin_trampoline_t write_callback_trampoline = nullptr;
2112fe6060f1SDimitry Andric   void *write_callback = nullptr;
2113fe6060f1SDimitry Andric } write_origin_callback_info;
2114fe6060f1SDimitry Andric 
211568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void
211668d75effSDimitry Andric __dfsw_dfsan_set_write_callback(
211768d75effSDimitry Andric     write_trampoline_t write_callback_trampoline,
211868d75effSDimitry Andric     void *write_callback,
211968d75effSDimitry Andric     dfsan_label write_callback_label,
212068d75effSDimitry Andric     dfsan_label *ret_label) {
212168d75effSDimitry Andric   write_callback_info.write_callback_trampoline = write_callback_trampoline;
212268d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
212368d75effSDimitry Andric }
212468d75effSDimitry Andric 
2125fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
2126fe6060f1SDimitry Andric     write_origin_trampoline_t write_callback_trampoline, void *write_callback,
2127fe6060f1SDimitry Andric     dfsan_label write_callback_label, dfsan_label *ret_label,
2128fe6060f1SDimitry Andric     dfsan_origin write_callback_origin, dfsan_origin *ret_origin) {
2129fe6060f1SDimitry Andric   write_origin_callback_info.write_callback_trampoline =
2130fe6060f1SDimitry Andric       write_callback_trampoline;
2131fe6060f1SDimitry Andric   write_origin_callback_info.write_callback = write_callback;
2132fe6060f1SDimitry Andric }
2133fe6060f1SDimitry Andric 
213468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
213568d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
213668d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
213768d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
213868d75effSDimitry Andric   if (write_callback_info.write_callback) {
213968d75effSDimitry Andric     write_callback_info.write_callback_trampoline(
214068d75effSDimitry Andric         write_callback_info.write_callback,
214168d75effSDimitry Andric         fd, buf, count,
214268d75effSDimitry Andric         fd_label, buf_label, count_label);
214368d75effSDimitry Andric   }
214468d75effSDimitry Andric 
214568d75effSDimitry Andric   *ret_label = 0;
214668d75effSDimitry Andric   return write(fd, buf, count);
214768d75effSDimitry Andric }
2148fe6060f1SDimitry Andric 
2149fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
2150fe6060f1SDimitry Andric     int fd, const void *buf, size_t count, dfsan_label fd_label,
2151fe6060f1SDimitry Andric     dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
2152fe6060f1SDimitry Andric     dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
2153fe6060f1SDimitry Andric     dfsan_origin *ret_origin) {
2154fe6060f1SDimitry Andric   if (write_origin_callback_info.write_callback) {
2155fe6060f1SDimitry Andric     write_origin_callback_info.write_callback_trampoline(
2156fe6060f1SDimitry Andric         write_origin_callback_info.write_callback, fd, buf, count, fd_label,
2157fe6060f1SDimitry Andric         buf_label, count_label, fd_origin, buf_origin, count_origin);
2158fe6060f1SDimitry Andric   }
2159fe6060f1SDimitry Andric 
2160fe6060f1SDimitry Andric   *ret_label = 0;
2161fe6060f1SDimitry Andric   return write(fd, buf, count);
2162fe6060f1SDimitry Andric }
216368d75effSDimitry Andric } // namespace __dfsan
216468d75effSDimitry Andric 
216568d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
216668d75effSDimitry Andric typedef int dfsan_label_va;
216768d75effSDimitry Andric 
216868d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
216968d75effSDimitry Andric // '%.3f').
217068d75effSDimitry Andric struct Formatter {
217168d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
217268d75effSDimitry Andric       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
217368d75effSDimitry Andric         width(-1) {}
217468d75effSDimitry Andric 
217568d75effSDimitry Andric   int format() {
217668d75effSDimitry Andric     char *tmp_fmt = build_format_string();
217768d75effSDimitry Andric     int retval =
217868d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
217968d75effSDimitry Andric                  0 /* used only to avoid warnings */);
218068d75effSDimitry Andric     free(tmp_fmt);
218168d75effSDimitry Andric     return retval;
218268d75effSDimitry Andric   }
218368d75effSDimitry Andric 
218468d75effSDimitry Andric   template <typename T> int format(T arg) {
218568d75effSDimitry Andric     char *tmp_fmt = build_format_string();
218668d75effSDimitry Andric     int retval;
218768d75effSDimitry Andric     if (width >= 0) {
218868d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
218968d75effSDimitry Andric                         tmp_fmt, width, arg);
219068d75effSDimitry Andric     } else {
219168d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
219268d75effSDimitry Andric                         tmp_fmt, arg);
219368d75effSDimitry Andric     }
219468d75effSDimitry Andric     free(tmp_fmt);
219568d75effSDimitry Andric     return retval;
219668d75effSDimitry Andric   }
219768d75effSDimitry Andric 
219868d75effSDimitry Andric   char *build_format_string() {
219968d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
220068d75effSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1);
220168d75effSDimitry Andric     assert(new_fmt);
220268d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
220368d75effSDimitry Andric     new_fmt[fmt_size] = '\0';
220468d75effSDimitry Andric     return new_fmt;
220568d75effSDimitry Andric   }
220668d75effSDimitry Andric 
220768d75effSDimitry Andric   char *str_cur() { return str + str_off; }
220868d75effSDimitry Andric 
220968d75effSDimitry Andric   size_t num_written_bytes(int retval) {
221068d75effSDimitry Andric     if (retval < 0) {
221168d75effSDimitry Andric       return 0;
221268d75effSDimitry Andric     }
221368d75effSDimitry Andric 
221468d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
221568d75effSDimitry Andric     if (num_avail == 0) {
221668d75effSDimitry Andric       return 0;
221768d75effSDimitry Andric     }
221868d75effSDimitry Andric 
221968d75effSDimitry Andric     size_t num_written = retval;
222068d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
222168d75effSDimitry Andric     // truncated.
222268d75effSDimitry Andric     if (num_written >= num_avail) {
222368d75effSDimitry Andric       num_written -= num_avail;
222468d75effSDimitry Andric     }
222568d75effSDimitry Andric 
222668d75effSDimitry Andric     return num_written;
222768d75effSDimitry Andric   }
222868d75effSDimitry Andric 
222968d75effSDimitry Andric   char *str;
223068d75effSDimitry Andric   size_t str_off;
223168d75effSDimitry Andric   size_t size;
223268d75effSDimitry Andric   const char *fmt_start;
223368d75effSDimitry Andric   const char *fmt_cur;
223468d75effSDimitry Andric   int width;
223568d75effSDimitry Andric };
223668d75effSDimitry Andric 
223768d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
223868d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
223968d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
224068d75effSDimitry Andric // the return value vsnprintf would return.
224168d75effSDimitry Andric //
224268d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
224368d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
224468d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
224568d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
224668d75effSDimitry Andric // propagate labels more precisely.
224768d75effSDimitry Andric //
224868d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
224968d75effSDimitry Andric // positional arguments.
225068d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
225168d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
2252fe6060f1SDimitry Andric                          dfsan_origin *va_origins, dfsan_origin *ret_origin,
225368d75effSDimitry Andric                          va_list ap) {
225468d75effSDimitry Andric   Formatter formatter(str, fmt, size);
225568d75effSDimitry Andric 
225668d75effSDimitry Andric   while (*formatter.fmt_cur) {
225768d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
225868d75effSDimitry Andric     formatter.width = -1;
225968d75effSDimitry Andric     int retval = 0;
226068d75effSDimitry Andric 
226168d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
226268d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
226368d75effSDimitry Andric       // of the string.
226468d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
226568d75effSDimitry Andric            ++formatter.fmt_cur) {}
226668d75effSDimitry Andric       retval = formatter.format();
226768d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
226868d75effSDimitry Andric                       formatter.num_written_bytes(retval));
226968d75effSDimitry Andric     } else {
227068d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
227168d75effSDimitry Andric       // specifier or the end of the string.
227268d75effSDimitry Andric       bool end_fmt = false;
227368d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
227468d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
227568d75effSDimitry Andric         case 'd':
227668d75effSDimitry Andric         case 'i':
227768d75effSDimitry Andric         case 'o':
227868d75effSDimitry Andric         case 'u':
227968d75effSDimitry Andric         case 'x':
228068d75effSDimitry Andric         case 'X':
228168d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
228268d75effSDimitry Andric           case 'h':
228368d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
228468d75effSDimitry Andric             // an int).
228568d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
228668d75effSDimitry Andric             break;
228768d75effSDimitry Andric           case 'l':
228868d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
228968d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
229068d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
229168d75effSDimitry Andric             } else {
229268d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
229368d75effSDimitry Andric             }
229468d75effSDimitry Andric             break;
229568d75effSDimitry Andric           case 'q':
229668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
229768d75effSDimitry Andric             break;
229868d75effSDimitry Andric           case 'j':
229968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
230068d75effSDimitry Andric             break;
230168d75effSDimitry Andric           case 'z':
230268d75effSDimitry Andric           case 't':
230368d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
230468d75effSDimitry Andric             break;
230568d75effSDimitry Andric           default:
230668d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
230768d75effSDimitry Andric           }
2308fe6060f1SDimitry Andric           if (va_origins == nullptr)
230968d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
231068d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2311fe6060f1SDimitry Andric           else
2312fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2313fe6060f1SDimitry Andric                                    formatter.str_cur(),
2314fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
231568d75effSDimitry Andric           end_fmt = true;
231668d75effSDimitry Andric           break;
231768d75effSDimitry Andric 
231868d75effSDimitry Andric         case 'a':
231968d75effSDimitry Andric         case 'A':
232068d75effSDimitry Andric         case 'e':
232168d75effSDimitry Andric         case 'E':
232268d75effSDimitry Andric         case 'f':
232368d75effSDimitry Andric         case 'F':
232468d75effSDimitry Andric         case 'g':
232568d75effSDimitry Andric         case 'G':
232668d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
232768d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
232868d75effSDimitry Andric           } else {
232968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
233068d75effSDimitry Andric           }
2331fe6060f1SDimitry Andric           if (va_origins == nullptr)
233268d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
233368d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2334fe6060f1SDimitry Andric           else
2335fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2336fe6060f1SDimitry Andric                                    formatter.str_cur(),
2337fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
233868d75effSDimitry Andric           end_fmt = true;
233968d75effSDimitry Andric           break;
234068d75effSDimitry Andric 
234168d75effSDimitry Andric         case 'c':
234268d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
2343fe6060f1SDimitry Andric           if (va_origins == nullptr)
234468d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
234568d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2346fe6060f1SDimitry Andric           else
2347fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2348fe6060f1SDimitry Andric                                    formatter.str_cur(),
2349fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
235068d75effSDimitry Andric           end_fmt = true;
235168d75effSDimitry Andric           break;
235268d75effSDimitry Andric 
235368d75effSDimitry Andric         case 's': {
235468d75effSDimitry Andric           char *arg = va_arg(ap, char *);
235568d75effSDimitry Andric           retval = formatter.format(arg);
2356fe6060f1SDimitry Andric           if (va_origins) {
2357fe6060f1SDimitry Andric             va_origins++;
2358fe6060f1SDimitry Andric             dfsan_mem_origin_transfer(formatter.str_cur(), arg,
2359fe6060f1SDimitry Andric                                       formatter.num_written_bytes(retval));
2360fe6060f1SDimitry Andric           }
236168d75effSDimitry Andric           va_labels++;
2362*04eeddc0SDimitry Andric           dfsan_mem_shadow_transfer(formatter.str_cur(), arg,
236368d75effSDimitry Andric                                     formatter.num_written_bytes(retval));
236468d75effSDimitry Andric           end_fmt = true;
236568d75effSDimitry Andric           break;
236668d75effSDimitry Andric         }
236768d75effSDimitry Andric 
236868d75effSDimitry Andric         case 'p':
236968d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
2370fe6060f1SDimitry Andric           if (va_origins == nullptr)
237168d75effSDimitry Andric             dfsan_set_label(*va_labels++, formatter.str_cur(),
237268d75effSDimitry Andric                             formatter.num_written_bytes(retval));
2373fe6060f1SDimitry Andric           else
2374fe6060f1SDimitry Andric             dfsan_set_label_origin(*va_labels++, *va_origins++,
2375fe6060f1SDimitry Andric                                    formatter.str_cur(),
2376fe6060f1SDimitry Andric                                    formatter.num_written_bytes(retval));
237768d75effSDimitry Andric           end_fmt = true;
237868d75effSDimitry Andric           break;
237968d75effSDimitry Andric 
238068d75effSDimitry Andric         case 'n': {
238168d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
238268d75effSDimitry Andric           *ptr = (int)formatter.str_off;
238368d75effSDimitry Andric           va_labels++;
2384fe6060f1SDimitry Andric           if (va_origins)
2385fe6060f1SDimitry Andric             va_origins++;
238668d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
238768d75effSDimitry Andric           end_fmt = true;
238868d75effSDimitry Andric           break;
238968d75effSDimitry Andric         }
239068d75effSDimitry Andric 
239168d75effSDimitry Andric         case '%':
239268d75effSDimitry Andric           retval = formatter.format();
239368d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
239468d75effSDimitry Andric                           formatter.num_written_bytes(retval));
239568d75effSDimitry Andric           end_fmt = true;
239668d75effSDimitry Andric           break;
239768d75effSDimitry Andric 
239868d75effSDimitry Andric         case '*':
239968d75effSDimitry Andric           formatter.width = va_arg(ap, int);
240068d75effSDimitry Andric           va_labels++;
2401fe6060f1SDimitry Andric           if (va_origins)
2402fe6060f1SDimitry Andric             va_origins++;
240368d75effSDimitry Andric           break;
240468d75effSDimitry Andric 
240568d75effSDimitry Andric         default:
240668d75effSDimitry Andric           break;
240768d75effSDimitry Andric         }
240868d75effSDimitry Andric       }
240968d75effSDimitry Andric     }
241068d75effSDimitry Andric 
241168d75effSDimitry Andric     if (retval < 0) {
241268d75effSDimitry Andric       return retval;
241368d75effSDimitry Andric     }
241468d75effSDimitry Andric 
241568d75effSDimitry Andric     formatter.fmt_cur++;
241668d75effSDimitry Andric     formatter.str_off += retval;
241768d75effSDimitry Andric   }
241868d75effSDimitry Andric 
241968d75effSDimitry Andric   *ret_label = 0;
2420fe6060f1SDimitry Andric   if (ret_origin)
2421fe6060f1SDimitry Andric     *ret_origin = 0;
242268d75effSDimitry Andric 
242368d75effSDimitry Andric   // Number of bytes written in total.
242468d75effSDimitry Andric   return formatter.str_off;
242568d75effSDimitry Andric }
242668d75effSDimitry Andric 
242768d75effSDimitry Andric extern "C" {
242868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
242968d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
243068d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
243168d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
243268d75effSDimitry Andric   va_list ap;
243368d75effSDimitry Andric   va_start(ap, ret_label);
2434fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, nullptr,
2435fe6060f1SDimitry Andric                           nullptr, ap);
2436fe6060f1SDimitry Andric   va_end(ap);
2437fe6060f1SDimitry Andric   return ret;
2438fe6060f1SDimitry Andric }
2439fe6060f1SDimitry Andric 
2440fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2441fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label,
2442fe6060f1SDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
2443fe6060f1SDimitry Andric                    dfsan_label *ret_label, dfsan_origin str_origin,
2444fe6060f1SDimitry Andric                    dfsan_origin format_origin, dfsan_origin *va_origins,
2445fe6060f1SDimitry Andric                    dfsan_origin *ret_origin, ...) {
2446fe6060f1SDimitry Andric   va_list ap;
2447fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2448fe6060f1SDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, va_origins,
2449fe6060f1SDimitry Andric                           ret_origin, ap);
245068d75effSDimitry Andric   va_end(ap);
245168d75effSDimitry Andric   return ret;
245268d75effSDimitry Andric }
245368d75effSDimitry Andric 
245468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
245568d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
245668d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
245768d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
245868d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
245968d75effSDimitry Andric   va_list ap;
246068d75effSDimitry Andric   va_start(ap, ret_label);
2461fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr,
2462fe6060f1SDimitry Andric                           nullptr, ap);
246368d75effSDimitry Andric   va_end(ap);
246468d75effSDimitry Andric   return ret;
246568d75effSDimitry Andric }
246668d75effSDimitry Andric 
2467fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2468fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format,
2469fe6060f1SDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
2470fe6060f1SDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
2471fe6060f1SDimitry Andric                     dfsan_label *ret_label, dfsan_origin str_origin,
2472fe6060f1SDimitry Andric                     dfsan_origin size_origin, dfsan_origin format_origin,
2473fe6060f1SDimitry Andric                     dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) {
2474fe6060f1SDimitry Andric   va_list ap;
2475fe6060f1SDimitry Andric   va_start(ap, ret_origin);
2476fe6060f1SDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins,
2477fe6060f1SDimitry Andric                           ret_origin, ap);
2478fe6060f1SDimitry Andric   va_end(ap);
2479fe6060f1SDimitry Andric   return ret;
2480fe6060f1SDimitry Andric }
2481fe6060f1SDimitry Andric 
2482fe6060f1SDimitry Andric static void BeforeFork() {
2483fe6060f1SDimitry Andric   StackDepotLockAll();
2484fe6060f1SDimitry Andric   GetChainedOriginDepot()->LockAll();
2485fe6060f1SDimitry Andric }
2486fe6060f1SDimitry Andric 
2487fe6060f1SDimitry Andric static void AfterFork() {
2488fe6060f1SDimitry Andric   GetChainedOriginDepot()->UnlockAll();
2489fe6060f1SDimitry Andric   StackDepotUnlockAll();
2490fe6060f1SDimitry Andric }
2491fe6060f1SDimitry Andric 
2492fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2493fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) {
2494fe6060f1SDimitry Andric   pid_t pid = fork();
2495fe6060f1SDimitry Andric   *ret_label = 0;
2496fe6060f1SDimitry Andric   return pid;
2497fe6060f1SDimitry Andric }
2498fe6060f1SDimitry Andric 
2499fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
2500fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
2501fe6060f1SDimitry Andric   BeforeFork();
2502fe6060f1SDimitry Andric   pid_t pid = __dfsw_fork(ret_label);
2503fe6060f1SDimitry Andric   AfterFork();
2504fe6060f1SDimitry Andric   return pid;
2505fe6060f1SDimitry Andric }
2506fe6060f1SDimitry Andric 
250768d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
250868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
250968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
251068d75effSDimitry Andric                              u32 *) {}
2511349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg,
2512349cc55cSDimitry Andric                              const uptr *end) {}
251368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
251468d75effSDimitry Andric 
251568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
251668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
251768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
251868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
251968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
252068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
252168d75effSDimitry Andric                              void) {}
252268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
252368d75effSDimitry Andric                              void) {}
252468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
252568d75effSDimitry Andric                              void) {}
252668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
252768d75effSDimitry Andric                              void) {}
252868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
252968d75effSDimitry Andric }  // extern "C"
2530