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 58*74626c16SDimitry Andric #define WRAPPER_ALIAS(fun, real) \ 59*74626c16SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_##fun() ALIAS(__dfsw_##real); \ 60*74626c16SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_##fun() ALIAS(__dfso_##real); 61*74626c16SDimitry Andric 62fe6060f1SDimitry Andric // Async-safe, non-reentrant spin lock. 63fe6060f1SDimitry Andric class SignalSpinLocker { 64fe6060f1SDimitry Andric public: 65fe6060f1SDimitry Andric SignalSpinLocker() { 66fe6060f1SDimitry Andric sigset_t all_set; 67fe6060f1SDimitry Andric sigfillset(&all_set); 68fe6060f1SDimitry Andric pthread_sigmask(SIG_SETMASK, &all_set, &saved_thread_mask_); 69fe6060f1SDimitry Andric sigactions_mu.Lock(); 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric ~SignalSpinLocker() { 72fe6060f1SDimitry Andric sigactions_mu.Unlock(); 73fe6060f1SDimitry Andric pthread_sigmask(SIG_SETMASK, &saved_thread_mask_, nullptr); 74fe6060f1SDimitry Andric } 75fe6060f1SDimitry Andric 76fe6060f1SDimitry Andric private: 77fe6060f1SDimitry Andric static StaticSpinMutex sigactions_mu; 78fe6060f1SDimitry Andric sigset_t saved_thread_mask_; 79fe6060f1SDimitry Andric 80fe6060f1SDimitry Andric SignalSpinLocker(const SignalSpinLocker &) = delete; 81fe6060f1SDimitry Andric SignalSpinLocker &operator=(const SignalSpinLocker &) = delete; 82fe6060f1SDimitry Andric }; 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric StaticSpinMutex SignalSpinLocker::sigactions_mu; 85fe6060f1SDimitry Andric 8668d75effSDimitry Andric extern "C" { 8768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int 8868d75effSDimitry Andric __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label, 8968d75effSDimitry Andric dfsan_label buf_label, dfsan_label *ret_label) { 9068d75effSDimitry Andric int ret = stat(path, buf); 9168d75effSDimitry Andric if (ret == 0) 9268d75effSDimitry Andric dfsan_set_label(0, buf, sizeof(struct stat)); 9368d75effSDimitry Andric *ret_label = 0; 9468d75effSDimitry Andric return ret; 9568d75effSDimitry Andric } 9668d75effSDimitry Andric 97fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_stat( 98fe6060f1SDimitry Andric const char *path, struct stat *buf, dfsan_label path_label, 99fe6060f1SDimitry Andric dfsan_label buf_label, dfsan_label *ret_label, dfsan_origin path_origin, 100fe6060f1SDimitry Andric dfsan_origin buf_origin, dfsan_origin *ret_origin) { 101fe6060f1SDimitry Andric int ret = __dfsw_stat(path, buf, path_label, buf_label, ret_label); 102fe6060f1SDimitry Andric return ret; 103fe6060f1SDimitry Andric } 104fe6060f1SDimitry Andric 10568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf, 10668d75effSDimitry Andric dfsan_label fd_label, 10768d75effSDimitry Andric dfsan_label buf_label, 10868d75effSDimitry Andric dfsan_label *ret_label) { 10968d75effSDimitry Andric int ret = fstat(fd, buf); 11068d75effSDimitry Andric if (ret == 0) 11168d75effSDimitry Andric dfsan_set_label(0, buf, sizeof(struct stat)); 11268d75effSDimitry Andric *ret_label = 0; 11368d75effSDimitry Andric return ret; 11468d75effSDimitry Andric } 11568d75effSDimitry Andric 116fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_fstat( 117fe6060f1SDimitry Andric int fd, struct stat *buf, dfsan_label fd_label, dfsan_label buf_label, 118fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin, 119fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 120fe6060f1SDimitry Andric int ret = __dfsw_fstat(fd, buf, fd_label, buf_label, ret_label); 121fe6060f1SDimitry Andric return ret; 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric 124fe6060f1SDimitry Andric static char *dfsan_strchr_with_label(const char *s, int c, size_t *bytes_read, 125fe6060f1SDimitry Andric dfsan_label s_label, dfsan_label c_label, 126fe6060f1SDimitry Andric dfsan_label *ret_label) { 127fe6060f1SDimitry Andric char *match_pos = nullptr; 128fe6060f1SDimitry Andric for (size_t i = 0;; ++i) { 129fe6060f1SDimitry Andric if (s[i] == c || s[i] == 0) { 130fe6060f1SDimitry Andric // If s[i] is the \0 at the end of the string, and \0 is not the 131fe6060f1SDimitry Andric // character we are searching for, then return null. 132fe6060f1SDimitry Andric *bytes_read = i + 1; 133fe6060f1SDimitry Andric match_pos = s[i] == 0 && c != 0 ? nullptr : const_cast<char *>(s + i); 134fe6060f1SDimitry Andric break; 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric } 137fe6060f1SDimitry Andric if (flags().strict_data_dependencies) 138fe6060f1SDimitry Andric *ret_label = s_label; 139fe6060f1SDimitry Andric else 140fe6060f1SDimitry Andric *ret_label = dfsan_union(dfsan_read_label(s, *bytes_read), 141fe6060f1SDimitry Andric dfsan_union(s_label, c_label)); 142fe6060f1SDimitry Andric return match_pos; 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 14568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c, 14668d75effSDimitry Andric dfsan_label s_label, 14768d75effSDimitry Andric dfsan_label c_label, 14868d75effSDimitry Andric dfsan_label *ret_label) { 149fe6060f1SDimitry Andric size_t bytes_read; 150fe6060f1SDimitry Andric return dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label, 151fe6060f1SDimitry Andric ret_label); 15268d75effSDimitry Andric } 1535ffd83dbSDimitry Andric 154fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strchr( 155fe6060f1SDimitry Andric const char *s, int c, dfsan_label s_label, dfsan_label c_label, 156fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin, 157fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 158fe6060f1SDimitry Andric size_t bytes_read; 159fe6060f1SDimitry Andric char *r = 160fe6060f1SDimitry Andric dfsan_strchr_with_label(s, c, &bytes_read, s_label, c_label, ret_label); 161fe6060f1SDimitry Andric if (flags().strict_data_dependencies) { 162fe6060f1SDimitry Andric *ret_origin = s_origin; 163fe6060f1SDimitry Andric } else if (*ret_label) { 164fe6060f1SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(s, bytes_read); 165fe6060f1SDimitry Andric *ret_origin = o ? o : (s_label ? s_origin : c_origin); 1665ffd83dbSDimitry Andric } 167fe6060f1SDimitry Andric return r; 16868d75effSDimitry Andric } 16968d75effSDimitry Andric 170e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strpbrk(const char *s, 171e8d8bef9SDimitry Andric const char *accept, 172e8d8bef9SDimitry Andric dfsan_label s_label, 173e8d8bef9SDimitry Andric dfsan_label accept_label, 17468d75effSDimitry Andric dfsan_label *ret_label) { 175e8d8bef9SDimitry Andric const char *ret = strpbrk(s, accept); 176e8d8bef9SDimitry Andric if (flags().strict_data_dependencies) { 177e8d8bef9SDimitry Andric *ret_label = ret ? s_label : 0; 178e8d8bef9SDimitry Andric } else { 179e8d8bef9SDimitry Andric size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1; 180e8d8bef9SDimitry Andric *ret_label = 181e8d8bef9SDimitry Andric dfsan_union(dfsan_read_label(s, s_bytes_read), 182e8d8bef9SDimitry Andric dfsan_union(dfsan_read_label(accept, strlen(accept) + 1), 183e8d8bef9SDimitry Andric dfsan_union(s_label, accept_label))); 184e8d8bef9SDimitry Andric } 185e8d8bef9SDimitry Andric return const_cast<char *>(ret); 186e8d8bef9SDimitry Andric } 187e8d8bef9SDimitry Andric 188fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strpbrk( 189fe6060f1SDimitry Andric const char *s, const char *accept, dfsan_label s_label, 190fe6060f1SDimitry Andric dfsan_label accept_label, dfsan_label *ret_label, dfsan_origin s_origin, 191fe6060f1SDimitry Andric dfsan_origin accept_origin, dfsan_origin *ret_origin) { 192fe6060f1SDimitry Andric const char *ret = __dfsw_strpbrk(s, accept, s_label, accept_label, ret_label); 193fe6060f1SDimitry Andric if (flags().strict_data_dependencies) { 194fe6060f1SDimitry Andric if (ret) 195fe6060f1SDimitry Andric *ret_origin = s_origin; 196fe6060f1SDimitry Andric } else { 197fe6060f1SDimitry Andric if (*ret_label) { 198fe6060f1SDimitry Andric size_t s_bytes_read = (ret ? ret - s : strlen(s)) + 1; 199fe6060f1SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_bytes_read); 200fe6060f1SDimitry Andric if (o) { 201fe6060f1SDimitry Andric *ret_origin = o; 202fe6060f1SDimitry Andric } else { 203fe6060f1SDimitry Andric o = dfsan_read_origin_of_first_taint(accept, strlen(accept) + 1); 204fe6060f1SDimitry Andric *ret_origin = o ? o : (s_label ? s_origin : accept_origin); 205fe6060f1SDimitry Andric } 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric } 208fe6060f1SDimitry Andric return const_cast<char *>(ret); 209fe6060f1SDimitry Andric } 210fe6060f1SDimitry Andric 21106c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strsep(char **s, const char *delim, 21206c3fb27SDimitry Andric dfsan_label s_label, 21306c3fb27SDimitry Andric dfsan_label delim_label, 21406c3fb27SDimitry Andric dfsan_label *ret_label) { 21506c3fb27SDimitry Andric dfsan_label base_label = dfsan_read_label(s, sizeof(*s)); 21606c3fb27SDimitry Andric char *base = *s; 21706c3fb27SDimitry Andric char *res = strsep(s, delim); 21806c3fb27SDimitry Andric if (res != *s) { 21906c3fb27SDimitry Andric char *token_start = res; 22006c3fb27SDimitry Andric int token_length = strlen(res); 22106c3fb27SDimitry Andric // the delimiter byte has been set to NULL 22206c3fb27SDimitry Andric dfsan_set_label(0, token_start + token_length, 1); 22306c3fb27SDimitry Andric } 22406c3fb27SDimitry Andric 22506c3fb27SDimitry Andric if (flags().strict_data_dependencies) { 22606c3fb27SDimitry Andric *ret_label = res ? base_label : 0; 22706c3fb27SDimitry Andric } else { 22806c3fb27SDimitry Andric size_t s_bytes_read = (res ? strlen(res) : strlen(base)) + 1; 22906c3fb27SDimitry Andric *ret_label = dfsan_union( 23006c3fb27SDimitry Andric dfsan_union(base_label, dfsan_read_label(base, sizeof(s_bytes_read))), 23106c3fb27SDimitry Andric dfsan_union(dfsan_read_label(delim, strlen(delim) + 1), 23206c3fb27SDimitry Andric dfsan_union(s_label, delim_label))); 23306c3fb27SDimitry Andric } 23406c3fb27SDimitry Andric 23506c3fb27SDimitry Andric return res; 23606c3fb27SDimitry Andric } 23706c3fb27SDimitry Andric 23806c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strsep( 23906c3fb27SDimitry Andric char **s, const char *delim, dfsan_label s_label, dfsan_label delim_label, 24006c3fb27SDimitry Andric dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin delim_origin, 24106c3fb27SDimitry Andric dfsan_origin *ret_origin) { 24206c3fb27SDimitry Andric dfsan_origin base_origin = dfsan_read_origin_of_first_taint(s, sizeof(*s)); 24306c3fb27SDimitry Andric char *res = __dfsw_strsep(s, delim, s_label, delim_label, ret_label); 24406c3fb27SDimitry Andric if (flags().strict_data_dependencies) { 24506c3fb27SDimitry Andric if (res) 24606c3fb27SDimitry Andric *ret_origin = base_origin; 24706c3fb27SDimitry Andric } else { 24806c3fb27SDimitry Andric if (*ret_label) { 24906c3fb27SDimitry Andric if (base_origin) { 25006c3fb27SDimitry Andric *ret_origin = base_origin; 25106c3fb27SDimitry Andric } else { 25206c3fb27SDimitry Andric dfsan_origin o = 25306c3fb27SDimitry Andric dfsan_read_origin_of_first_taint(delim, strlen(delim) + 1); 25406c3fb27SDimitry Andric *ret_origin = o ? o : (s_label ? s_origin : delim_origin); 25506c3fb27SDimitry Andric } 25606c3fb27SDimitry Andric } 25706c3fb27SDimitry Andric } 25806c3fb27SDimitry Andric 25906c3fb27SDimitry Andric return res; 26006c3fb27SDimitry Andric } 26106c3fb27SDimitry Andric 262e8d8bef9SDimitry Andric static int dfsan_memcmp_bcmp(const void *s1, const void *s2, size_t n, 263fe6060f1SDimitry Andric size_t *bytes_read) { 26468d75effSDimitry Andric const char *cs1 = (const char *) s1, *cs2 = (const char *) s2; 26568d75effSDimitry Andric for (size_t i = 0; i != n; ++i) { 26668d75effSDimitry Andric if (cs1[i] != cs2[i]) { 267fe6060f1SDimitry Andric *bytes_read = i + 1; 26868d75effSDimitry Andric return cs1[i] - cs2[i]; 26968d75effSDimitry Andric } 27068d75effSDimitry Andric } 271fe6060f1SDimitry Andric *bytes_read = n; 27268d75effSDimitry Andric return 0; 27368d75effSDimitry Andric } 27468d75effSDimitry Andric 275fe6060f1SDimitry Andric static dfsan_label dfsan_get_memcmp_label(const void *s1, const void *s2, 276fe6060f1SDimitry Andric size_t pos) { 277fe6060f1SDimitry Andric if (flags().strict_data_dependencies) 278fe6060f1SDimitry Andric return 0; 279fe6060f1SDimitry Andric return dfsan_union(dfsan_read_label(s1, pos), dfsan_read_label(s2, pos)); 280fe6060f1SDimitry Andric } 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric static void dfsan_get_memcmp_origin(const void *s1, const void *s2, size_t pos, 283fe6060f1SDimitry Andric dfsan_label *ret_label, 284fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 285fe6060f1SDimitry Andric *ret_label = dfsan_get_memcmp_label(s1, s2, pos); 286fe6060f1SDimitry Andric if (*ret_label == 0) 287fe6060f1SDimitry Andric return; 288fe6060f1SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(s1, pos); 289fe6060f1SDimitry Andric *ret_origin = o ? o : dfsan_read_origin_of_first_taint(s2, pos); 290fe6060f1SDimitry Andric } 291fe6060f1SDimitry Andric 292fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_label(const void *s1, const void *s2, size_t n, 293fe6060f1SDimitry Andric dfsan_label *ret_label) { 294fe6060f1SDimitry Andric size_t bytes_read; 295fe6060f1SDimitry Andric int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read); 296fe6060f1SDimitry Andric *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read); 297fe6060f1SDimitry Andric return r; 298fe6060f1SDimitry Andric } 299fe6060f1SDimitry Andric 300fe6060f1SDimitry Andric static int dfsan_memcmp_bcmp_origin(const void *s1, const void *s2, size_t n, 301fe6060f1SDimitry Andric dfsan_label *ret_label, 302fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 303fe6060f1SDimitry Andric size_t bytes_read; 304fe6060f1SDimitry Andric int r = dfsan_memcmp_bcmp(s1, s2, n, &bytes_read); 305fe6060f1SDimitry Andric dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin); 306fe6060f1SDimitry Andric return r; 307fe6060f1SDimitry Andric } 308fe6060f1SDimitry Andric 309e8d8bef9SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc, 310e8d8bef9SDimitry Andric const void *s1, const void *s2, size_t n, 311e8d8bef9SDimitry Andric dfsan_label s1_label, dfsan_label s2_label, 312e8d8bef9SDimitry Andric dfsan_label n_label) 313e8d8bef9SDimitry Andric 314fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, uptr caller_pc, 315fe6060f1SDimitry Andric const void *s1, const void *s2, size_t n, 316fe6060f1SDimitry Andric dfsan_label s1_label, dfsan_label s2_label, 317fe6060f1SDimitry Andric dfsan_label n_label, dfsan_origin s1_origin, 318fe6060f1SDimitry Andric dfsan_origin s2_origin, dfsan_origin n_origin) 319fe6060f1SDimitry Andric 320e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2, 321e8d8bef9SDimitry Andric size_t n, dfsan_label s1_label, 322e8d8bef9SDimitry Andric dfsan_label s2_label, 323e8d8bef9SDimitry Andric dfsan_label n_label, 324e8d8bef9SDimitry Andric dfsan_label *ret_label) { 325e8d8bef9SDimitry Andric CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n, 326e8d8bef9SDimitry Andric s1_label, s2_label, n_label); 327fe6060f1SDimitry Andric return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label); 328fe6060f1SDimitry Andric } 329fe6060f1SDimitry Andric 330fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_memcmp( 331fe6060f1SDimitry Andric const void *s1, const void *s2, size_t n, dfsan_label s1_label, 332fe6060f1SDimitry Andric dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label, 333fe6060f1SDimitry Andric dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin, 334fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 335fe6060f1SDimitry Andric CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_memcmp, GET_CALLER_PC(), s1, 336fe6060f1SDimitry Andric s2, n, s1_label, s2_label, n_label, s1_origin, 337fe6060f1SDimitry Andric s2_origin, n_origin); 338fe6060f1SDimitry Andric return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin); 339e8d8bef9SDimitry Andric } 340e8d8bef9SDimitry Andric 341e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_bcmp(const void *s1, const void *s2, 342e8d8bef9SDimitry Andric size_t n, dfsan_label s1_label, 343e8d8bef9SDimitry Andric dfsan_label s2_label, 344e8d8bef9SDimitry Andric dfsan_label n_label, 345e8d8bef9SDimitry Andric dfsan_label *ret_label) { 346fe6060f1SDimitry Andric return dfsan_memcmp_bcmp_label(s1, s2, n, ret_label); 347fe6060f1SDimitry Andric } 348fe6060f1SDimitry Andric 349fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_bcmp( 350fe6060f1SDimitry Andric const void *s1, const void *s2, size_t n, dfsan_label s1_label, 351fe6060f1SDimitry Andric dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label, 352fe6060f1SDimitry Andric dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin, 353fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 354fe6060f1SDimitry Andric return dfsan_memcmp_bcmp_origin(s1, s2, n, ret_label, ret_origin); 355fe6060f1SDimitry Andric } 356fe6060f1SDimitry Andric 357fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit. 358fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2. 359fe6060f1SDimitry Andric static int dfsan_strncmp(const char *s1, const char *s2, size_t n, 360fe6060f1SDimitry Andric size_t *bytes_read) { 361fe6060f1SDimitry Andric for (size_t i = 0;; ++i) { 362fe6060f1SDimitry Andric if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || (n > 0 && i == n - 1)) { 363fe6060f1SDimitry Andric *bytes_read = i + 1; 364fe6060f1SDimitry Andric return s1[i] - s2[i]; 365fe6060f1SDimitry Andric } 366fe6060f1SDimitry Andric } 367e8d8bef9SDimitry Andric } 368e8d8bef9SDimitry Andric 36968d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc, 37068d75effSDimitry Andric const char *s1, const char *s2, 37168d75effSDimitry Andric dfsan_label s1_label, dfsan_label s2_label) 37268d75effSDimitry Andric 373fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, uptr caller_pc, 374fe6060f1SDimitry Andric const char *s1, const char *s2, 375fe6060f1SDimitry Andric dfsan_label s1_label, dfsan_label s2_label, 376fe6060f1SDimitry Andric dfsan_origin s1_origin, dfsan_origin s2_origin) 377fe6060f1SDimitry Andric 37868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2, 37968d75effSDimitry Andric dfsan_label s1_label, 38068d75effSDimitry Andric dfsan_label s2_label, 38168d75effSDimitry Andric dfsan_label *ret_label) { 38268d75effSDimitry Andric CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2, 38368d75effSDimitry Andric s1_label, s2_label); 384fe6060f1SDimitry Andric size_t bytes_read; 385fe6060f1SDimitry Andric int r = dfsan_strncmp(s1, s2, 0, &bytes_read); 386fe6060f1SDimitry Andric *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read); 387fe6060f1SDimitry Andric return r; 38868d75effSDimitry Andric } 38968d75effSDimitry Andric 390fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcmp( 391fe6060f1SDimitry Andric const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label, 392fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin, 393fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 394fe6060f1SDimitry Andric CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strcmp, GET_CALLER_PC(), s1, 395fe6060f1SDimitry Andric s2, s1_label, s2_label, s1_origin, s2_origin); 396fe6060f1SDimitry Andric size_t bytes_read; 397fe6060f1SDimitry Andric int r = dfsan_strncmp(s1, s2, 0, &bytes_read); 398fe6060f1SDimitry Andric dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin); 399fe6060f1SDimitry Andric return r; 400fe6060f1SDimitry Andric } 401fe6060f1SDimitry Andric 402fe6060f1SDimitry Andric // When n == 0, compare strings without byte limit. 403fe6060f1SDimitry Andric // When n > 0, compare the first (at most) n bytes of s1 and s2. 404fe6060f1SDimitry Andric static int dfsan_strncasecmp(const char *s1, const char *s2, size_t n, 405fe6060f1SDimitry Andric size_t *bytes_read) { 40668d75effSDimitry Andric for (size_t i = 0;; ++i) { 4075ffd83dbSDimitry Andric char s1_lower = tolower(s1[i]); 4085ffd83dbSDimitry Andric char s2_lower = tolower(s2[i]); 4095ffd83dbSDimitry Andric 410fe6060f1SDimitry Andric if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0 || 411fe6060f1SDimitry Andric (n > 0 && i == n - 1)) { 412fe6060f1SDimitry Andric *bytes_read = i + 1; 4135ffd83dbSDimitry Andric return s1_lower - s2_lower; 41468d75effSDimitry Andric } 41568d75effSDimitry Andric } 416fe6060f1SDimitry Andric } 417fe6060f1SDimitry Andric 418fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcasecmp(const char *s1, 419fe6060f1SDimitry Andric const char *s2, 420fe6060f1SDimitry Andric dfsan_label s1_label, 421fe6060f1SDimitry Andric dfsan_label s2_label, 422fe6060f1SDimitry Andric dfsan_label *ret_label) { 423fe6060f1SDimitry Andric size_t bytes_read; 424fe6060f1SDimitry Andric int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read); 425fe6060f1SDimitry Andric *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read); 426fe6060f1SDimitry Andric return r; 427fe6060f1SDimitry Andric } 428fe6060f1SDimitry Andric 429fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strcasecmp( 430fe6060f1SDimitry Andric const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label, 431fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin s1_origin, dfsan_origin s2_origin, 432fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 433fe6060f1SDimitry Andric size_t bytes_read; 434fe6060f1SDimitry Andric int r = dfsan_strncasecmp(s1, s2, 0, &bytes_read); 435fe6060f1SDimitry Andric dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin); 436fe6060f1SDimitry Andric return r; 43768d75effSDimitry Andric } 43868d75effSDimitry Andric 43968d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc, 44068d75effSDimitry Andric const char *s1, const char *s2, size_t n, 44168d75effSDimitry Andric dfsan_label s1_label, dfsan_label s2_label, 44268d75effSDimitry Andric dfsan_label n_label) 44368d75effSDimitry Andric 444fe6060f1SDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, uptr caller_pc, 445fe6060f1SDimitry Andric const char *s1, const char *s2, size_t n, 446fe6060f1SDimitry Andric dfsan_label s1_label, dfsan_label s2_label, 447fe6060f1SDimitry Andric dfsan_label n_label, dfsan_origin s1_origin, 448fe6060f1SDimitry Andric dfsan_origin s2_origin, dfsan_origin n_origin) 449fe6060f1SDimitry Andric 45068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2, 45168d75effSDimitry Andric size_t n, dfsan_label s1_label, 45268d75effSDimitry Andric dfsan_label s2_label, 45368d75effSDimitry Andric dfsan_label n_label, 45468d75effSDimitry Andric dfsan_label *ret_label) { 45568d75effSDimitry Andric if (n == 0) { 45668d75effSDimitry Andric *ret_label = 0; 45768d75effSDimitry Andric return 0; 45868d75effSDimitry Andric } 45968d75effSDimitry Andric 46068d75effSDimitry Andric CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2, 46168d75effSDimitry Andric n, s1_label, s2_label, n_label); 46268d75effSDimitry Andric 463fe6060f1SDimitry Andric size_t bytes_read; 464fe6060f1SDimitry Andric int r = dfsan_strncmp(s1, s2, n, &bytes_read); 465fe6060f1SDimitry Andric *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read); 466fe6060f1SDimitry Andric return r; 46768d75effSDimitry Andric } 46868d75effSDimitry Andric 469fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncmp( 470fe6060f1SDimitry Andric const char *s1, const char *s2, size_t n, dfsan_label s1_label, 471fe6060f1SDimitry Andric dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label, 472fe6060f1SDimitry Andric dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin, 473fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 47468d75effSDimitry Andric if (n == 0) { 47568d75effSDimitry Andric *ret_label = 0; 47668d75effSDimitry Andric return 0; 47768d75effSDimitry Andric } 47868d75effSDimitry Andric 479fe6060f1SDimitry Andric CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_origin_strncmp, GET_CALLER_PC(), 480fe6060f1SDimitry Andric s1, s2, n, s1_label, s2_label, n_label, s1_origin, 481fe6060f1SDimitry Andric s2_origin, n_origin); 4825ffd83dbSDimitry Andric 483fe6060f1SDimitry Andric size_t bytes_read; 484fe6060f1SDimitry Andric int r = dfsan_strncmp(s1, s2, n, &bytes_read); 485fe6060f1SDimitry Andric dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin); 486fe6060f1SDimitry Andric return r; 487fe6060f1SDimitry Andric } 488fe6060f1SDimitry Andric 489fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncasecmp( 490fe6060f1SDimitry Andric const char *s1, const char *s2, size_t n, dfsan_label s1_label, 491fe6060f1SDimitry Andric dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) { 492fe6060f1SDimitry Andric if (n == 0) { 49368d75effSDimitry Andric *ret_label = 0; 49468d75effSDimitry Andric return 0; 49568d75effSDimitry Andric } 49668d75effSDimitry Andric 497fe6060f1SDimitry Andric size_t bytes_read; 498fe6060f1SDimitry Andric int r = dfsan_strncasecmp(s1, s2, n, &bytes_read); 499fe6060f1SDimitry Andric *ret_label = dfsan_get_memcmp_label(s1, s2, bytes_read); 500fe6060f1SDimitry Andric return r; 50168d75effSDimitry Andric } 50268d75effSDimitry Andric 503fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_strncasecmp( 504fe6060f1SDimitry Andric const char *s1, const char *s2, size_t n, dfsan_label s1_label, 505fe6060f1SDimitry Andric dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label, 506fe6060f1SDimitry Andric dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin, 507fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 508fe6060f1SDimitry Andric if (n == 0) { 509fe6060f1SDimitry Andric *ret_label = 0; 510fe6060f1SDimitry Andric return 0; 511fe6060f1SDimitry Andric } 512fe6060f1SDimitry Andric 513fe6060f1SDimitry Andric size_t bytes_read; 514fe6060f1SDimitry Andric int r = dfsan_strncasecmp(s1, s2, n, &bytes_read); 515fe6060f1SDimitry Andric dfsan_get_memcmp_origin(s1, s2, bytes_read, ret_label, ret_origin); 516fe6060f1SDimitry Andric return r; 517fe6060f1SDimitry Andric } 518fe6060f1SDimitry Andric 519fe6060f1SDimitry Andric 52068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t 52168d75effSDimitry Andric __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) { 52268d75effSDimitry Andric size_t ret = strlen(s); 52368d75effSDimitry Andric if (flags().strict_data_dependencies) { 52468d75effSDimitry Andric *ret_label = 0; 52568d75effSDimitry Andric } else { 52668d75effSDimitry Andric *ret_label = dfsan_read_label(s, ret + 1); 52768d75effSDimitry Andric } 52868d75effSDimitry Andric return ret; 52968d75effSDimitry Andric } 53068d75effSDimitry Andric 531fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s, 532fe6060f1SDimitry Andric dfsan_label s_label, 533fe6060f1SDimitry Andric dfsan_label *ret_label, 534fe6060f1SDimitry Andric dfsan_origin s_origin, 535fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 536fe6060f1SDimitry Andric size_t ret = __dfsw_strlen(s, s_label, ret_label); 537fe6060f1SDimitry Andric if (!flags().strict_data_dependencies) 538fe6060f1SDimitry Andric *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1); 539fe6060f1SDimitry Andric return ret; 540fe6060f1SDimitry Andric } 541fe6060f1SDimitry Andric 54206c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strnlen(const char *s, 54306c3fb27SDimitry Andric size_t maxlen, 54406c3fb27SDimitry Andric dfsan_label s_label, 54506c3fb27SDimitry Andric dfsan_label maxlen_label, 54606c3fb27SDimitry Andric dfsan_label *ret_label) { 54706c3fb27SDimitry Andric size_t ret = strnlen(s, maxlen); 54806c3fb27SDimitry Andric if (flags().strict_data_dependencies) { 54906c3fb27SDimitry Andric *ret_label = 0; 55006c3fb27SDimitry Andric } else { 55106c3fb27SDimitry Andric size_t full_len = strlen(s); 55206c3fb27SDimitry Andric size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen; 55306c3fb27SDimitry Andric *ret_label = dfsan_union(maxlen_label, dfsan_read_label(s, covered_len)); 55406c3fb27SDimitry Andric } 55506c3fb27SDimitry Andric return ret; 55606c3fb27SDimitry Andric } 55706c3fb27SDimitry Andric 55806c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strnlen( 55906c3fb27SDimitry Andric const char *s, size_t maxlen, dfsan_label s_label, dfsan_label maxlen_label, 56006c3fb27SDimitry Andric dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin maxlen_origin, 56106c3fb27SDimitry Andric dfsan_origin *ret_origin) { 56206c3fb27SDimitry Andric size_t ret = __dfsw_strnlen(s, maxlen, s_label, maxlen_label, ret_label); 56306c3fb27SDimitry Andric if (!flags().strict_data_dependencies) { 56406c3fb27SDimitry Andric size_t full_len = strlen(s); 56506c3fb27SDimitry Andric size_t covered_len = maxlen > (full_len + 1) ? (full_len + 1) : maxlen; 56606c3fb27SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(s, covered_len); 56706c3fb27SDimitry Andric *ret_origin = o ? o : maxlen_origin; 56806c3fb27SDimitry Andric } 56906c3fb27SDimitry Andric return ret; 57006c3fb27SDimitry Andric } 57106c3fb27SDimitry Andric 572fe6060f1SDimitry Andric static void *dfsan_memmove(void *dest, const void *src, size_t n) { 573fe6060f1SDimitry Andric dfsan_label *sdest = shadow_for(dest); 574fe6060f1SDimitry Andric const dfsan_label *ssrc = shadow_for(src); 575fe6060f1SDimitry Andric internal_memmove((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label)); 576fe6060f1SDimitry Andric return internal_memmove(dest, src, n); 577fe6060f1SDimitry Andric } 578fe6060f1SDimitry Andric 579fe6060f1SDimitry Andric static void *dfsan_memmove_with_origin(void *dest, const void *src, size_t n) { 580fe6060f1SDimitry Andric dfsan_mem_origin_transfer(dest, src, n); 581fe6060f1SDimitry Andric return dfsan_memmove(dest, src, n); 582fe6060f1SDimitry Andric } 58368d75effSDimitry Andric 58468d75effSDimitry Andric static void *dfsan_memcpy(void *dest, const void *src, size_t n) { 58504eeddc0SDimitry Andric dfsan_mem_shadow_transfer(dest, src, n); 58668d75effSDimitry Andric return internal_memcpy(dest, src, n); 58768d75effSDimitry Andric } 58868d75effSDimitry Andric 589fe6060f1SDimitry Andric static void *dfsan_memcpy_with_origin(void *dest, const void *src, size_t n) { 590fe6060f1SDimitry Andric dfsan_mem_origin_transfer(dest, src, n); 591fe6060f1SDimitry Andric return dfsan_memcpy(dest, src, n); 592fe6060f1SDimitry Andric } 593fe6060f1SDimitry Andric 59468d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) { 59568d75effSDimitry Andric internal_memset(s, c, n); 59668d75effSDimitry Andric dfsan_set_label(c_label, s, n); 59768d75effSDimitry Andric } 59868d75effSDimitry Andric 599fe6060f1SDimitry Andric static void dfsan_memset_with_origin(void *s, int c, dfsan_label c_label, 600fe6060f1SDimitry Andric dfsan_origin c_origin, size_t n) { 601fe6060f1SDimitry Andric internal_memset(s, c, n); 602fe6060f1SDimitry Andric dfsan_set_label_origin(c_label, c_origin, s, n); 603fe6060f1SDimitry Andric } 604fe6060f1SDimitry Andric 60568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 60668d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n, 60768d75effSDimitry Andric dfsan_label dest_label, dfsan_label src_label, 60868d75effSDimitry Andric dfsan_label n_label, dfsan_label *ret_label) { 60968d75effSDimitry Andric *ret_label = dest_label; 61068d75effSDimitry Andric return dfsan_memcpy(dest, src, n); 61168d75effSDimitry Andric } 61268d75effSDimitry Andric 61368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 614fe6060f1SDimitry Andric void *__dfso_memcpy(void *dest, const void *src, size_t n, 615fe6060f1SDimitry Andric dfsan_label dest_label, dfsan_label src_label, 616fe6060f1SDimitry Andric dfsan_label n_label, dfsan_label *ret_label, 617fe6060f1SDimitry Andric dfsan_origin dest_origin, dfsan_origin src_origin, 618fe6060f1SDimitry Andric dfsan_origin n_origin, dfsan_origin *ret_origin) { 619fe6060f1SDimitry Andric *ret_label = dest_label; 620fe6060f1SDimitry Andric *ret_origin = dest_origin; 621fe6060f1SDimitry Andric return dfsan_memcpy_with_origin(dest, src, n); 622fe6060f1SDimitry Andric } 623fe6060f1SDimitry Andric 624fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 625fe6060f1SDimitry Andric void *__dfsw_memmove(void *dest, const void *src, size_t n, 626fe6060f1SDimitry Andric dfsan_label dest_label, dfsan_label src_label, 627fe6060f1SDimitry Andric dfsan_label n_label, dfsan_label *ret_label) { 628fe6060f1SDimitry Andric *ret_label = dest_label; 629fe6060f1SDimitry Andric return dfsan_memmove(dest, src, n); 630fe6060f1SDimitry Andric } 631fe6060f1SDimitry Andric 632fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 633fe6060f1SDimitry Andric void *__dfso_memmove(void *dest, const void *src, size_t n, 634fe6060f1SDimitry Andric dfsan_label dest_label, dfsan_label src_label, 635fe6060f1SDimitry Andric dfsan_label n_label, dfsan_label *ret_label, 636fe6060f1SDimitry Andric dfsan_origin dest_origin, dfsan_origin src_origin, 637fe6060f1SDimitry Andric dfsan_origin n_origin, dfsan_origin *ret_origin) { 638fe6060f1SDimitry Andric *ret_label = dest_label; 639fe6060f1SDimitry Andric *ret_origin = dest_origin; 640fe6060f1SDimitry Andric return dfsan_memmove_with_origin(dest, src, n); 641fe6060f1SDimitry Andric } 642fe6060f1SDimitry Andric 643fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 64468d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n, 64568d75effSDimitry Andric dfsan_label s_label, dfsan_label c_label, 64668d75effSDimitry Andric dfsan_label n_label, dfsan_label *ret_label) { 64768d75effSDimitry Andric dfsan_memset(s, c, c_label, n); 64868d75effSDimitry Andric *ret_label = s_label; 64968d75effSDimitry Andric return s; 65068d75effSDimitry Andric } 65168d75effSDimitry Andric 652fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 653fe6060f1SDimitry Andric void *__dfso_memset(void *s, int c, size_t n, dfsan_label s_label, 654fe6060f1SDimitry Andric dfsan_label c_label, dfsan_label n_label, 655fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin s_origin, 656fe6060f1SDimitry Andric dfsan_origin c_origin, dfsan_origin n_origin, 657fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 658fe6060f1SDimitry Andric dfsan_memset_with_origin(s, c, c_label, c_origin, n); 659fe6060f1SDimitry Andric *ret_label = s_label; 660fe6060f1SDimitry Andric *ret_origin = s_origin; 661fe6060f1SDimitry Andric return s; 662fe6060f1SDimitry Andric } 663fe6060f1SDimitry Andric 664fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src, 665fe6060f1SDimitry Andric dfsan_label dest_label, 666fe6060f1SDimitry Andric dfsan_label src_label, 667fe6060f1SDimitry Andric dfsan_label *ret_label) { 668fe6060f1SDimitry Andric size_t dest_len = strlen(dest); 669349cc55cSDimitry Andric char *ret = strcat(dest, src); 67004eeddc0SDimitry Andric dfsan_mem_shadow_transfer(dest + dest_len, src, strlen(src)); 671fe6060f1SDimitry Andric *ret_label = dest_label; 672fe6060f1SDimitry Andric return ret; 673fe6060f1SDimitry Andric } 674fe6060f1SDimitry Andric 675fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat( 676fe6060f1SDimitry Andric char *dest, const char *src, dfsan_label dest_label, dfsan_label src_label, 677fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin, 678fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 679fe6060f1SDimitry Andric size_t dest_len = strlen(dest); 680349cc55cSDimitry Andric char *ret = strcat(dest, src); 681fe6060f1SDimitry Andric size_t src_len = strlen(src); 682fe6060f1SDimitry Andric dfsan_mem_origin_transfer(dest + dest_len, src, src_len); 68304eeddc0SDimitry Andric dfsan_mem_shadow_transfer(dest + dest_len, src, src_len); 684fe6060f1SDimitry Andric *ret_label = dest_label; 685fe6060f1SDimitry Andric *ret_origin = dest_origin; 686fe6060f1SDimitry Andric return ret; 687fe6060f1SDimitry Andric } 688fe6060f1SDimitry Andric 68906c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strncat( 69006c3fb27SDimitry Andric char *dest, const char *src, size_t num, dfsan_label dest_label, 69106c3fb27SDimitry Andric dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label) { 69206c3fb27SDimitry Andric size_t src_len = strlen(src); 69306c3fb27SDimitry Andric src_len = src_len < num ? src_len : num; 69406c3fb27SDimitry Andric size_t dest_len = strlen(dest); 69506c3fb27SDimitry Andric 69606c3fb27SDimitry Andric char *ret = strncat(dest, src, num); 69706c3fb27SDimitry Andric dfsan_mem_shadow_transfer(dest + dest_len, src, src_len); 69806c3fb27SDimitry Andric *ret_label = dest_label; 69906c3fb27SDimitry Andric return ret; 70006c3fb27SDimitry Andric } 70106c3fb27SDimitry Andric 70206c3fb27SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncat( 70306c3fb27SDimitry Andric char *dest, const char *src, size_t num, dfsan_label dest_label, 70406c3fb27SDimitry Andric dfsan_label src_label, dfsan_label num_label, dfsan_label *ret_label, 70506c3fb27SDimitry Andric dfsan_origin dest_origin, dfsan_origin src_origin, dfsan_origin num_origin, 70606c3fb27SDimitry Andric dfsan_origin *ret_origin) { 70706c3fb27SDimitry Andric size_t src_len = strlen(src); 70806c3fb27SDimitry Andric src_len = src_len < num ? src_len : num; 70906c3fb27SDimitry Andric size_t dest_len = strlen(dest); 71006c3fb27SDimitry Andric 71106c3fb27SDimitry Andric char *ret = strncat(dest, src, num); 71206c3fb27SDimitry Andric 71306c3fb27SDimitry Andric dfsan_mem_origin_transfer(dest + dest_len, src, src_len); 71406c3fb27SDimitry Andric dfsan_mem_shadow_transfer(dest + dest_len, src, src_len); 71506c3fb27SDimitry Andric *ret_label = dest_label; 71606c3fb27SDimitry Andric *ret_origin = dest_origin; 71706c3fb27SDimitry Andric return ret; 71806c3fb27SDimitry Andric } 71906c3fb27SDimitry Andric 72068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char * 72168d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) { 72268d75effSDimitry Andric size_t len = strlen(s); 72368d75effSDimitry Andric void *p = malloc(len+1); 72468d75effSDimitry Andric dfsan_memcpy(p, s, len+1); 72568d75effSDimitry Andric *ret_label = 0; 72668d75effSDimitry Andric return static_cast<char *>(p); 72768d75effSDimitry Andric } 72868d75effSDimitry Andric 729fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strdup(const char *s, 730fe6060f1SDimitry Andric dfsan_label s_label, 731fe6060f1SDimitry Andric dfsan_label *ret_label, 732fe6060f1SDimitry Andric dfsan_origin s_origin, 733fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 734fe6060f1SDimitry Andric size_t len = strlen(s); 735fe6060f1SDimitry Andric void *p = malloc(len + 1); 736fe6060f1SDimitry Andric dfsan_memcpy_with_origin(p, s, len + 1); 737fe6060f1SDimitry Andric *ret_label = 0; 738fe6060f1SDimitry Andric return static_cast<char *>(p); 739fe6060f1SDimitry Andric } 740fe6060f1SDimitry Andric 74168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char * 74268d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label, 74368d75effSDimitry Andric dfsan_label s2_label, dfsan_label n_label, 74468d75effSDimitry Andric dfsan_label *ret_label) { 74568d75effSDimitry Andric size_t len = strlen(s2); 74668d75effSDimitry Andric if (len < n) { 74768d75effSDimitry Andric dfsan_memcpy(s1, s2, len+1); 74868d75effSDimitry Andric dfsan_memset(s1+len+1, 0, 0, n-len-1); 74968d75effSDimitry Andric } else { 75068d75effSDimitry Andric dfsan_memcpy(s1, s2, n); 75168d75effSDimitry Andric } 75268d75effSDimitry Andric 75368d75effSDimitry Andric *ret_label = s1_label; 75468d75effSDimitry Andric return s1; 75568d75effSDimitry Andric } 75668d75effSDimitry Andric 757fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strncpy( 758fe6060f1SDimitry Andric char *s1, const char *s2, size_t n, dfsan_label s1_label, 759fe6060f1SDimitry Andric dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label, 760fe6060f1SDimitry Andric dfsan_origin s1_origin, dfsan_origin s2_origin, dfsan_origin n_origin, 761fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 762fe6060f1SDimitry Andric size_t len = strlen(s2); 763fe6060f1SDimitry Andric if (len < n) { 764fe6060f1SDimitry Andric dfsan_memcpy_with_origin(s1, s2, len + 1); 765fe6060f1SDimitry Andric dfsan_memset_with_origin(s1 + len + 1, 0, 0, 0, n - len - 1); 766fe6060f1SDimitry Andric } else { 767fe6060f1SDimitry Andric dfsan_memcpy_with_origin(s1, s2, n); 768fe6060f1SDimitry Andric } 769fe6060f1SDimitry Andric 770fe6060f1SDimitry Andric *ret_label = s1_label; 771fe6060f1SDimitry Andric *ret_origin = s1_origin; 772fe6060f1SDimitry Andric return s1; 773fe6060f1SDimitry Andric } 774fe6060f1SDimitry Andric 77568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t 77668d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset, 77768d75effSDimitry Andric dfsan_label fd_label, dfsan_label buf_label, 77868d75effSDimitry Andric dfsan_label count_label, dfsan_label offset_label, 77968d75effSDimitry Andric dfsan_label *ret_label) { 78068d75effSDimitry Andric ssize_t ret = pread(fd, buf, count, offset); 78168d75effSDimitry Andric if (ret > 0) 78268d75effSDimitry Andric dfsan_set_label(0, buf, ret); 78368d75effSDimitry Andric *ret_label = 0; 78468d75effSDimitry Andric return ret; 78568d75effSDimitry Andric } 78668d75effSDimitry Andric 787fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_pread( 788fe6060f1SDimitry Andric int fd, void *buf, size_t count, off_t offset, dfsan_label fd_label, 789fe6060f1SDimitry Andric dfsan_label buf_label, dfsan_label count_label, dfsan_label offset_label, 790fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin fd_origin, dfsan_origin buf_origin, 791fe6060f1SDimitry Andric dfsan_origin count_origin, dfsan_label offset_origin, 792fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 793fe6060f1SDimitry Andric return __dfsw_pread(fd, buf, count, offset, fd_label, buf_label, count_label, 794fe6060f1SDimitry Andric offset_label, ret_label); 795fe6060f1SDimitry Andric } 796fe6060f1SDimitry Andric 79768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t 79868d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count, 79968d75effSDimitry Andric dfsan_label fd_label, dfsan_label buf_label, 80068d75effSDimitry Andric dfsan_label count_label, 80168d75effSDimitry Andric dfsan_label *ret_label) { 80268d75effSDimitry Andric ssize_t ret = read(fd, buf, count); 80368d75effSDimitry Andric if (ret > 0) 80468d75effSDimitry Andric dfsan_set_label(0, buf, ret); 80568d75effSDimitry Andric *ret_label = 0; 80668d75effSDimitry Andric return ret; 80768d75effSDimitry Andric } 80868d75effSDimitry Andric 809fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_read( 810fe6060f1SDimitry Andric int fd, void *buf, size_t count, dfsan_label fd_label, 811fe6060f1SDimitry Andric dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label, 812fe6060f1SDimitry Andric dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin, 813fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 814fe6060f1SDimitry Andric return __dfsw_read(fd, buf, count, fd_label, buf_label, count_label, 815fe6060f1SDimitry Andric ret_label); 816fe6060f1SDimitry Andric } 817fe6060f1SDimitry Andric 81868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id, 81968d75effSDimitry Andric struct timespec *tp, 82068d75effSDimitry Andric dfsan_label clk_id_label, 82168d75effSDimitry Andric dfsan_label tp_label, 82268d75effSDimitry Andric dfsan_label *ret_label) { 82368d75effSDimitry Andric int ret = clock_gettime(clk_id, tp); 82468d75effSDimitry Andric if (ret == 0) 82568d75effSDimitry Andric dfsan_set_label(0, tp, sizeof(struct timespec)); 82668d75effSDimitry Andric *ret_label = 0; 82768d75effSDimitry Andric return ret; 82868d75effSDimitry Andric } 82968d75effSDimitry Andric 830fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_clock_gettime( 831fe6060f1SDimitry Andric clockid_t clk_id, struct timespec *tp, dfsan_label clk_id_label, 832fe6060f1SDimitry Andric dfsan_label tp_label, dfsan_label *ret_label, dfsan_origin clk_id_origin, 833fe6060f1SDimitry Andric dfsan_origin tp_origin, dfsan_origin *ret_origin) { 834fe6060f1SDimitry Andric return __dfsw_clock_gettime(clk_id, tp, clk_id_label, tp_label, ret_label); 835fe6060f1SDimitry Andric } 836fe6060f1SDimitry Andric 837fe6060f1SDimitry Andric static void dfsan_set_zero_label(const void *ptr, uptr size) { 83868d75effSDimitry Andric dfsan_set_label(0, const_cast<void *>(ptr), size); 83968d75effSDimitry Andric } 84068d75effSDimitry Andric 84168d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally 84268d75effSDimitry Andric // doesn't participate in dynamic symbol resolution. Therefore we won't 84368d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here. 84468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void * 84568d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label, 84668d75effSDimitry Andric dfsan_label flag_label, dfsan_label *ret_label) { 84768d75effSDimitry Andric void *handle = dlopen(filename, flag); 84868d75effSDimitry Andric link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle); 8497a6dacacSDimitry Andric if (filename && map) 850fe6060f1SDimitry Andric ForEachMappedRegion(map, dfsan_set_zero_label); 85168d75effSDimitry Andric *ret_label = 0; 85268d75effSDimitry Andric return handle; 85368d75effSDimitry Andric } 85468d75effSDimitry Andric 855fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen( 856fe6060f1SDimitry Andric const char *filename, int flag, dfsan_label filename_label, 857fe6060f1SDimitry Andric dfsan_label flag_label, dfsan_label *ret_label, 858fe6060f1SDimitry Andric dfsan_origin filename_origin, dfsan_origin flag_origin, 859fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 860fe6060f1SDimitry Andric return __dfsw_dlopen(filename, flag, filename_label, flag_label, ret_label); 861fe6060f1SDimitry Andric } 86268d75effSDimitry Andric 863fe6060f1SDimitry Andric static void *DFsanThreadStartFunc(void *arg) { 864fe6060f1SDimitry Andric DFsanThread *t = (DFsanThread *)arg; 865fe6060f1SDimitry Andric SetCurrentThread(t); 866349cc55cSDimitry Andric t->Init(); 867349cc55cSDimitry Andric SetSigProcMask(&t->starting_sigset_, nullptr); 868fe6060f1SDimitry Andric return t->ThreadStart(); 869fe6060f1SDimitry Andric } 870fe6060f1SDimitry Andric 871fe6060f1SDimitry Andric static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr, 872fe6060f1SDimitry Andric void *start_routine, void *arg, 873fe6060f1SDimitry Andric dfsan_label *ret_label, 874fe6060f1SDimitry Andric bool track_origins = false) { 875fe6060f1SDimitry Andric pthread_attr_t myattr; 876fe6060f1SDimitry Andric if (!attr) { 877fe6060f1SDimitry Andric pthread_attr_init(&myattr); 878fe6060f1SDimitry Andric attr = &myattr; 879fe6060f1SDimitry Andric } 880fe6060f1SDimitry Andric 881fe6060f1SDimitry Andric // Ensure that the thread stack is large enough to hold all TLS data. 882fe6060f1SDimitry Andric AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr))); 883fe6060f1SDimitry Andric 884fe6060f1SDimitry Andric DFsanThread *t = 88581ad6265SDimitry Andric DFsanThread::Create((thread_callback_t)start_routine, arg, track_origins); 886349cc55cSDimitry Andric ScopedBlockSignals block(&t->starting_sigset_); 887fe6060f1SDimitry Andric int res = pthread_create(thread, attr, DFsanThreadStartFunc, t); 888fe6060f1SDimitry Andric 889fe6060f1SDimitry Andric if (attr == &myattr) 890fe6060f1SDimitry Andric pthread_attr_destroy(&myattr); 891fe6060f1SDimitry Andric *ret_label = 0; 892fe6060f1SDimitry Andric return res; 89368d75effSDimitry Andric } 89468d75effSDimitry Andric 89568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create( 89681ad6265SDimitry Andric pthread_t *thread, const pthread_attr_t *attr, void *start_routine, 89781ad6265SDimitry Andric void *arg, dfsan_label thread_label, dfsan_label attr_label, 89881ad6265SDimitry Andric dfsan_label start_routine_label, dfsan_label arg_label, 89981ad6265SDimitry Andric dfsan_label *ret_label) { 90081ad6265SDimitry Andric return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label); 901fe6060f1SDimitry Andric } 902fe6060f1SDimitry Andric 903fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create( 90481ad6265SDimitry Andric pthread_t *thread, const pthread_attr_t *attr, void *start_routine, 90581ad6265SDimitry Andric void *arg, dfsan_label thread_label, dfsan_label attr_label, 90681ad6265SDimitry Andric dfsan_label start_routine_label, dfsan_label arg_label, 90781ad6265SDimitry Andric dfsan_label *ret_label, dfsan_origin thread_origin, 908fe6060f1SDimitry Andric dfsan_origin attr_origin, dfsan_origin start_routine_origin, 909fe6060f1SDimitry Andric dfsan_origin arg_origin, dfsan_origin *ret_origin) { 91081ad6265SDimitry Andric return dfsan_pthread_create(thread, attr, start_routine, arg, ret_label, 91181ad6265SDimitry Andric true); 91268d75effSDimitry Andric } 91368d75effSDimitry Andric 914e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread, 915e8d8bef9SDimitry Andric void **retval, 916e8d8bef9SDimitry Andric dfsan_label thread_label, 917e8d8bef9SDimitry Andric dfsan_label retval_label, 918e8d8bef9SDimitry Andric dfsan_label *ret_label) { 919e8d8bef9SDimitry Andric int ret = pthread_join(thread, retval); 920e8d8bef9SDimitry Andric if (ret == 0 && retval) 921e8d8bef9SDimitry Andric dfsan_set_label(0, retval, sizeof(*retval)); 922e8d8bef9SDimitry Andric *ret_label = 0; 923e8d8bef9SDimitry Andric return ret; 924e8d8bef9SDimitry Andric } 925e8d8bef9SDimitry Andric 926fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join( 927fe6060f1SDimitry Andric pthread_t thread, void **retval, dfsan_label thread_label, 928fe6060f1SDimitry Andric dfsan_label retval_label, dfsan_label *ret_label, 929fe6060f1SDimitry Andric dfsan_origin thread_origin, dfsan_origin retval_origin, 930fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 931fe6060f1SDimitry Andric return __dfsw_pthread_join(thread, retval, thread_label, retval_label, 932fe6060f1SDimitry Andric ret_label); 933fe6060f1SDimitry Andric } 934fe6060f1SDimitry Andric 93568d75effSDimitry Andric struct dl_iterate_phdr_info { 93681ad6265SDimitry Andric int (*callback)(struct dl_phdr_info *info, size_t size, void *data); 937fe6060f1SDimitry Andric void *data; 938fe6060f1SDimitry Andric }; 939fe6060f1SDimitry Andric 94068d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) { 94168d75effSDimitry Andric dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data; 94268d75effSDimitry Andric dfsan_set_label(0, *info); 94368d75effSDimitry Andric dfsan_set_label(0, const_cast<char *>(info->dlpi_name), 94468d75effSDimitry Andric strlen(info->dlpi_name) + 1); 94568d75effSDimitry Andric dfsan_set_label( 94668d75effSDimitry Andric 0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)), 94768d75effSDimitry Andric sizeof(*info->dlpi_phdr) * info->dlpi_phnum); 94868d75effSDimitry Andric 94981ad6265SDimitry Andric dfsan_clear_thread_local_state(); 95081ad6265SDimitry Andric return dipi->callback(info, size, dipi->data); 951fe6060f1SDimitry Andric } 952fe6060f1SDimitry Andric 95368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr( 95481ad6265SDimitry Andric int (*callback)(struct dl_phdr_info *info, size_t size, void *data), 95581ad6265SDimitry Andric void *data, dfsan_label callback_label, dfsan_label data_label, 95681ad6265SDimitry Andric dfsan_label *ret_label) { 95781ad6265SDimitry Andric dl_iterate_phdr_info dipi = {callback, data}; 95868d75effSDimitry Andric *ret_label = 0; 95968d75effSDimitry Andric return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi); 96068d75effSDimitry Andric } 96168d75effSDimitry Andric 962fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_dl_iterate_phdr( 96381ad6265SDimitry Andric int (*callback)(struct dl_phdr_info *info, size_t size, void *data), 96481ad6265SDimitry Andric void *data, dfsan_label callback_label, dfsan_label data_label, 96581ad6265SDimitry Andric dfsan_label *ret_label, dfsan_origin callback_origin, 96681ad6265SDimitry Andric dfsan_origin data_origin, dfsan_origin *ret_origin) { 96781ad6265SDimitry Andric dl_iterate_phdr_info dipi = {callback, data}; 968fe6060f1SDimitry Andric *ret_label = 0; 96981ad6265SDimitry Andric return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi); 970fe6060f1SDimitry Andric } 971fe6060f1SDimitry Andric 972e8d8bef9SDimitry Andric // This function is only available for glibc 2.27 or newer. Mark it weak so 973e8d8bef9SDimitry Andric // linking succeeds with older glibcs. 974e8d8bef9SDimitry Andric SANITIZER_WEAK_ATTRIBUTE void _dl_get_tls_static_info(size_t *sizep, 975e8d8bef9SDimitry Andric size_t *alignp); 976e8d8bef9SDimitry Andric 977e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw__dl_get_tls_static_info( 978e8d8bef9SDimitry Andric size_t *sizep, size_t *alignp, dfsan_label sizep_label, 979e8d8bef9SDimitry Andric dfsan_label alignp_label) { 980e8d8bef9SDimitry Andric assert(_dl_get_tls_static_info); 981e8d8bef9SDimitry Andric _dl_get_tls_static_info(sizep, alignp); 982e8d8bef9SDimitry Andric dfsan_set_label(0, sizep, sizeof(*sizep)); 983e8d8bef9SDimitry Andric dfsan_set_label(0, alignp, sizeof(*alignp)); 984e8d8bef9SDimitry Andric } 985e8d8bef9SDimitry Andric 986fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso__dl_get_tls_static_info( 987fe6060f1SDimitry Andric size_t *sizep, size_t *alignp, dfsan_label sizep_label, 988fe6060f1SDimitry Andric dfsan_label alignp_label, dfsan_origin sizep_origin, 989fe6060f1SDimitry Andric dfsan_origin alignp_origin) { 990fe6060f1SDimitry Andric __dfsw__dl_get_tls_static_info(sizep, alignp, sizep_label, alignp_label); 991fe6060f1SDimitry Andric } 992fe6060f1SDimitry Andric 99368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 99468d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label, 99568d75effSDimitry Andric dfsan_label buf_label, dfsan_label *ret_label) { 99668d75effSDimitry Andric char *ret = ctime_r(timep, buf); 99768d75effSDimitry Andric if (ret) { 99868d75effSDimitry Andric dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf, 99968d75effSDimitry Andric strlen(buf) + 1); 100068d75effSDimitry Andric *ret_label = buf_label; 100168d75effSDimitry Andric } else { 100268d75effSDimitry Andric *ret_label = 0; 100368d75effSDimitry Andric } 100468d75effSDimitry Andric return ret; 100568d75effSDimitry Andric } 100668d75effSDimitry Andric 100768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1008fe6060f1SDimitry Andric char *__dfso_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label, 1009fe6060f1SDimitry Andric dfsan_label buf_label, dfsan_label *ret_label, 1010fe6060f1SDimitry Andric dfsan_origin timep_origin, dfsan_origin buf_origin, 1011fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1012fe6060f1SDimitry Andric char *ret = ctime_r(timep, buf); 1013fe6060f1SDimitry Andric if (ret) { 1014fe6060f1SDimitry Andric dfsan_set_label_origin( 1015fe6060f1SDimitry Andric dfsan_read_label(timep, sizeof(time_t)), 1016fe6060f1SDimitry Andric dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), buf, 1017fe6060f1SDimitry Andric strlen(buf) + 1); 1018fe6060f1SDimitry Andric *ret_label = buf_label; 1019fe6060f1SDimitry Andric *ret_origin = buf_origin; 1020fe6060f1SDimitry Andric } else { 1021fe6060f1SDimitry Andric *ret_label = 0; 1022fe6060f1SDimitry Andric } 1023fe6060f1SDimitry Andric return ret; 1024fe6060f1SDimitry Andric } 1025fe6060f1SDimitry Andric 1026fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 102768d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label, 102868d75effSDimitry Andric dfsan_label size_label, dfsan_label stream_label, 102968d75effSDimitry Andric dfsan_label *ret_label) { 103068d75effSDimitry Andric char *ret = fgets(s, size, stream); 103168d75effSDimitry Andric if (ret) { 103268d75effSDimitry Andric dfsan_set_label(0, ret, strlen(ret) + 1); 103368d75effSDimitry Andric *ret_label = s_label; 103468d75effSDimitry Andric } else { 103568d75effSDimitry Andric *ret_label = 0; 103668d75effSDimitry Andric } 103768d75effSDimitry Andric return ret; 103868d75effSDimitry Andric } 103968d75effSDimitry Andric 104068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1041fe6060f1SDimitry Andric char *__dfso_fgets(char *s, int size, FILE *stream, dfsan_label s_label, 1042fe6060f1SDimitry Andric dfsan_label size_label, dfsan_label stream_label, 1043fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin s_origin, 1044fe6060f1SDimitry Andric dfsan_origin size_origin, dfsan_origin stream_origin, 1045fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1046fe6060f1SDimitry Andric char *ret = __dfsw_fgets(s, size, stream, s_label, size_label, stream_label, 1047fe6060f1SDimitry Andric ret_label); 1048fe6060f1SDimitry Andric if (ret) 1049fe6060f1SDimitry Andric *ret_origin = s_origin; 1050fe6060f1SDimitry Andric return ret; 1051fe6060f1SDimitry Andric } 1052fe6060f1SDimitry Andric 1053fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 105468d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label, 105568d75effSDimitry Andric dfsan_label size_label, dfsan_label *ret_label) { 105668d75effSDimitry Andric char *ret = getcwd(buf, size); 105768d75effSDimitry Andric if (ret) { 105868d75effSDimitry Andric dfsan_set_label(0, ret, strlen(ret) + 1); 105968d75effSDimitry Andric *ret_label = buf_label; 106068d75effSDimitry Andric } else { 106168d75effSDimitry Andric *ret_label = 0; 106268d75effSDimitry Andric } 106368d75effSDimitry Andric return ret; 106468d75effSDimitry Andric } 106568d75effSDimitry Andric 106668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1067fe6060f1SDimitry Andric char *__dfso_getcwd(char *buf, size_t size, dfsan_label buf_label, 1068fe6060f1SDimitry Andric dfsan_label size_label, dfsan_label *ret_label, 1069fe6060f1SDimitry Andric dfsan_origin buf_origin, dfsan_origin size_origin, 1070fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1071fe6060f1SDimitry Andric char *ret = __dfsw_getcwd(buf, size, buf_label, size_label, ret_label); 1072fe6060f1SDimitry Andric if (ret) 1073fe6060f1SDimitry Andric *ret_origin = buf_origin; 1074fe6060f1SDimitry Andric return ret; 1075fe6060f1SDimitry Andric } 1076fe6060f1SDimitry Andric 1077fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 107868d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) { 107968d75effSDimitry Andric char *ret = get_current_dir_name(); 1080fe6060f1SDimitry Andric if (ret) 108168d75effSDimitry Andric dfsan_set_label(0, ret, strlen(ret) + 1); 108268d75effSDimitry Andric *ret_label = 0; 108368d75effSDimitry Andric return ret; 108468d75effSDimitry Andric } 108568d75effSDimitry Andric 108668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1087fe6060f1SDimitry Andric char *__dfso_get_current_dir_name(dfsan_label *ret_label, 1088fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1089fe6060f1SDimitry Andric return __dfsw_get_current_dir_name(ret_label); 1090fe6060f1SDimitry Andric } 1091fe6060f1SDimitry Andric 1092349cc55cSDimitry Andric // This function is only available for glibc 2.25 or newer. Mark it weak so 1093349cc55cSDimitry Andric // linking succeeds with older glibcs. 1094349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length); 1095349cc55cSDimitry Andric 1096349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length, 1097349cc55cSDimitry Andric dfsan_label buffer_label, 1098349cc55cSDimitry Andric dfsan_label length_label, 1099349cc55cSDimitry Andric dfsan_label *ret_label) { 1100349cc55cSDimitry Andric int ret = getentropy(buffer, length); 1101349cc55cSDimitry Andric if (ret == 0) { 1102349cc55cSDimitry Andric dfsan_set_label(0, buffer, length); 1103349cc55cSDimitry Andric } 1104349cc55cSDimitry Andric *ret_label = 0; 1105349cc55cSDimitry Andric return ret; 1106349cc55cSDimitry Andric } 1107349cc55cSDimitry Andric 1108349cc55cSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length, 1109349cc55cSDimitry Andric dfsan_label buffer_label, 1110349cc55cSDimitry Andric dfsan_label length_label, 1111349cc55cSDimitry Andric dfsan_label *ret_label, 1112349cc55cSDimitry Andric dfsan_origin buffer_origin, 1113349cc55cSDimitry Andric dfsan_origin length_origin, 1114349cc55cSDimitry Andric dfsan_origin *ret_origin) { 1115349cc55cSDimitry Andric return __dfsw_getentropy(buffer, length, buffer_label, length_label, 1116349cc55cSDimitry Andric ret_label); 1117349cc55cSDimitry Andric } 1118349cc55cSDimitry Andric 1119fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 112068d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label, 112168d75effSDimitry Andric dfsan_label len_label, dfsan_label *ret_label) { 112268d75effSDimitry Andric int ret = gethostname(name, len); 112368d75effSDimitry Andric if (ret == 0) { 112468d75effSDimitry Andric dfsan_set_label(0, name, strlen(name) + 1); 112568d75effSDimitry Andric } 112668d75effSDimitry Andric *ret_label = 0; 112768d75effSDimitry Andric return ret; 112868d75effSDimitry Andric } 112968d75effSDimitry Andric 113068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1131fe6060f1SDimitry Andric int __dfso_gethostname(char *name, size_t len, dfsan_label name_label, 1132fe6060f1SDimitry Andric dfsan_label len_label, dfsan_label *ret_label, 1133fe6060f1SDimitry Andric dfsan_origin name_origin, dfsan_origin len_origin, 1134fe6060f1SDimitry Andric dfsan_label *ret_origin) { 1135fe6060f1SDimitry Andric return __dfsw_gethostname(name, len, name_label, len_label, ret_label); 1136fe6060f1SDimitry Andric } 1137fe6060f1SDimitry Andric 1138fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 113968d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim, 114068d75effSDimitry Andric dfsan_label resource_label, dfsan_label rlim_label, 114168d75effSDimitry Andric dfsan_label *ret_label) { 114268d75effSDimitry Andric int ret = getrlimit(resource, rlim); 114368d75effSDimitry Andric if (ret == 0) { 114468d75effSDimitry Andric dfsan_set_label(0, rlim, sizeof(struct rlimit)); 114568d75effSDimitry Andric } 114668d75effSDimitry Andric *ret_label = 0; 114768d75effSDimitry Andric return ret; 114868d75effSDimitry Andric } 114968d75effSDimitry Andric 115068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1151fe6060f1SDimitry Andric int __dfso_getrlimit(int resource, struct rlimit *rlim, 1152fe6060f1SDimitry Andric dfsan_label resource_label, dfsan_label rlim_label, 1153fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin resource_origin, 1154fe6060f1SDimitry Andric dfsan_origin rlim_origin, dfsan_origin *ret_origin) { 1155fe6060f1SDimitry Andric return __dfsw_getrlimit(resource, rlim, resource_label, rlim_label, 1156fe6060f1SDimitry Andric ret_label); 1157fe6060f1SDimitry Andric } 1158fe6060f1SDimitry Andric 1159fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 116068d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label, 116168d75effSDimitry Andric dfsan_label usage_label, dfsan_label *ret_label) { 116268d75effSDimitry Andric int ret = getrusage(who, usage); 116368d75effSDimitry Andric if (ret == 0) { 116468d75effSDimitry Andric dfsan_set_label(0, usage, sizeof(struct rusage)); 116568d75effSDimitry Andric } 116668d75effSDimitry Andric *ret_label = 0; 116768d75effSDimitry Andric return ret; 116868d75effSDimitry Andric } 116968d75effSDimitry Andric 117068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1171fe6060f1SDimitry Andric int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label, 1172fe6060f1SDimitry Andric dfsan_label usage_label, dfsan_label *ret_label, 1173fe6060f1SDimitry Andric dfsan_origin who_origin, dfsan_origin usage_origin, 1174fe6060f1SDimitry Andric dfsan_label *ret_origin) { 1175fe6060f1SDimitry Andric return __dfsw_getrusage(who, usage, who_label, usage_label, ret_label); 1176fe6060f1SDimitry Andric } 1177fe6060f1SDimitry Andric 1178fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 117968d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label, 118068d75effSDimitry Andric dfsan_label src_label, dfsan_label *ret_label) { 1181349cc55cSDimitry Andric char *ret = strcpy(dest, src); 118268d75effSDimitry Andric if (ret) { 118304eeddc0SDimitry Andric dfsan_mem_shadow_transfer(dest, src, strlen(src) + 1); 118468d75effSDimitry Andric } 118568d75effSDimitry Andric *ret_label = dst_label; 118668d75effSDimitry Andric return ret; 118768d75effSDimitry Andric } 118868d75effSDimitry Andric 118968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1190fe6060f1SDimitry Andric char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label, 1191fe6060f1SDimitry Andric dfsan_label src_label, dfsan_label *ret_label, 1192fe6060f1SDimitry Andric dfsan_origin dst_origin, dfsan_origin src_origin, 1193fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1194349cc55cSDimitry Andric char *ret = strcpy(dest, src); 1195fe6060f1SDimitry Andric if (ret) { 1196fe6060f1SDimitry Andric size_t str_len = strlen(src) + 1; 1197fe6060f1SDimitry Andric dfsan_mem_origin_transfer(dest, src, str_len); 119804eeddc0SDimitry Andric dfsan_mem_shadow_transfer(dest, src, str_len); 119968d75effSDimitry Andric } 1200fe6060f1SDimitry Andric *ret_label = dst_label; 1201fe6060f1SDimitry Andric *ret_origin = dst_origin; 1202fe6060f1SDimitry Andric return ret; 1203fe6060f1SDimitry Andric } 1204*74626c16SDimitry Andric } 1205fe6060f1SDimitry Andric 1206*74626c16SDimitry Andric template <typename Fn> 1207*74626c16SDimitry Andric static ALWAYS_INLINE auto dfsan_strtol_impl( 1208*74626c16SDimitry Andric Fn real, const char *nptr, char **endptr, int base, 1209*74626c16SDimitry Andric char **tmp_endptr) -> decltype(real(nullptr, nullptr, 0)) { 1210fe6060f1SDimitry Andric assert(tmp_endptr); 1211*74626c16SDimitry Andric auto ret = real(nptr, tmp_endptr, base); 1212fe6060f1SDimitry Andric if (endptr) 1213fe6060f1SDimitry Andric *endptr = *tmp_endptr; 1214fe6060f1SDimitry Andric return ret; 1215fe6060f1SDimitry Andric } 1216fe6060f1SDimitry Andric 1217*74626c16SDimitry Andric extern "C" { 1218fe6060f1SDimitry Andric static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr, 1219fe6060f1SDimitry Andric dfsan_label base_label, 1220fe6060f1SDimitry Andric dfsan_label *ret_label) { 122168d75effSDimitry Andric if (tmp_endptr > nptr) { 122268d75effSDimitry Andric // If *tmp_endptr is '\0' include its label as well. 122368d75effSDimitry Andric *ret_label = dfsan_union( 122468d75effSDimitry Andric base_label, 122568d75effSDimitry Andric dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1))); 122668d75effSDimitry Andric } else { 122768d75effSDimitry Andric *ret_label = 0; 122868d75effSDimitry Andric } 1229fe6060f1SDimitry Andric } 1230fe6060f1SDimitry Andric 1231fe6060f1SDimitry Andric static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr, 1232fe6060f1SDimitry Andric dfsan_label base_label, 1233fe6060f1SDimitry Andric dfsan_label *ret_label, 1234fe6060f1SDimitry Andric dfsan_origin base_origin, 1235fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1236fe6060f1SDimitry Andric if (tmp_endptr > nptr) { 1237fe6060f1SDimitry Andric // When multiple inputs are tainted, we propagate one of its origins. 1238fe6060f1SDimitry Andric // Because checking if base_label is tainted does not need additional 1239fe6060f1SDimitry Andric // computation, we prefer to propagating base_origin. 1240fe6060f1SDimitry Andric *ret_origin = base_label 1241fe6060f1SDimitry Andric ? base_origin 1242fe6060f1SDimitry Andric : dfsan_read_origin_of_first_taint( 1243fe6060f1SDimitry Andric nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)); 1244fe6060f1SDimitry Andric } 1245fe6060f1SDimitry Andric } 1246fe6060f1SDimitry Andric 1247fe6060f1SDimitry Andric static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) { 1248fe6060f1SDimitry Andric assert(tmp_endptr); 1249fe6060f1SDimitry Andric double ret = strtod(nptr, tmp_endptr); 1250fe6060f1SDimitry Andric if (endptr) 1251fe6060f1SDimitry Andric *endptr = *tmp_endptr; 1252fe6060f1SDimitry Andric return ret; 1253fe6060f1SDimitry Andric } 1254fe6060f1SDimitry Andric 1255fe6060f1SDimitry Andric static void dfsan_strtod_label(const char *nptr, const char *tmp_endptr, 1256fe6060f1SDimitry Andric dfsan_label *ret_label) { 125768d75effSDimitry Andric if (tmp_endptr > nptr) { 125868d75effSDimitry Andric // If *tmp_endptr is '\0' include its label as well. 125968d75effSDimitry Andric *ret_label = dfsan_read_label( 126068d75effSDimitry Andric nptr, 126168d75effSDimitry Andric tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)); 126268d75effSDimitry Andric } else { 126368d75effSDimitry Andric *ret_label = 0; 126468d75effSDimitry Andric } 1265fe6060f1SDimitry Andric } 1266fe6060f1SDimitry Andric 1267fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1268fe6060f1SDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr, dfsan_label nptr_label, 1269fe6060f1SDimitry Andric dfsan_label endptr_label, dfsan_label *ret_label) { 1270fe6060f1SDimitry Andric char *tmp_endptr; 1271fe6060f1SDimitry Andric double ret = dfsan_strtod(nptr, endptr, &tmp_endptr); 1272fe6060f1SDimitry Andric dfsan_strtod_label(nptr, tmp_endptr, ret_label); 1273fe6060f1SDimitry Andric return ret; 1274fe6060f1SDimitry Andric } 1275fe6060f1SDimitry Andric 1276fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1277fe6060f1SDimitry Andric double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label, 1278fe6060f1SDimitry Andric dfsan_label endptr_label, dfsan_label *ret_label, 1279fe6060f1SDimitry Andric dfsan_origin nptr_origin, dfsan_origin endptr_origin, 1280fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1281fe6060f1SDimitry Andric char *tmp_endptr; 1282fe6060f1SDimitry Andric double ret = dfsan_strtod(nptr, endptr, &tmp_endptr); 1283fe6060f1SDimitry Andric dfsan_strtod_label(nptr, tmp_endptr, ret_label); 1284fe6060f1SDimitry Andric if (tmp_endptr > nptr) { 1285fe6060f1SDimitry Andric // If *tmp_endptr is '\0' include its label as well. 1286fe6060f1SDimitry Andric *ret_origin = dfsan_read_origin_of_first_taint( 1287fe6060f1SDimitry Andric nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)); 1288fe6060f1SDimitry Andric } else { 1289fe6060f1SDimitry Andric *ret_origin = 0; 1290fe6060f1SDimitry Andric } 1291fe6060f1SDimitry Andric return ret; 1292fe6060f1SDimitry Andric } 1293fe6060f1SDimitry Andric 1294*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtod, strtod) 1295*74626c16SDimitry Andric 1296*74626c16SDimitry Andric #define WRAPPER_STRTO(ret_type, fun) \ 1297*74626c16SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfsw_##fun( \ 1298*74626c16SDimitry Andric const char *nptr, char **endptr, int base, dfsan_label nptr_label, \ 1299*74626c16SDimitry Andric dfsan_label endptr_label, dfsan_label base_label, \ 1300*74626c16SDimitry Andric dfsan_label *ret_label) { \ 1301*74626c16SDimitry Andric char *tmp_endptr; \ 1302*74626c16SDimitry Andric auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr); \ 1303*74626c16SDimitry Andric dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); \ 1304*74626c16SDimitry Andric return ret; \ 1305*74626c16SDimitry Andric } \ 1306*74626c16SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfso_##fun( \ 1307*74626c16SDimitry Andric const char *nptr, char **endptr, int base, dfsan_label nptr_label, \ 1308*74626c16SDimitry Andric dfsan_label endptr_label, dfsan_label base_label, \ 1309*74626c16SDimitry Andric dfsan_label *ret_label, dfsan_origin nptr_origin, \ 1310*74626c16SDimitry Andric dfsan_origin endptr_origin, dfsan_origin base_origin, \ 1311*74626c16SDimitry Andric dfsan_origin *ret_origin) { \ 1312*74626c16SDimitry Andric char *tmp_endptr; \ 1313*74626c16SDimitry Andric auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr); \ 1314*74626c16SDimitry Andric dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); \ 1315*74626c16SDimitry Andric dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, \ 1316*74626c16SDimitry Andric base_origin, ret_origin); \ 1317*74626c16SDimitry Andric return ret; \ 131868d75effSDimitry Andric } 131968d75effSDimitry Andric 1320*74626c16SDimitry Andric WRAPPER_STRTO(long, strtol) 1321*74626c16SDimitry Andric WRAPPER_STRTO(long long, strtoll) 1322*74626c16SDimitry Andric WRAPPER_STRTO(unsigned long, strtoul) 1323*74626c16SDimitry Andric WRAPPER_STRTO(unsigned long long, strtoull) 1324*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtol, strtol) 1325*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtoll, strtoll) 1326*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtoul, strtoul) 1327*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_strtoull, strtoull) 132868d75effSDimitry Andric 132968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 133068d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) { 133168d75effSDimitry Andric time_t ret = time(t); 133268d75effSDimitry Andric if (ret != (time_t) -1 && t) { 133368d75effSDimitry Andric dfsan_set_label(0, t, sizeof(time_t)); 133468d75effSDimitry Andric } 133568d75effSDimitry Andric *ret_label = 0; 133668d75effSDimitry Andric return ret; 133768d75effSDimitry Andric } 133868d75effSDimitry Andric 133968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1340fe6060f1SDimitry Andric time_t __dfso_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label, 1341fe6060f1SDimitry Andric dfsan_origin t_origin, dfsan_origin *ret_origin) { 1342fe6060f1SDimitry Andric return __dfsw_time(t, t_label, ret_label); 1343fe6060f1SDimitry Andric } 1344fe6060f1SDimitry Andric 1345fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 134668d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label, 134768d75effSDimitry Andric dfsan_label src_label, dfsan_label dst_label, 134868d75effSDimitry Andric dfsan_label *ret_label) { 134968d75effSDimitry Andric int ret = inet_pton(af, src, dst); 135068d75effSDimitry Andric if (ret == 1) { 135168d75effSDimitry Andric dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst, 135268d75effSDimitry Andric af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr)); 135368d75effSDimitry Andric } 135468d75effSDimitry Andric *ret_label = 0; 135568d75effSDimitry Andric return ret; 135668d75effSDimitry Andric } 135768d75effSDimitry Andric 135868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1359fe6060f1SDimitry Andric int __dfso_inet_pton(int af, const char *src, void *dst, dfsan_label af_label, 1360fe6060f1SDimitry Andric dfsan_label src_label, dfsan_label dst_label, 1361fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin af_origin, 1362fe6060f1SDimitry Andric dfsan_origin src_origin, dfsan_origin dst_origin, 1363fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1364fe6060f1SDimitry Andric int ret = inet_pton(af, src, dst); 1365fe6060f1SDimitry Andric if (ret == 1) { 1366fe6060f1SDimitry Andric int src_len = strlen(src) + 1; 1367fe6060f1SDimitry Andric dfsan_set_label_origin( 1368fe6060f1SDimitry Andric dfsan_read_label(src, src_len), 1369fe6060f1SDimitry Andric dfsan_read_origin_of_first_taint(src, src_len), dst, 1370fe6060f1SDimitry Andric af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr)); 1371fe6060f1SDimitry Andric } 1372fe6060f1SDimitry Andric *ret_label = 0; 1373fe6060f1SDimitry Andric return ret; 1374fe6060f1SDimitry Andric } 1375fe6060f1SDimitry Andric 1376fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 137768d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result, 137868d75effSDimitry Andric dfsan_label timep_label, dfsan_label result_label, 137968d75effSDimitry Andric dfsan_label *ret_label) { 138068d75effSDimitry Andric struct tm *ret = localtime_r(timep, result); 138168d75effSDimitry Andric if (ret) { 138268d75effSDimitry Andric dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result, 138368d75effSDimitry Andric sizeof(struct tm)); 138468d75effSDimitry Andric *ret_label = result_label; 138568d75effSDimitry Andric } else { 138668d75effSDimitry Andric *ret_label = 0; 138768d75effSDimitry Andric } 138868d75effSDimitry Andric return ret; 138968d75effSDimitry Andric } 139068d75effSDimitry Andric 139168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1392fe6060f1SDimitry Andric struct tm *__dfso_localtime_r(const time_t *timep, struct tm *result, 1393fe6060f1SDimitry Andric dfsan_label timep_label, dfsan_label result_label, 1394fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin timep_origin, 1395fe6060f1SDimitry Andric dfsan_origin result_origin, 1396fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1397fe6060f1SDimitry Andric struct tm *ret = localtime_r(timep, result); 1398fe6060f1SDimitry Andric if (ret) { 1399fe6060f1SDimitry Andric dfsan_set_label_origin( 1400fe6060f1SDimitry Andric dfsan_read_label(timep, sizeof(time_t)), 1401fe6060f1SDimitry Andric dfsan_read_origin_of_first_taint(timep, sizeof(time_t)), result, 1402fe6060f1SDimitry Andric sizeof(struct tm)); 1403fe6060f1SDimitry Andric *ret_label = result_label; 1404fe6060f1SDimitry Andric *ret_origin = result_origin; 1405fe6060f1SDimitry Andric } else { 1406fe6060f1SDimitry Andric *ret_label = 0; 1407fe6060f1SDimitry Andric } 1408fe6060f1SDimitry Andric return ret; 1409fe6060f1SDimitry Andric } 1410fe6060f1SDimitry Andric 1411fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 141268d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd, 141368d75effSDimitry Andric char *buf, size_t buflen, struct passwd **result, 141468d75effSDimitry Andric dfsan_label uid_label, dfsan_label pwd_label, 141568d75effSDimitry Andric dfsan_label buf_label, dfsan_label buflen_label, 141668d75effSDimitry Andric dfsan_label result_label, dfsan_label *ret_label) { 141768d75effSDimitry Andric // Store the data in pwd, the strings referenced from pwd in buf, and the 141868d75effSDimitry Andric // address of pwd in *result. On failure, NULL is stored in *result. 141968d75effSDimitry Andric int ret = getpwuid_r(uid, pwd, buf, buflen, result); 142068d75effSDimitry Andric if (ret == 0) { 142168d75effSDimitry Andric dfsan_set_label(0, pwd, sizeof(struct passwd)); 142268d75effSDimitry Andric dfsan_set_label(0, buf, strlen(buf) + 1); 142368d75effSDimitry Andric } 142468d75effSDimitry Andric *ret_label = 0; 142568d75effSDimitry Andric dfsan_set_label(0, result, sizeof(struct passwd*)); 142668d75effSDimitry Andric return ret; 142768d75effSDimitry Andric } 142868d75effSDimitry Andric 142968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1430fe6060f1SDimitry Andric int __dfso_getpwuid_r(id_t uid, struct passwd *pwd, char *buf, size_t buflen, 1431fe6060f1SDimitry Andric struct passwd **result, dfsan_label uid_label, 1432fe6060f1SDimitry Andric dfsan_label pwd_label, dfsan_label buf_label, 1433fe6060f1SDimitry Andric dfsan_label buflen_label, dfsan_label result_label, 1434fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin uid_origin, 1435fe6060f1SDimitry Andric dfsan_origin pwd_origin, dfsan_origin buf_origin, 1436fe6060f1SDimitry Andric dfsan_origin buflen_origin, dfsan_origin result_origin, 1437fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1438fe6060f1SDimitry Andric return __dfsw_getpwuid_r(uid, pwd, buf, buflen, result, uid_label, pwd_label, 1439fe6060f1SDimitry Andric buf_label, buflen_label, result_label, ret_label); 1440fe6060f1SDimitry Andric } 1441fe6060f1SDimitry Andric 1442fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1443e8d8bef9SDimitry Andric int __dfsw_epoll_wait(int epfd, struct epoll_event *events, int maxevents, 1444e8d8bef9SDimitry Andric int timeout, dfsan_label epfd_label, 1445e8d8bef9SDimitry Andric dfsan_label events_label, dfsan_label maxevents_label, 1446e8d8bef9SDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label) { 1447e8d8bef9SDimitry Andric int ret = epoll_wait(epfd, events, maxevents, timeout); 1448e8d8bef9SDimitry Andric if (ret > 0) 1449e8d8bef9SDimitry Andric dfsan_set_label(0, events, ret * sizeof(*events)); 1450e8d8bef9SDimitry Andric *ret_label = 0; 1451e8d8bef9SDimitry Andric return ret; 1452e8d8bef9SDimitry Andric } 1453e8d8bef9SDimitry Andric 1454e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1455fe6060f1SDimitry Andric int __dfso_epoll_wait(int epfd, struct epoll_event *events, int maxevents, 1456fe6060f1SDimitry Andric int timeout, dfsan_label epfd_label, 1457fe6060f1SDimitry Andric dfsan_label events_label, dfsan_label maxevents_label, 1458fe6060f1SDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label, 1459fe6060f1SDimitry Andric dfsan_origin epfd_origin, dfsan_origin events_origin, 1460fe6060f1SDimitry Andric dfsan_origin maxevents_origin, 1461fe6060f1SDimitry Andric dfsan_origin timeout_origin, dfsan_origin *ret_origin) { 1462fe6060f1SDimitry Andric return __dfsw_epoll_wait(epfd, events, maxevents, timeout, epfd_label, 1463fe6060f1SDimitry Andric events_label, maxevents_label, timeout_label, 1464fe6060f1SDimitry Andric ret_label); 1465fe6060f1SDimitry Andric } 1466fe6060f1SDimitry Andric 1467fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 146868d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout, 146968d75effSDimitry Andric dfsan_label dfs_label, dfsan_label nfds_label, 147068d75effSDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label) { 147168d75effSDimitry Andric int ret = poll(fds, nfds, timeout); 147268d75effSDimitry Andric if (ret >= 0) { 147368d75effSDimitry Andric for (; nfds > 0; --nfds) { 147468d75effSDimitry Andric dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents)); 147568d75effSDimitry Andric } 147668d75effSDimitry Andric } 147768d75effSDimitry Andric *ret_label = 0; 147868d75effSDimitry Andric return ret; 147968d75effSDimitry Andric } 148068d75effSDimitry Andric 148168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1482fe6060f1SDimitry Andric int __dfso_poll(struct pollfd *fds, nfds_t nfds, int timeout, 1483fe6060f1SDimitry Andric dfsan_label dfs_label, dfsan_label nfds_label, 1484fe6060f1SDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label, 1485fe6060f1SDimitry Andric dfsan_origin dfs_origin, dfsan_origin nfds_origin, 1486fe6060f1SDimitry Andric dfsan_origin timeout_origin, dfsan_origin *ret_origin) { 1487fe6060f1SDimitry Andric return __dfsw_poll(fds, nfds, timeout, dfs_label, nfds_label, timeout_label, 1488fe6060f1SDimitry Andric ret_label); 1489fe6060f1SDimitry Andric } 1490fe6060f1SDimitry Andric 1491fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 149268d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds, 149368d75effSDimitry Andric fd_set *exceptfds, struct timeval *timeout, 149468d75effSDimitry Andric dfsan_label nfds_label, dfsan_label readfds_label, 149568d75effSDimitry Andric dfsan_label writefds_label, dfsan_label exceptfds_label, 149668d75effSDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label) { 149768d75effSDimitry Andric int ret = select(nfds, readfds, writefds, exceptfds, timeout); 149868d75effSDimitry Andric // Clear everything (also on error) since their content is either set or 149968d75effSDimitry Andric // undefined. 150068d75effSDimitry Andric if (readfds) { 150168d75effSDimitry Andric dfsan_set_label(0, readfds, sizeof(fd_set)); 150268d75effSDimitry Andric } 150368d75effSDimitry Andric if (writefds) { 150468d75effSDimitry Andric dfsan_set_label(0, writefds, sizeof(fd_set)); 150568d75effSDimitry Andric } 150668d75effSDimitry Andric if (exceptfds) { 150768d75effSDimitry Andric dfsan_set_label(0, exceptfds, sizeof(fd_set)); 150868d75effSDimitry Andric } 150968d75effSDimitry Andric dfsan_set_label(0, timeout, sizeof(struct timeval)); 151068d75effSDimitry Andric *ret_label = 0; 151168d75effSDimitry Andric return ret; 151268d75effSDimitry Andric } 151368d75effSDimitry Andric 151468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1515fe6060f1SDimitry Andric int __dfso_select(int nfds, fd_set *readfds, fd_set *writefds, 1516fe6060f1SDimitry Andric fd_set *exceptfds, struct timeval *timeout, 1517fe6060f1SDimitry Andric dfsan_label nfds_label, dfsan_label readfds_label, 1518fe6060f1SDimitry Andric dfsan_label writefds_label, dfsan_label exceptfds_label, 1519fe6060f1SDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label, 1520fe6060f1SDimitry Andric dfsan_origin nfds_origin, dfsan_origin readfds_origin, 1521fe6060f1SDimitry Andric dfsan_origin writefds_origin, dfsan_origin exceptfds_origin, 1522fe6060f1SDimitry Andric dfsan_origin timeout_origin, dfsan_origin *ret_origin) { 1523fe6060f1SDimitry Andric return __dfsw_select(nfds, readfds, writefds, exceptfds, timeout, nfds_label, 1524fe6060f1SDimitry Andric readfds_label, writefds_label, exceptfds_label, 1525fe6060f1SDimitry Andric timeout_label, ret_label); 1526fe6060f1SDimitry Andric } 1527fe6060f1SDimitry Andric 1528fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 152968d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask, 153068d75effSDimitry Andric dfsan_label pid_label, 153168d75effSDimitry Andric dfsan_label cpusetsize_label, 153268d75effSDimitry Andric dfsan_label mask_label, dfsan_label *ret_label) { 153368d75effSDimitry Andric int ret = sched_getaffinity(pid, cpusetsize, mask); 153468d75effSDimitry Andric if (ret == 0) { 153568d75effSDimitry Andric dfsan_set_label(0, mask, cpusetsize); 153668d75effSDimitry Andric } 153768d75effSDimitry Andric *ret_label = 0; 153868d75effSDimitry Andric return ret; 153968d75effSDimitry Andric } 154068d75effSDimitry Andric 154168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1542fe6060f1SDimitry Andric int __dfso_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask, 1543fe6060f1SDimitry Andric dfsan_label pid_label, 1544fe6060f1SDimitry Andric dfsan_label cpusetsize_label, 1545fe6060f1SDimitry Andric dfsan_label mask_label, dfsan_label *ret_label, 1546fe6060f1SDimitry Andric dfsan_origin pid_origin, 1547fe6060f1SDimitry Andric dfsan_origin cpusetsize_origin, 1548fe6060f1SDimitry Andric dfsan_origin mask_origin, 1549fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1550fe6060f1SDimitry Andric return __dfsw_sched_getaffinity(pid, cpusetsize, mask, pid_label, 1551fe6060f1SDimitry Andric cpusetsize_label, mask_label, ret_label); 1552fe6060f1SDimitry Andric } 1553fe6060f1SDimitry Andric 1554fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 155568d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label, 155668d75effSDimitry Andric dfsan_label *ret_label) { 155768d75effSDimitry Andric int ret = sigemptyset(set); 155868d75effSDimitry Andric dfsan_set_label(0, set, sizeof(sigset_t)); 1559fe6060f1SDimitry Andric *ret_label = 0; 156068d75effSDimitry Andric return ret; 156168d75effSDimitry Andric } 156268d75effSDimitry Andric 156368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1564fe6060f1SDimitry Andric int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label, 1565fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin set_origin, 1566fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1567fe6060f1SDimitry Andric return __dfsw_sigemptyset(set, set_label, ret_label); 1568fe6060f1SDimitry Andric } 1569fe6060f1SDimitry Andric 1570fe6060f1SDimitry Andric class SignalHandlerScope { 1571fe6060f1SDimitry Andric public: 1572fe6060f1SDimitry Andric SignalHandlerScope() { 1573fe6060f1SDimitry Andric if (DFsanThread *t = GetCurrentThread()) 1574fe6060f1SDimitry Andric t->EnterSignalHandler(); 1575fe6060f1SDimitry Andric } 1576fe6060f1SDimitry Andric ~SignalHandlerScope() { 1577fe6060f1SDimitry Andric if (DFsanThread *t = GetCurrentThread()) 1578fe6060f1SDimitry Andric t->LeaveSignalHandler(); 1579fe6060f1SDimitry Andric } 1580fe6060f1SDimitry Andric }; 1581fe6060f1SDimitry Andric 1582fe6060f1SDimitry Andric // Clear DFSan runtime TLS state at the end of a scope. 1583fe6060f1SDimitry Andric // 1584fe6060f1SDimitry Andric // Implementation must be async-signal-safe and use small data size, because 1585fe6060f1SDimitry Andric // instances of this class may live on the signal handler stack. 1586fe6060f1SDimitry Andric // 1587fe6060f1SDimitry Andric // DFSan uses TLS to pass metadata of arguments and return values. When an 1588fe6060f1SDimitry Andric // instrumented function accesses the TLS, if a signal callback happens, and the 1589fe6060f1SDimitry Andric // callback calls other instrumented functions with updating the same TLS, the 1590fe6060f1SDimitry Andric // TLS is in an inconsistent state after the callback ends. This may cause 1591fe6060f1SDimitry Andric // either under-tainting or over-tainting. 1592fe6060f1SDimitry Andric // 1593fe6060f1SDimitry Andric // The current implementation simply resets TLS at restore. This prevents from 1594fe6060f1SDimitry Andric // over-tainting. Although under-tainting may still happen, a taint flow can be 1595fe6060f1SDimitry Andric // found eventually if we run a DFSan-instrumented program multiple times. The 1596fe6060f1SDimitry Andric // alternative option is saving the entire TLS. However the TLS storage takes 1597fe6060f1SDimitry Andric // 2k bytes, and signal calls could be nested. So it does not seem worth. 1598fe6060f1SDimitry Andric class ScopedClearThreadLocalState { 1599fe6060f1SDimitry Andric public: 1600fe6060f1SDimitry Andric ScopedClearThreadLocalState() {} 1601fe6060f1SDimitry Andric ~ScopedClearThreadLocalState() { dfsan_clear_thread_local_state(); } 1602fe6060f1SDimitry Andric }; 1603fe6060f1SDimitry Andric 1604fe6060f1SDimitry Andric // SignalSpinLocker::sigactions_mu guarantees atomicity of sigaction() calls. 1605fe6060f1SDimitry Andric const int kMaxSignals = 1024; 1606fe6060f1SDimitry Andric static atomic_uintptr_t sigactions[kMaxSignals]; 1607fe6060f1SDimitry Andric 1608fe6060f1SDimitry Andric static void SignalHandler(int signo) { 1609fe6060f1SDimitry Andric SignalHandlerScope signal_handler_scope; 1610fe6060f1SDimitry Andric ScopedClearThreadLocalState scoped_clear_tls; 1611fe6060f1SDimitry Andric 161281ad6265SDimitry Andric // Clear shadows for all inputs provided by system. 1613fe6060f1SDimitry Andric dfsan_clear_arg_tls(0, sizeof(dfsan_label)); 1614fe6060f1SDimitry Andric 1615fe6060f1SDimitry Andric typedef void (*signal_cb)(int x); 1616fe6060f1SDimitry Andric signal_cb cb = 1617fe6060f1SDimitry Andric (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed); 1618fe6060f1SDimitry Andric cb(signo); 1619fe6060f1SDimitry Andric } 1620fe6060f1SDimitry Andric 1621fe6060f1SDimitry Andric static void SignalAction(int signo, siginfo_t *si, void *uc) { 1622fe6060f1SDimitry Andric SignalHandlerScope signal_handler_scope; 1623fe6060f1SDimitry Andric ScopedClearThreadLocalState scoped_clear_tls; 1624fe6060f1SDimitry Andric 1625fe6060f1SDimitry Andric // Clear shadows for all inputs provided by system. Similar to SignalHandler. 1626fe6060f1SDimitry Andric dfsan_clear_arg_tls(0, 3 * sizeof(dfsan_label)); 1627fe6060f1SDimitry Andric dfsan_set_label(0, si, sizeof(*si)); 1628fe6060f1SDimitry Andric dfsan_set_label(0, uc, sizeof(ucontext_t)); 1629fe6060f1SDimitry Andric 1630fe6060f1SDimitry Andric typedef void (*sigaction_cb)(int, siginfo_t *, void *); 1631fe6060f1SDimitry Andric sigaction_cb cb = 1632fe6060f1SDimitry Andric (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed); 1633fe6060f1SDimitry Andric cb(signo, si, uc); 1634fe6060f1SDimitry Andric } 1635fe6060f1SDimitry Andric 1636fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 163768d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act, 163868d75effSDimitry Andric struct sigaction *oldact, dfsan_label signum_label, 163968d75effSDimitry Andric dfsan_label act_label, dfsan_label oldact_label, 164068d75effSDimitry Andric dfsan_label *ret_label) { 1641fe6060f1SDimitry Andric CHECK_LT(signum, kMaxSignals); 1642fe6060f1SDimitry Andric SignalSpinLocker lock; 1643fe6060f1SDimitry Andric uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed); 1644fe6060f1SDimitry Andric struct sigaction new_act; 1645fe6060f1SDimitry Andric struct sigaction *pnew_act = act ? &new_act : nullptr; 1646fe6060f1SDimitry Andric if (act) { 1647fe6060f1SDimitry Andric internal_memcpy(pnew_act, act, sizeof(struct sigaction)); 1648fe6060f1SDimitry Andric if (pnew_act->sa_flags & SA_SIGINFO) { 1649fe6060f1SDimitry Andric uptr cb = (uptr)(pnew_act->sa_sigaction); 1650fe6060f1SDimitry Andric if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) { 1651fe6060f1SDimitry Andric atomic_store(&sigactions[signum], cb, memory_order_relaxed); 1652fe6060f1SDimitry Andric pnew_act->sa_sigaction = SignalAction; 1653fe6060f1SDimitry Andric } 1654fe6060f1SDimitry Andric } else { 1655fe6060f1SDimitry Andric uptr cb = (uptr)(pnew_act->sa_handler); 1656fe6060f1SDimitry Andric if (cb != (uptr)SIG_IGN && cb != (uptr)SIG_DFL) { 1657fe6060f1SDimitry Andric atomic_store(&sigactions[signum], cb, memory_order_relaxed); 1658fe6060f1SDimitry Andric pnew_act->sa_handler = SignalHandler; 1659fe6060f1SDimitry Andric } 1660fe6060f1SDimitry Andric } 1661fe6060f1SDimitry Andric } 1662fe6060f1SDimitry Andric 1663fe6060f1SDimitry Andric int ret = sigaction(signum, pnew_act, oldact); 1664fe6060f1SDimitry Andric 1665fe6060f1SDimitry Andric if (ret == 0 && oldact) { 1666fe6060f1SDimitry Andric if (oldact->sa_flags & SA_SIGINFO) { 1667fe6060f1SDimitry Andric if (oldact->sa_sigaction == SignalAction) 1668fe6060f1SDimitry Andric oldact->sa_sigaction = (decltype(oldact->sa_sigaction))old_cb; 1669fe6060f1SDimitry Andric } else { 1670fe6060f1SDimitry Andric if (oldact->sa_handler == SignalHandler) 1671fe6060f1SDimitry Andric oldact->sa_handler = (decltype(oldact->sa_handler))old_cb; 1672fe6060f1SDimitry Andric } 1673fe6060f1SDimitry Andric } 1674fe6060f1SDimitry Andric 167568d75effSDimitry Andric if (oldact) { 167668d75effSDimitry Andric dfsan_set_label(0, oldact, sizeof(struct sigaction)); 167768d75effSDimitry Andric } 167868d75effSDimitry Andric *ret_label = 0; 167968d75effSDimitry Andric return ret; 168068d75effSDimitry Andric } 168168d75effSDimitry Andric 168268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1683fe6060f1SDimitry Andric int __dfso_sigaction(int signum, const struct sigaction *act, 1684fe6060f1SDimitry Andric struct sigaction *oldact, dfsan_label signum_label, 1685fe6060f1SDimitry Andric dfsan_label act_label, dfsan_label oldact_label, 1686fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin signum_origin, 1687fe6060f1SDimitry Andric dfsan_origin act_origin, dfsan_origin oldact_origin, 1688fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1689fe6060f1SDimitry Andric return __dfsw_sigaction(signum, act, oldact, signum_label, act_label, 1690fe6060f1SDimitry Andric oldact_label, ret_label); 1691fe6060f1SDimitry Andric } 1692fe6060f1SDimitry Andric 1693fe6060f1SDimitry Andric static sighandler_t dfsan_signal(int signum, sighandler_t handler, 1694fe6060f1SDimitry Andric dfsan_label *ret_label) { 1695fe6060f1SDimitry Andric CHECK_LT(signum, kMaxSignals); 1696fe6060f1SDimitry Andric SignalSpinLocker lock; 1697fe6060f1SDimitry Andric uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed); 1698fe6060f1SDimitry Andric if (handler != SIG_IGN && handler != SIG_DFL) { 1699fe6060f1SDimitry Andric atomic_store(&sigactions[signum], (uptr)handler, memory_order_relaxed); 1700fe6060f1SDimitry Andric handler = &SignalHandler; 1701fe6060f1SDimitry Andric } 1702fe6060f1SDimitry Andric 1703fe6060f1SDimitry Andric sighandler_t ret = signal(signum, handler); 1704fe6060f1SDimitry Andric 1705fe6060f1SDimitry Andric if (ret == SignalHandler) 1706fe6060f1SDimitry Andric ret = (sighandler_t)old_cb; 1707fe6060f1SDimitry Andric 1708fe6060f1SDimitry Andric *ret_label = 0; 1709fe6060f1SDimitry Andric return ret; 1710fe6060f1SDimitry Andric } 1711fe6060f1SDimitry Andric 1712fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 171381ad6265SDimitry Andric sighandler_t __dfsw_signal(int signum, sighandler_t handler, 171481ad6265SDimitry Andric dfsan_label signum_label, dfsan_label handler_label, 171581ad6265SDimitry Andric dfsan_label *ret_label) { 1716fe6060f1SDimitry Andric return dfsan_signal(signum, handler, ret_label); 1717fe6060f1SDimitry Andric } 1718fe6060f1SDimitry Andric 1719fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 172081ad6265SDimitry Andric sighandler_t __dfso_signal(int signum, sighandler_t handler, 172181ad6265SDimitry Andric dfsan_label signum_label, dfsan_label handler_label, 1722fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin signum_origin, 172381ad6265SDimitry Andric dfsan_origin handler_origin, 172481ad6265SDimitry Andric dfsan_origin *ret_origin) { 1725fe6060f1SDimitry Andric return dfsan_signal(signum, handler, ret_label); 1726fe6060f1SDimitry Andric } 1727fe6060f1SDimitry Andric 1728fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1729e8d8bef9SDimitry Andric int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label, 1730e8d8bef9SDimitry Andric dfsan_label old_ss_label, dfsan_label *ret_label) { 1731e8d8bef9SDimitry Andric int ret = sigaltstack(ss, old_ss); 1732e8d8bef9SDimitry Andric if (ret != -1 && old_ss) 1733e8d8bef9SDimitry Andric dfsan_set_label(0, old_ss, sizeof(*old_ss)); 1734e8d8bef9SDimitry Andric *ret_label = 0; 1735e8d8bef9SDimitry Andric return ret; 1736e8d8bef9SDimitry Andric } 1737e8d8bef9SDimitry Andric 1738e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1739fe6060f1SDimitry Andric int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label, 1740fe6060f1SDimitry Andric dfsan_label old_ss_label, dfsan_label *ret_label, 1741fe6060f1SDimitry Andric dfsan_origin ss_origin, dfsan_origin old_ss_origin, 1742fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1743fe6060f1SDimitry Andric return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label); 1744fe6060f1SDimitry Andric } 1745fe6060f1SDimitry Andric 1746fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 174768d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz, 174868d75effSDimitry Andric dfsan_label tv_label, dfsan_label tz_label, 174968d75effSDimitry Andric dfsan_label *ret_label) { 175068d75effSDimitry Andric int ret = gettimeofday(tv, tz); 175168d75effSDimitry Andric if (tv) { 175268d75effSDimitry Andric dfsan_set_label(0, tv, sizeof(struct timeval)); 175368d75effSDimitry Andric } 175468d75effSDimitry Andric if (tz) { 175568d75effSDimitry Andric dfsan_set_label(0, tz, sizeof(struct timezone)); 175668d75effSDimitry Andric } 175768d75effSDimitry Andric *ret_label = 0; 175868d75effSDimitry Andric return ret; 175968d75effSDimitry Andric } 176068d75effSDimitry Andric 1761fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 1762fe6060f1SDimitry Andric int __dfso_gettimeofday(struct timeval *tv, struct timezone *tz, 1763fe6060f1SDimitry Andric dfsan_label tv_label, dfsan_label tz_label, 1764fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin tv_origin, 1765fe6060f1SDimitry Andric dfsan_origin tz_origin, dfsan_origin *ret_origin) { 1766fe6060f1SDimitry Andric return __dfsw_gettimeofday(tv, tz, tv_label, tz_label, ret_label); 1767fe6060f1SDimitry Andric } 1768fe6060f1SDimitry Andric 176968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n, 177068d75effSDimitry Andric dfsan_label s_label, 177168d75effSDimitry Andric dfsan_label c_label, 177268d75effSDimitry Andric dfsan_label n_label, 177368d75effSDimitry Andric dfsan_label *ret_label) { 177468d75effSDimitry Andric void *ret = memchr(s, c, n); 177568d75effSDimitry Andric if (flags().strict_data_dependencies) { 177668d75effSDimitry Andric *ret_label = ret ? s_label : 0; 177768d75effSDimitry Andric } else { 177868d75effSDimitry Andric size_t len = 177968d75effSDimitry Andric ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1 178068d75effSDimitry Andric : n; 178168d75effSDimitry Andric *ret_label = 178268d75effSDimitry Andric dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label)); 178368d75effSDimitry Andric } 178468d75effSDimitry Andric return ret; 178568d75effSDimitry Andric } 178668d75effSDimitry Andric 1787fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_memchr( 1788fe6060f1SDimitry Andric void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label, 1789fe6060f1SDimitry Andric dfsan_label n_label, dfsan_label *ret_label, dfsan_origin s_origin, 1790fe6060f1SDimitry Andric dfsan_origin c_origin, dfsan_origin n_origin, dfsan_origin *ret_origin) { 1791fe6060f1SDimitry Andric void *ret = __dfsw_memchr(s, c, n, s_label, c_label, n_label, ret_label); 1792fe6060f1SDimitry Andric if (flags().strict_data_dependencies) { 1793fe6060f1SDimitry Andric if (ret) 1794fe6060f1SDimitry Andric *ret_origin = s_origin; 1795fe6060f1SDimitry Andric } else { 1796fe6060f1SDimitry Andric size_t len = 1797fe6060f1SDimitry Andric ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1 1798fe6060f1SDimitry Andric : n; 1799fe6060f1SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(s, len); 1800fe6060f1SDimitry Andric *ret_origin = o ? o : (s_label ? s_origin : c_origin); 1801fe6060f1SDimitry Andric } 1802fe6060f1SDimitry Andric return ret; 1803fe6060f1SDimitry Andric } 1804fe6060f1SDimitry Andric 180568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c, 180668d75effSDimitry Andric dfsan_label s_label, 180768d75effSDimitry Andric dfsan_label c_label, 180868d75effSDimitry Andric dfsan_label *ret_label) { 180968d75effSDimitry Andric char *ret = strrchr(s, c); 181068d75effSDimitry Andric if (flags().strict_data_dependencies) { 181168d75effSDimitry Andric *ret_label = ret ? s_label : 0; 181268d75effSDimitry Andric } else { 181368d75effSDimitry Andric *ret_label = 181468d75effSDimitry Andric dfsan_union(dfsan_read_label(s, strlen(s) + 1), 181568d75effSDimitry Andric dfsan_union(s_label, c_label)); 181668d75effSDimitry Andric } 181768d75effSDimitry Andric 181868d75effSDimitry Andric return ret; 181968d75effSDimitry Andric } 182068d75effSDimitry Andric 1821fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strrchr( 1822fe6060f1SDimitry Andric char *s, int c, dfsan_label s_label, dfsan_label c_label, 1823fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin s_origin, dfsan_origin c_origin, 1824fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1825fe6060f1SDimitry Andric char *ret = __dfsw_strrchr(s, c, s_label, c_label, ret_label); 1826fe6060f1SDimitry Andric if (flags().strict_data_dependencies) { 1827fe6060f1SDimitry Andric if (ret) 1828fe6060f1SDimitry Andric *ret_origin = s_origin; 1829fe6060f1SDimitry Andric } else { 1830fe6060f1SDimitry Andric size_t s_len = strlen(s) + 1; 1831fe6060f1SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(s, s_len); 1832fe6060f1SDimitry Andric *ret_origin = o ? o : (s_label ? s_origin : c_origin); 1833fe6060f1SDimitry Andric } 1834fe6060f1SDimitry Andric 1835fe6060f1SDimitry Andric return ret; 1836fe6060f1SDimitry Andric } 1837fe6060f1SDimitry Andric 183868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle, 183968d75effSDimitry Andric dfsan_label haystack_label, 184068d75effSDimitry Andric dfsan_label needle_label, 184168d75effSDimitry Andric dfsan_label *ret_label) { 184268d75effSDimitry Andric char *ret = strstr(haystack, needle); 184368d75effSDimitry Andric if (flags().strict_data_dependencies) { 184468d75effSDimitry Andric *ret_label = ret ? haystack_label : 0; 184568d75effSDimitry Andric } else { 184668d75effSDimitry Andric size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1; 184768d75effSDimitry Andric *ret_label = 184868d75effSDimitry Andric dfsan_union(dfsan_read_label(haystack, len), 184968d75effSDimitry Andric dfsan_union(dfsan_read_label(needle, strlen(needle) + 1), 185068d75effSDimitry Andric dfsan_union(haystack_label, needle_label))); 185168d75effSDimitry Andric } 185268d75effSDimitry Andric 185368d75effSDimitry Andric return ret; 185468d75effSDimitry Andric } 185568d75effSDimitry Andric 1856fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strstr(char *haystack, char *needle, 1857fe6060f1SDimitry Andric dfsan_label haystack_label, 1858fe6060f1SDimitry Andric dfsan_label needle_label, 1859fe6060f1SDimitry Andric dfsan_label *ret_label, 1860fe6060f1SDimitry Andric dfsan_origin haystack_origin, 1861fe6060f1SDimitry Andric dfsan_origin needle_origin, 1862fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 1863fe6060f1SDimitry Andric char *ret = 1864fe6060f1SDimitry Andric __dfsw_strstr(haystack, needle, haystack_label, needle_label, ret_label); 1865fe6060f1SDimitry Andric if (flags().strict_data_dependencies) { 1866fe6060f1SDimitry Andric if (ret) 1867fe6060f1SDimitry Andric *ret_origin = haystack_origin; 1868fe6060f1SDimitry Andric } else { 1869fe6060f1SDimitry Andric size_t needle_len = strlen(needle); 1870fe6060f1SDimitry Andric size_t len = ret ? ret + needle_len - haystack : strlen(haystack) + 1; 1871fe6060f1SDimitry Andric dfsan_origin o = dfsan_read_origin_of_first_taint(haystack, len); 1872fe6060f1SDimitry Andric if (o) { 1873fe6060f1SDimitry Andric *ret_origin = o; 1874fe6060f1SDimitry Andric } else { 1875fe6060f1SDimitry Andric o = dfsan_read_origin_of_first_taint(needle, needle_len + 1); 1876fe6060f1SDimitry Andric *ret_origin = o ? o : (haystack_label ? haystack_origin : needle_origin); 1877fe6060f1SDimitry Andric } 1878fe6060f1SDimitry Andric } 1879fe6060f1SDimitry Andric 1880fe6060f1SDimitry Andric return ret; 1881fe6060f1SDimitry Andric } 1882fe6060f1SDimitry Andric 188368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req, 188468d75effSDimitry Andric struct timespec *rem, 188568d75effSDimitry Andric dfsan_label req_label, 188668d75effSDimitry Andric dfsan_label rem_label, 188768d75effSDimitry Andric dfsan_label *ret_label) { 188868d75effSDimitry Andric int ret = nanosleep(req, rem); 188968d75effSDimitry Andric *ret_label = 0; 189068d75effSDimitry Andric if (ret == -1) { 189168d75effSDimitry Andric // Interrupted by a signal, rem is filled with the remaining time. 189268d75effSDimitry Andric dfsan_set_label(0, rem, sizeof(struct timespec)); 189368d75effSDimitry Andric } 189468d75effSDimitry Andric return ret; 189568d75effSDimitry Andric } 189668d75effSDimitry Andric 1897fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_nanosleep( 1898fe6060f1SDimitry Andric const struct timespec *req, struct timespec *rem, dfsan_label req_label, 1899fe6060f1SDimitry Andric dfsan_label rem_label, dfsan_label *ret_label, dfsan_origin req_origin, 1900fe6060f1SDimitry Andric dfsan_origin rem_origin, dfsan_origin *ret_origin) { 1901fe6060f1SDimitry Andric return __dfsw_nanosleep(req, rem, req_label, rem_label, ret_label); 1902fe6060f1SDimitry Andric } 1903fe6060f1SDimitry Andric 1904e8d8bef9SDimitry Andric static void clear_msghdr_labels(size_t bytes_written, struct msghdr *msg) { 1905e8d8bef9SDimitry Andric dfsan_set_label(0, msg, sizeof(*msg)); 1906e8d8bef9SDimitry Andric dfsan_set_label(0, msg->msg_name, msg->msg_namelen); 1907e8d8bef9SDimitry Andric dfsan_set_label(0, msg->msg_control, msg->msg_controllen); 1908e8d8bef9SDimitry Andric for (size_t i = 0; bytes_written > 0; ++i) { 1909e8d8bef9SDimitry Andric assert(i < msg->msg_iovlen); 1910e8d8bef9SDimitry Andric struct iovec *iov = &msg->msg_iov[i]; 1911e8d8bef9SDimitry Andric size_t iov_written = 1912e8d8bef9SDimitry Andric bytes_written < iov->iov_len ? bytes_written : iov->iov_len; 1913e8d8bef9SDimitry Andric dfsan_set_label(0, iov->iov_base, iov_written); 1914e8d8bef9SDimitry Andric bytes_written -= iov_written; 1915e8d8bef9SDimitry Andric } 1916e8d8bef9SDimitry Andric } 1917e8d8bef9SDimitry Andric 1918e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_recvmmsg( 1919e8d8bef9SDimitry Andric int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, 1920e8d8bef9SDimitry Andric struct timespec *timeout, dfsan_label sockfd_label, 1921e8d8bef9SDimitry Andric dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label, 1922e8d8bef9SDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label) { 1923e8d8bef9SDimitry Andric int ret = recvmmsg(sockfd, msgvec, vlen, flags, timeout); 1924e8d8bef9SDimitry Andric for (int i = 0; i < ret; ++i) { 1925e8d8bef9SDimitry Andric dfsan_set_label(0, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len)); 1926e8d8bef9SDimitry Andric clear_msghdr_labels(msgvec[i].msg_len, &msgvec[i].msg_hdr); 1927e8d8bef9SDimitry Andric } 1928e8d8bef9SDimitry Andric *ret_label = 0; 1929e8d8bef9SDimitry Andric return ret; 1930e8d8bef9SDimitry Andric } 1931e8d8bef9SDimitry Andric 1932fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_recvmmsg( 1933fe6060f1SDimitry Andric int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, 1934fe6060f1SDimitry Andric struct timespec *timeout, dfsan_label sockfd_label, 1935fe6060f1SDimitry Andric dfsan_label msgvec_label, dfsan_label vlen_label, dfsan_label flags_label, 1936fe6060f1SDimitry Andric dfsan_label timeout_label, dfsan_label *ret_label, 1937fe6060f1SDimitry Andric dfsan_origin sockfd_origin, dfsan_origin msgvec_origin, 1938fe6060f1SDimitry Andric dfsan_origin vlen_origin, dfsan_origin flags_origin, 1939fe6060f1SDimitry Andric dfsan_origin timeout_origin, dfsan_origin *ret_origin) { 1940fe6060f1SDimitry Andric return __dfsw_recvmmsg(sockfd, msgvec, vlen, flags, timeout, sockfd_label, 1941fe6060f1SDimitry Andric msgvec_label, vlen_label, flags_label, timeout_label, 1942fe6060f1SDimitry Andric ret_label); 1943fe6060f1SDimitry Andric } 1944fe6060f1SDimitry Andric 1945e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfsw_recvmsg( 1946e8d8bef9SDimitry Andric int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label, 1947e8d8bef9SDimitry Andric dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label) { 1948e8d8bef9SDimitry Andric ssize_t ret = recvmsg(sockfd, msg, flags); 1949e8d8bef9SDimitry Andric if (ret >= 0) 1950e8d8bef9SDimitry Andric clear_msghdr_labels(ret, msg); 1951e8d8bef9SDimitry Andric *ret_label = 0; 1952e8d8bef9SDimitry Andric return ret; 1953e8d8bef9SDimitry Andric } 1954e8d8bef9SDimitry Andric 1955fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t __dfso_recvmsg( 1956fe6060f1SDimitry Andric int sockfd, struct msghdr *msg, int flags, dfsan_label sockfd_label, 1957fe6060f1SDimitry Andric dfsan_label msg_label, dfsan_label flags_label, dfsan_label *ret_label, 1958fe6060f1SDimitry Andric dfsan_origin sockfd_origin, dfsan_origin msg_origin, 1959fe6060f1SDimitry Andric dfsan_origin flags_origin, dfsan_origin *ret_origin) { 1960fe6060f1SDimitry Andric return __dfsw_recvmsg(sockfd, msg, flags, sockfd_label, msg_label, 1961fe6060f1SDimitry Andric flags_label, ret_label); 1962fe6060f1SDimitry Andric } 1963fe6060f1SDimitry Andric 196468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int 196568d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2], 196668d75effSDimitry Andric dfsan_label domain_label, dfsan_label type_label, 196768d75effSDimitry Andric dfsan_label protocol_label, dfsan_label sv_label, 196868d75effSDimitry Andric dfsan_label *ret_label) { 196968d75effSDimitry Andric int ret = socketpair(domain, type, protocol, sv); 197068d75effSDimitry Andric *ret_label = 0; 197168d75effSDimitry Andric if (ret == 0) { 197268d75effSDimitry Andric dfsan_set_label(0, sv, sizeof(*sv) * 2); 197368d75effSDimitry Andric } 197468d75effSDimitry Andric return ret; 197568d75effSDimitry Andric } 197668d75effSDimitry Andric 1977fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_socketpair( 1978fe6060f1SDimitry Andric int domain, int type, int protocol, int sv[2], dfsan_label domain_label, 1979fe6060f1SDimitry Andric dfsan_label type_label, dfsan_label protocol_label, dfsan_label sv_label, 1980fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin domain_origin, 1981fe6060f1SDimitry Andric dfsan_origin type_origin, dfsan_origin protocol_origin, 1982fe6060f1SDimitry Andric dfsan_origin sv_origin, dfsan_origin *ret_origin) { 1983fe6060f1SDimitry Andric return __dfsw_socketpair(domain, type, protocol, sv, domain_label, type_label, 1984fe6060f1SDimitry Andric protocol_label, sv_label, ret_label); 1985fe6060f1SDimitry Andric } 1986fe6060f1SDimitry Andric 1987e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockopt( 1988e8d8bef9SDimitry Andric int sockfd, int level, int optname, void *optval, socklen_t *optlen, 1989e8d8bef9SDimitry Andric dfsan_label sockfd_label, dfsan_label level_label, 1990e8d8bef9SDimitry Andric dfsan_label optname_label, dfsan_label optval_label, 1991e8d8bef9SDimitry Andric dfsan_label optlen_label, dfsan_label *ret_label) { 1992e8d8bef9SDimitry Andric int ret = getsockopt(sockfd, level, optname, optval, optlen); 1993e8d8bef9SDimitry Andric if (ret != -1 && optval && optlen) { 1994e8d8bef9SDimitry Andric dfsan_set_label(0, optlen, sizeof(*optlen)); 1995e8d8bef9SDimitry Andric dfsan_set_label(0, optval, *optlen); 1996e8d8bef9SDimitry Andric } 1997e8d8bef9SDimitry Andric *ret_label = 0; 1998e8d8bef9SDimitry Andric return ret; 1999e8d8bef9SDimitry Andric } 2000e8d8bef9SDimitry Andric 2001fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockopt( 2002fe6060f1SDimitry Andric int sockfd, int level, int optname, void *optval, socklen_t *optlen, 2003fe6060f1SDimitry Andric dfsan_label sockfd_label, dfsan_label level_label, 2004fe6060f1SDimitry Andric dfsan_label optname_label, dfsan_label optval_label, 2005fe6060f1SDimitry Andric dfsan_label optlen_label, dfsan_label *ret_label, 2006fe6060f1SDimitry Andric dfsan_origin sockfd_origin, dfsan_origin level_origin, 2007fe6060f1SDimitry Andric dfsan_origin optname_origin, dfsan_origin optval_origin, 2008fe6060f1SDimitry Andric dfsan_origin optlen_origin, dfsan_origin *ret_origin) { 2009fe6060f1SDimitry Andric return __dfsw_getsockopt(sockfd, level, optname, optval, optlen, sockfd_label, 2010fe6060f1SDimitry Andric level_label, optname_label, optval_label, 2011fe6060f1SDimitry Andric optlen_label, ret_label); 2012fe6060f1SDimitry Andric } 2013fe6060f1SDimitry Andric 2014e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getsockname( 2015e8d8bef9SDimitry Andric int sockfd, struct sockaddr *addr, socklen_t *addrlen, 2016e8d8bef9SDimitry Andric dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label, 2017e8d8bef9SDimitry Andric dfsan_label *ret_label) { 2018e8d8bef9SDimitry Andric socklen_t origlen = addrlen ? *addrlen : 0; 2019e8d8bef9SDimitry Andric int ret = getsockname(sockfd, addr, addrlen); 2020e8d8bef9SDimitry Andric if (ret != -1 && addr && addrlen) { 2021e8d8bef9SDimitry Andric socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen; 2022e8d8bef9SDimitry Andric dfsan_set_label(0, addrlen, sizeof(*addrlen)); 2023e8d8bef9SDimitry Andric dfsan_set_label(0, addr, written_bytes); 2024e8d8bef9SDimitry Andric } 2025e8d8bef9SDimitry Andric *ret_label = 0; 2026e8d8bef9SDimitry Andric return ret; 2027e8d8bef9SDimitry Andric } 2028e8d8bef9SDimitry Andric 2029fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getsockname( 2030fe6060f1SDimitry Andric int sockfd, struct sockaddr *addr, socklen_t *addrlen, 2031fe6060f1SDimitry Andric dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label, 2032fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin sockfd_origin, 2033fe6060f1SDimitry Andric dfsan_origin addr_origin, dfsan_origin addrlen_origin, 2034fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 2035fe6060f1SDimitry Andric return __dfsw_getsockname(sockfd, addr, addrlen, sockfd_label, addr_label, 2036fe6060f1SDimitry Andric addrlen_label, ret_label); 2037fe6060f1SDimitry Andric } 2038fe6060f1SDimitry Andric 2039e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getpeername( 2040e8d8bef9SDimitry Andric int sockfd, struct sockaddr *addr, socklen_t *addrlen, 2041e8d8bef9SDimitry Andric dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label, 2042e8d8bef9SDimitry Andric dfsan_label *ret_label) { 2043e8d8bef9SDimitry Andric socklen_t origlen = addrlen ? *addrlen : 0; 2044e8d8bef9SDimitry Andric int ret = getpeername(sockfd, addr, addrlen); 2045e8d8bef9SDimitry Andric if (ret != -1 && addr && addrlen) { 2046e8d8bef9SDimitry Andric socklen_t written_bytes = origlen < *addrlen ? origlen : *addrlen; 2047e8d8bef9SDimitry Andric dfsan_set_label(0, addrlen, sizeof(*addrlen)); 2048e8d8bef9SDimitry Andric dfsan_set_label(0, addr, written_bytes); 2049e8d8bef9SDimitry Andric } 2050e8d8bef9SDimitry Andric *ret_label = 0; 2051e8d8bef9SDimitry Andric return ret; 2052e8d8bef9SDimitry Andric } 2053e8d8bef9SDimitry Andric 2054fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getpeername( 2055fe6060f1SDimitry Andric int sockfd, struct sockaddr *addr, socklen_t *addrlen, 2056fe6060f1SDimitry Andric dfsan_label sockfd_label, dfsan_label addr_label, dfsan_label addrlen_label, 2057fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin sockfd_origin, 2058fe6060f1SDimitry Andric dfsan_origin addr_origin, dfsan_origin addrlen_origin, 2059fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 2060fe6060f1SDimitry Andric return __dfsw_getpeername(sockfd, addr, addrlen, sockfd_label, addr_label, 2061fe6060f1SDimitry Andric addrlen_label, ret_label); 2062fe6060f1SDimitry Andric } 2063fe6060f1SDimitry Andric 206481ad6265SDimitry Andric // Type of the function passed to dfsan_set_write_callback. 206581ad6265SDimitry Andric typedef void (*write_dfsan_callback_t)(int fd, const void *buf, ssize_t count); 2066fe6060f1SDimitry Andric 206768d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct. 206868d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them. 206968d75effSDimitry Andric static struct { 207081ad6265SDimitry Andric write_dfsan_callback_t write_callback = nullptr; 207168d75effSDimitry Andric } write_callback_info; 207268d75effSDimitry Andric 207381ad6265SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_dfsan_set_write_callback( 207481ad6265SDimitry Andric write_dfsan_callback_t write_callback, dfsan_label write_callback_label, 207568d75effSDimitry Andric dfsan_label *ret_label) { 207668d75effSDimitry Andric write_callback_info.write_callback = write_callback; 207768d75effSDimitry Andric } 207868d75effSDimitry Andric 2079fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback( 208081ad6265SDimitry Andric write_dfsan_callback_t write_callback, dfsan_label write_callback_label, 208181ad6265SDimitry Andric dfsan_label *ret_label, dfsan_origin write_callback_origin, 208281ad6265SDimitry Andric dfsan_origin *ret_origin) { 208381ad6265SDimitry Andric write_callback_info.write_callback = write_callback; 208481ad6265SDimitry Andric } 208581ad6265SDimitry Andric 208681ad6265SDimitry Andric static inline void setup_tls_args_for_write_callback( 208781ad6265SDimitry Andric dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label, 208881ad6265SDimitry Andric bool origins, dfsan_origin fd_origin, dfsan_origin buf_origin, 208981ad6265SDimitry Andric dfsan_origin count_origin) { 209081ad6265SDimitry Andric // The callback code will expect argument shadow labels in the args TLS, 209181ad6265SDimitry Andric // and origin labels in the origin args TLS. 209281ad6265SDimitry Andric // Previously this was done by a trampoline, but we want to remove this: 209381ad6265SDimitry Andric // https://github.com/llvm/llvm-project/issues/54172 209481ad6265SDimitry Andric // 209581ad6265SDimitry Andric // Instead, this code is manually setting up the args TLS data. 209681ad6265SDimitry Andric // 209781ad6265SDimitry Andric // The offsets used need to correspond with the instrumentation code, 209881ad6265SDimitry Andric // see llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp 209981ad6265SDimitry Andric // DFSanFunction::getShadowForTLSArgument. 210081ad6265SDimitry Andric // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L1684 210181ad6265SDimitry Andric // https://github.com/llvm/llvm-project/blob/0acc9e4b5edd8b39ff3d4c6d0e17f02007671c4e/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp#L125 210281ad6265SDimitry Andric // 210381ad6265SDimitry Andric // Here the arguments are all primitives, but it can be more complex 210481ad6265SDimitry Andric // to compute offsets for array/aggregate type arguments. 210581ad6265SDimitry Andric // 210681ad6265SDimitry Andric // TODO(browneee): Consider a builtin to improve maintainabliity. 210781ad6265SDimitry Andric // With a builtin, we would provide the argument labels via builtin, 210881ad6265SDimitry Andric // and the builtin would reuse parts of the instrumentation code to ensure 210981ad6265SDimitry Andric // that this code and the instrumentation can never be out of sync. 211081ad6265SDimitry Andric // Note: Currently DFSan instrumentation does not run on this code, so 211181ad6265SDimitry Andric // the builtin may need to be handled outside DFSan instrumentation. 211281ad6265SDimitry Andric dfsan_set_arg_tls(0, fd_label); 211381ad6265SDimitry Andric dfsan_set_arg_tls(1, buf_label); 211481ad6265SDimitry Andric dfsan_set_arg_tls(2, count_label); 211581ad6265SDimitry Andric if (origins) { 211681ad6265SDimitry Andric dfsan_set_arg_origin_tls(0, fd_origin); 211781ad6265SDimitry Andric dfsan_set_arg_origin_tls(1, buf_origin); 211881ad6265SDimitry Andric dfsan_set_arg_origin_tls(2, count_origin); 211981ad6265SDimitry Andric } 2120fe6060f1SDimitry Andric } 2121fe6060f1SDimitry Andric 212268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int 212368d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count, 212468d75effSDimitry Andric dfsan_label fd_label, dfsan_label buf_label, 212568d75effSDimitry Andric dfsan_label count_label, dfsan_label *ret_label) { 212668d75effSDimitry Andric if (write_callback_info.write_callback) { 212781ad6265SDimitry Andric setup_tls_args_for_write_callback(fd_label, buf_label, count_label, false, 212881ad6265SDimitry Andric 0, 0, 0); 212981ad6265SDimitry Andric write_callback_info.write_callback(fd, buf, count); 213068d75effSDimitry Andric } 213168d75effSDimitry Andric 213268d75effSDimitry Andric *ret_label = 0; 213368d75effSDimitry Andric return write(fd, buf, count); 213468d75effSDimitry Andric } 2135fe6060f1SDimitry Andric 2136fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write( 2137fe6060f1SDimitry Andric int fd, const void *buf, size_t count, dfsan_label fd_label, 2138fe6060f1SDimitry Andric dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label, 2139fe6060f1SDimitry Andric dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin, 2140fe6060f1SDimitry Andric dfsan_origin *ret_origin) { 214181ad6265SDimitry Andric if (write_callback_info.write_callback) { 214281ad6265SDimitry Andric setup_tls_args_for_write_callback(fd_label, buf_label, count_label, true, 214381ad6265SDimitry Andric fd_origin, buf_origin, count_origin); 214481ad6265SDimitry Andric write_callback_info.write_callback(fd, buf, count); 2145fe6060f1SDimitry Andric } 2146fe6060f1SDimitry Andric 2147fe6060f1SDimitry Andric *ret_label = 0; 2148fe6060f1SDimitry Andric return write(fd, buf, count); 2149fe6060f1SDimitry Andric } 215068d75effSDimitry Andric } // namespace __dfsan 215168d75effSDimitry Andric 215268d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg() 215368d75effSDimitry Andric typedef int dfsan_label_va; 215468d75effSDimitry Andric 215568d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g., 215668d75effSDimitry Andric // '%.3f'). 215768d75effSDimitry Andric struct Formatter { 215868d75effSDimitry Andric Formatter(char *str_, const char *fmt_, size_t size_) 21595f757f3fSDimitry Andric : str(str_), 21605f757f3fSDimitry Andric str_off(0), 21615f757f3fSDimitry Andric size(size_), 21625f757f3fSDimitry Andric fmt_start(fmt_), 21635f757f3fSDimitry Andric fmt_cur(fmt_), 21645f757f3fSDimitry Andric width(-1), 21655f757f3fSDimitry Andric num_scanned(-1), 21665f757f3fSDimitry Andric skip(false) {} 216768d75effSDimitry Andric 216868d75effSDimitry Andric int format() { 216968d75effSDimitry Andric char *tmp_fmt = build_format_string(); 217068d75effSDimitry Andric int retval = 217168d75effSDimitry Andric snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt, 217268d75effSDimitry Andric 0 /* used only to avoid warnings */); 217368d75effSDimitry Andric free(tmp_fmt); 217468d75effSDimitry Andric return retval; 217568d75effSDimitry Andric } 217668d75effSDimitry Andric 217768d75effSDimitry Andric template <typename T> int format(T arg) { 217868d75effSDimitry Andric char *tmp_fmt = build_format_string(); 217968d75effSDimitry Andric int retval; 218068d75effSDimitry Andric if (width >= 0) { 218168d75effSDimitry Andric retval = snprintf(str + str_off, str_off < size ? size - str_off : 0, 218268d75effSDimitry Andric tmp_fmt, width, arg); 218368d75effSDimitry Andric } else { 218468d75effSDimitry Andric retval = snprintf(str + str_off, str_off < size ? size - str_off : 0, 218568d75effSDimitry Andric tmp_fmt, arg); 218668d75effSDimitry Andric } 218768d75effSDimitry Andric free(tmp_fmt); 218868d75effSDimitry Andric return retval; 218968d75effSDimitry Andric } 219068d75effSDimitry Andric 21915f757f3fSDimitry Andric int scan() { 21925f757f3fSDimitry Andric char *tmp_fmt = build_format_string(true); 21935f757f3fSDimitry Andric int read_count = 0; 21945f757f3fSDimitry Andric int retval = sscanf(str + str_off, tmp_fmt, &read_count); 21955f757f3fSDimitry Andric if (retval > 0) { 21965f757f3fSDimitry Andric if (-1 == num_scanned) 21975f757f3fSDimitry Andric num_scanned = 0; 21985f757f3fSDimitry Andric num_scanned += retval; 21995f757f3fSDimitry Andric } 22005f757f3fSDimitry Andric free(tmp_fmt); 22015f757f3fSDimitry Andric return read_count; 22025f757f3fSDimitry Andric } 22035f757f3fSDimitry Andric 22045f757f3fSDimitry Andric template <typename T> 22055f757f3fSDimitry Andric int scan(T arg) { 22065f757f3fSDimitry Andric char *tmp_fmt = build_format_string(true); 22075f757f3fSDimitry Andric int read_count = 0; 22085f757f3fSDimitry Andric int retval = sscanf(str + str_off, tmp_fmt, arg, &read_count); 22095f757f3fSDimitry Andric if (retval > 0) { 22105f757f3fSDimitry Andric if (-1 == num_scanned) 22115f757f3fSDimitry Andric num_scanned = 0; 22125f757f3fSDimitry Andric num_scanned += retval; 22135f757f3fSDimitry Andric } 22145f757f3fSDimitry Andric free(tmp_fmt); 22155f757f3fSDimitry Andric return read_count; 22165f757f3fSDimitry Andric } 22175f757f3fSDimitry Andric 22185f757f3fSDimitry Andric // with_n -> toggles adding %n on/off; off by default 22195f757f3fSDimitry Andric char *build_format_string(bool with_n = false) { 222068d75effSDimitry Andric size_t fmt_size = fmt_cur - fmt_start + 1; 22215f757f3fSDimitry Andric size_t add_size = 0; 22225f757f3fSDimitry Andric if (with_n) 22235f757f3fSDimitry Andric add_size = 2; 22245f757f3fSDimitry Andric char *new_fmt = (char *)malloc(fmt_size + 1 + add_size); 222568d75effSDimitry Andric assert(new_fmt); 222668d75effSDimitry Andric internal_memcpy(new_fmt, fmt_start, fmt_size); 22275f757f3fSDimitry Andric if (!with_n) { 222868d75effSDimitry Andric new_fmt[fmt_size] = '\0'; 22295f757f3fSDimitry Andric } else { 22305f757f3fSDimitry Andric new_fmt[fmt_size] = '%'; 22315f757f3fSDimitry Andric new_fmt[fmt_size + 1] = 'n'; 22325f757f3fSDimitry Andric new_fmt[fmt_size + 2] = '\0'; 22335f757f3fSDimitry Andric } 22345f757f3fSDimitry Andric 223568d75effSDimitry Andric return new_fmt; 223668d75effSDimitry Andric } 223768d75effSDimitry Andric 223868d75effSDimitry Andric char *str_cur() { return str + str_off; } 223968d75effSDimitry Andric 224068d75effSDimitry Andric size_t num_written_bytes(int retval) { 224168d75effSDimitry Andric if (retval < 0) { 224268d75effSDimitry Andric return 0; 224368d75effSDimitry Andric } 224468d75effSDimitry Andric 224568d75effSDimitry Andric size_t num_avail = str_off < size ? size - str_off : 0; 224668d75effSDimitry Andric if (num_avail == 0) { 224768d75effSDimitry Andric return 0; 224868d75effSDimitry Andric } 224968d75effSDimitry Andric 225068d75effSDimitry Andric size_t num_written = retval; 225168d75effSDimitry Andric // A return value of {v,}snprintf of size or more means that the output was 225268d75effSDimitry Andric // truncated. 225368d75effSDimitry Andric if (num_written >= num_avail) { 225468d75effSDimitry Andric num_written -= num_avail; 225568d75effSDimitry Andric } 225668d75effSDimitry Andric 225768d75effSDimitry Andric return num_written; 225868d75effSDimitry Andric } 225968d75effSDimitry Andric 226068d75effSDimitry Andric char *str; 226168d75effSDimitry Andric size_t str_off; 226268d75effSDimitry Andric size_t size; 226368d75effSDimitry Andric const char *fmt_start; 226468d75effSDimitry Andric const char *fmt_cur; 226568d75effSDimitry Andric int width; 22665f757f3fSDimitry Andric int num_scanned; 22675f757f3fSDimitry Andric bool skip; 226868d75effSDimitry Andric }; 226968d75effSDimitry Andric 227068d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output 227168d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and 227268d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns 227368d75effSDimitry Andric // the return value vsnprintf would return. 227468d75effSDimitry Andric // 227568d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a 227668d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each 227768d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure 227868d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to 227968d75effSDimitry Andric // propagate labels more precisely. 228068d75effSDimitry Andric // 228168d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with 228268d75effSDimitry Andric // positional arguments. 228368d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt, 228468d75effSDimitry Andric dfsan_label *va_labels, dfsan_label *ret_label, 2285fe6060f1SDimitry Andric dfsan_origin *va_origins, dfsan_origin *ret_origin, 228668d75effSDimitry Andric va_list ap) { 228768d75effSDimitry Andric Formatter formatter(str, fmt, size); 228868d75effSDimitry Andric 228968d75effSDimitry Andric while (*formatter.fmt_cur) { 229068d75effSDimitry Andric formatter.fmt_start = formatter.fmt_cur; 229168d75effSDimitry Andric formatter.width = -1; 229268d75effSDimitry Andric int retval = 0; 229368d75effSDimitry Andric 229468d75effSDimitry Andric if (*formatter.fmt_cur != '%') { 229568d75effSDimitry Andric // Ordinary character. Consume all the characters until a '%' or the end 229668d75effSDimitry Andric // of the string. 229768d75effSDimitry Andric for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%'; 229868d75effSDimitry Andric ++formatter.fmt_cur) {} 229968d75effSDimitry Andric retval = formatter.format(); 230068d75effSDimitry Andric dfsan_set_label(0, formatter.str_cur(), 230168d75effSDimitry Andric formatter.num_written_bytes(retval)); 230268d75effSDimitry Andric } else { 230368d75effSDimitry Andric // Conversion directive. Consume all the characters until a conversion 230468d75effSDimitry Andric // specifier or the end of the string. 230568d75effSDimitry Andric bool end_fmt = false; 230668d75effSDimitry Andric for (; *formatter.fmt_cur && !end_fmt; ) { 230768d75effSDimitry Andric switch (*++formatter.fmt_cur) { 230868d75effSDimitry Andric case 'd': 230968d75effSDimitry Andric case 'i': 231068d75effSDimitry Andric case 'o': 231168d75effSDimitry Andric case 'u': 231268d75effSDimitry Andric case 'x': 231368d75effSDimitry Andric case 'X': 231468d75effSDimitry Andric switch (*(formatter.fmt_cur - 1)) { 231568d75effSDimitry Andric case 'h': 231668d75effSDimitry Andric // Also covers the 'hh' case (since the size of the arg is still 231768d75effSDimitry Andric // an int). 231868d75effSDimitry Andric retval = formatter.format(va_arg(ap, int)); 231968d75effSDimitry Andric break; 232068d75effSDimitry Andric case 'l': 232168d75effSDimitry Andric if (formatter.fmt_cur - formatter.fmt_start >= 2 && 232268d75effSDimitry Andric *(formatter.fmt_cur - 2) == 'l') { 232368d75effSDimitry Andric retval = formatter.format(va_arg(ap, long long int)); 232468d75effSDimitry Andric } else { 232568d75effSDimitry Andric retval = formatter.format(va_arg(ap, long int)); 232668d75effSDimitry Andric } 232768d75effSDimitry Andric break; 232868d75effSDimitry Andric case 'q': 232968d75effSDimitry Andric retval = formatter.format(va_arg(ap, long long int)); 233068d75effSDimitry Andric break; 233168d75effSDimitry Andric case 'j': 233268d75effSDimitry Andric retval = formatter.format(va_arg(ap, intmax_t)); 233368d75effSDimitry Andric break; 233468d75effSDimitry Andric case 'z': 233568d75effSDimitry Andric case 't': 233668d75effSDimitry Andric retval = formatter.format(va_arg(ap, size_t)); 233768d75effSDimitry Andric break; 233868d75effSDimitry Andric default: 233968d75effSDimitry Andric retval = formatter.format(va_arg(ap, int)); 234068d75effSDimitry Andric } 2341fe6060f1SDimitry Andric if (va_origins == nullptr) 234268d75effSDimitry Andric dfsan_set_label(*va_labels++, formatter.str_cur(), 234368d75effSDimitry Andric formatter.num_written_bytes(retval)); 2344fe6060f1SDimitry Andric else 2345fe6060f1SDimitry Andric dfsan_set_label_origin(*va_labels++, *va_origins++, 2346fe6060f1SDimitry Andric formatter.str_cur(), 2347fe6060f1SDimitry Andric formatter.num_written_bytes(retval)); 234868d75effSDimitry Andric end_fmt = true; 234968d75effSDimitry Andric break; 235068d75effSDimitry Andric 235168d75effSDimitry Andric case 'a': 235268d75effSDimitry Andric case 'A': 235368d75effSDimitry Andric case 'e': 235468d75effSDimitry Andric case 'E': 235568d75effSDimitry Andric case 'f': 235668d75effSDimitry Andric case 'F': 235768d75effSDimitry Andric case 'g': 235868d75effSDimitry Andric case 'G': 235968d75effSDimitry Andric if (*(formatter.fmt_cur - 1) == 'L') { 236068d75effSDimitry Andric retval = formatter.format(va_arg(ap, long double)); 236168d75effSDimitry Andric } else { 236268d75effSDimitry Andric retval = formatter.format(va_arg(ap, double)); 236368d75effSDimitry Andric } 2364fe6060f1SDimitry Andric if (va_origins == nullptr) 236568d75effSDimitry Andric dfsan_set_label(*va_labels++, formatter.str_cur(), 236668d75effSDimitry Andric formatter.num_written_bytes(retval)); 2367fe6060f1SDimitry Andric else 2368fe6060f1SDimitry Andric dfsan_set_label_origin(*va_labels++, *va_origins++, 2369fe6060f1SDimitry Andric formatter.str_cur(), 2370fe6060f1SDimitry Andric formatter.num_written_bytes(retval)); 237168d75effSDimitry Andric end_fmt = true; 237268d75effSDimitry Andric break; 237368d75effSDimitry Andric 237468d75effSDimitry Andric case 'c': 237568d75effSDimitry Andric retval = formatter.format(va_arg(ap, int)); 2376fe6060f1SDimitry Andric if (va_origins == nullptr) 237768d75effSDimitry Andric dfsan_set_label(*va_labels++, formatter.str_cur(), 237868d75effSDimitry Andric formatter.num_written_bytes(retval)); 2379fe6060f1SDimitry Andric else 2380fe6060f1SDimitry Andric dfsan_set_label_origin(*va_labels++, *va_origins++, 2381fe6060f1SDimitry Andric formatter.str_cur(), 2382fe6060f1SDimitry Andric formatter.num_written_bytes(retval)); 238368d75effSDimitry Andric end_fmt = true; 238468d75effSDimitry Andric break; 238568d75effSDimitry Andric 238668d75effSDimitry Andric case 's': { 238768d75effSDimitry Andric char *arg = va_arg(ap, char *); 238868d75effSDimitry Andric retval = formatter.format(arg); 2389fe6060f1SDimitry Andric if (va_origins) { 2390fe6060f1SDimitry Andric va_origins++; 2391fe6060f1SDimitry Andric dfsan_mem_origin_transfer(formatter.str_cur(), arg, 2392fe6060f1SDimitry Andric formatter.num_written_bytes(retval)); 2393fe6060f1SDimitry Andric } 239468d75effSDimitry Andric va_labels++; 239504eeddc0SDimitry Andric dfsan_mem_shadow_transfer(formatter.str_cur(), arg, 239668d75effSDimitry Andric formatter.num_written_bytes(retval)); 239768d75effSDimitry Andric end_fmt = true; 239868d75effSDimitry Andric break; 239968d75effSDimitry Andric } 240068d75effSDimitry Andric 240168d75effSDimitry Andric case 'p': 240268d75effSDimitry Andric retval = formatter.format(va_arg(ap, void *)); 2403fe6060f1SDimitry Andric if (va_origins == nullptr) 240468d75effSDimitry Andric dfsan_set_label(*va_labels++, formatter.str_cur(), 240568d75effSDimitry Andric formatter.num_written_bytes(retval)); 2406fe6060f1SDimitry Andric else 2407fe6060f1SDimitry Andric dfsan_set_label_origin(*va_labels++, *va_origins++, 2408fe6060f1SDimitry Andric formatter.str_cur(), 2409fe6060f1SDimitry Andric formatter.num_written_bytes(retval)); 241068d75effSDimitry Andric end_fmt = true; 241168d75effSDimitry Andric break; 241268d75effSDimitry Andric 241368d75effSDimitry Andric case 'n': { 241468d75effSDimitry Andric int *ptr = va_arg(ap, int *); 241568d75effSDimitry Andric *ptr = (int)formatter.str_off; 241668d75effSDimitry Andric va_labels++; 2417fe6060f1SDimitry Andric if (va_origins) 2418fe6060f1SDimitry Andric va_origins++; 241968d75effSDimitry Andric dfsan_set_label(0, ptr, sizeof(ptr)); 242068d75effSDimitry Andric end_fmt = true; 242168d75effSDimitry Andric break; 242268d75effSDimitry Andric } 242368d75effSDimitry Andric 242468d75effSDimitry Andric case '%': 242568d75effSDimitry Andric retval = formatter.format(); 242668d75effSDimitry Andric dfsan_set_label(0, formatter.str_cur(), 242768d75effSDimitry Andric formatter.num_written_bytes(retval)); 242868d75effSDimitry Andric end_fmt = true; 242968d75effSDimitry Andric break; 243068d75effSDimitry Andric 243168d75effSDimitry Andric case '*': 243268d75effSDimitry Andric formatter.width = va_arg(ap, int); 243368d75effSDimitry Andric va_labels++; 2434fe6060f1SDimitry Andric if (va_origins) 2435fe6060f1SDimitry Andric va_origins++; 243668d75effSDimitry Andric break; 243768d75effSDimitry Andric 243868d75effSDimitry Andric default: 243968d75effSDimitry Andric break; 244068d75effSDimitry Andric } 244168d75effSDimitry Andric } 244268d75effSDimitry Andric } 244368d75effSDimitry Andric 244468d75effSDimitry Andric if (retval < 0) { 244568d75effSDimitry Andric return retval; 244668d75effSDimitry Andric } 244768d75effSDimitry Andric 244868d75effSDimitry Andric formatter.fmt_cur++; 244968d75effSDimitry Andric formatter.str_off += retval; 245068d75effSDimitry Andric } 245168d75effSDimitry Andric 245268d75effSDimitry Andric *ret_label = 0; 2453fe6060f1SDimitry Andric if (ret_origin) 2454fe6060f1SDimitry Andric *ret_origin = 0; 245568d75effSDimitry Andric 245668d75effSDimitry Andric // Number of bytes written in total. 245768d75effSDimitry Andric return formatter.str_off; 245868d75effSDimitry Andric } 245968d75effSDimitry Andric 24605f757f3fSDimitry Andric // This function is an inverse of format_buffer: we take the input buffer, 24615f757f3fSDimitry Andric // scan it in search for format strings and store the results in the varargs. 24625f757f3fSDimitry Andric // The labels are propagated from the input buffer to the varargs. 24635f757f3fSDimitry Andric static int scan_buffer(char *str, size_t size, const char *fmt, 24645f757f3fSDimitry Andric dfsan_label *va_labels, dfsan_label *ret_label, 24655f757f3fSDimitry Andric dfsan_origin *str_origin, dfsan_origin *ret_origin, 24665f757f3fSDimitry Andric va_list ap) { 24675f757f3fSDimitry Andric Formatter formatter(str, fmt, size); 24685f757f3fSDimitry Andric while (*formatter.fmt_cur) { 24695f757f3fSDimitry Andric formatter.fmt_start = formatter.fmt_cur; 24705f757f3fSDimitry Andric formatter.width = -1; 24715f757f3fSDimitry Andric formatter.skip = false; 24725f757f3fSDimitry Andric int read_count = 0; 24735f757f3fSDimitry Andric void *dst_ptr = 0; 24745f757f3fSDimitry Andric size_t write_size = 0; 24755f757f3fSDimitry Andric if (*formatter.fmt_cur != '%') { 24765f757f3fSDimitry Andric // Ordinary character. Consume all the characters until a '%' or the end 24775f757f3fSDimitry Andric // of the string. 24785f757f3fSDimitry Andric for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%'; 24795f757f3fSDimitry Andric ++formatter.fmt_cur) { 24805f757f3fSDimitry Andric } 24815f757f3fSDimitry Andric read_count = formatter.scan(); 24825f757f3fSDimitry Andric dfsan_set_label(0, formatter.str_cur(), 24835f757f3fSDimitry Andric formatter.num_written_bytes(read_count)); 24845f757f3fSDimitry Andric } else { 24855f757f3fSDimitry Andric // Conversion directive. Consume all the characters until a conversion 24865f757f3fSDimitry Andric // specifier or the end of the string. 24875f757f3fSDimitry Andric bool end_fmt = false; 24885f757f3fSDimitry Andric for (; *formatter.fmt_cur && !end_fmt;) { 24895f757f3fSDimitry Andric switch (*++formatter.fmt_cur) { 24905f757f3fSDimitry Andric case 'd': 24915f757f3fSDimitry Andric case 'i': 24925f757f3fSDimitry Andric case 'o': 24935f757f3fSDimitry Andric case 'u': 24945f757f3fSDimitry Andric case 'x': 24955f757f3fSDimitry Andric case 'X': 24965f757f3fSDimitry Andric if (formatter.skip) { 24975f757f3fSDimitry Andric read_count = formatter.scan(); 24985f757f3fSDimitry Andric } else { 24995f757f3fSDimitry Andric switch (*(formatter.fmt_cur - 1)) { 25005f757f3fSDimitry Andric case 'h': 25015f757f3fSDimitry Andric // Also covers the 'hh' case (since the size of the arg is still 25025f757f3fSDimitry Andric // an int). 25035f757f3fSDimitry Andric dst_ptr = va_arg(ap, int *); 25045f757f3fSDimitry Andric read_count = formatter.scan((int *)dst_ptr); 25055f757f3fSDimitry Andric write_size = sizeof(int); 25065f757f3fSDimitry Andric break; 25075f757f3fSDimitry Andric case 'l': 25085f757f3fSDimitry Andric if (formatter.fmt_cur - formatter.fmt_start >= 2 && 25095f757f3fSDimitry Andric *(formatter.fmt_cur - 2) == 'l') { 25105f757f3fSDimitry Andric dst_ptr = va_arg(ap, long long int *); 25115f757f3fSDimitry Andric read_count = formatter.scan((long long int *)dst_ptr); 25125f757f3fSDimitry Andric write_size = sizeof(long long int); 25135f757f3fSDimitry Andric } else { 25145f757f3fSDimitry Andric dst_ptr = va_arg(ap, long int *); 25155f757f3fSDimitry Andric read_count = formatter.scan((long int *)dst_ptr); 25165f757f3fSDimitry Andric write_size = sizeof(long int); 25175f757f3fSDimitry Andric } 25185f757f3fSDimitry Andric break; 25195f757f3fSDimitry Andric case 'q': 25205f757f3fSDimitry Andric dst_ptr = va_arg(ap, long long int *); 25215f757f3fSDimitry Andric read_count = formatter.scan((long long int *)dst_ptr); 25225f757f3fSDimitry Andric write_size = sizeof(long long int); 25235f757f3fSDimitry Andric break; 25245f757f3fSDimitry Andric case 'j': 25255f757f3fSDimitry Andric dst_ptr = va_arg(ap, intmax_t *); 25265f757f3fSDimitry Andric read_count = formatter.scan((intmax_t *)dst_ptr); 25275f757f3fSDimitry Andric write_size = sizeof(intmax_t); 25285f757f3fSDimitry Andric break; 25295f757f3fSDimitry Andric case 'z': 25305f757f3fSDimitry Andric case 't': 25315f757f3fSDimitry Andric dst_ptr = va_arg(ap, size_t *); 25325f757f3fSDimitry Andric read_count = formatter.scan((size_t *)dst_ptr); 25335f757f3fSDimitry Andric write_size = sizeof(size_t); 25345f757f3fSDimitry Andric break; 25355f757f3fSDimitry Andric default: 25365f757f3fSDimitry Andric dst_ptr = va_arg(ap, int *); 25375f757f3fSDimitry Andric read_count = formatter.scan((int *)dst_ptr); 25385f757f3fSDimitry Andric write_size = sizeof(int); 25395f757f3fSDimitry Andric } 25405f757f3fSDimitry Andric // get the label associated with the string at the corresponding 25415f757f3fSDimitry Andric // place 25425f757f3fSDimitry Andric dfsan_label l = dfsan_read_label( 25435f757f3fSDimitry Andric formatter.str_cur(), formatter.num_written_bytes(read_count)); 25445f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 25455f757f3fSDimitry Andric if (str_origin != nullptr) { 25465f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 25475f757f3fSDimitry Andric size_t scan_count = formatter.num_written_bytes(read_count); 25485f757f3fSDimitry Andric size_t size = scan_count > write_size ? write_size : scan_count; 25495f757f3fSDimitry Andric dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size); 25505f757f3fSDimitry Andric } 25515f757f3fSDimitry Andric } 25525f757f3fSDimitry Andric end_fmt = true; 25535f757f3fSDimitry Andric 25545f757f3fSDimitry Andric break; 25555f757f3fSDimitry Andric 25565f757f3fSDimitry Andric case 'a': 25575f757f3fSDimitry Andric case 'A': 25585f757f3fSDimitry Andric case 'e': 25595f757f3fSDimitry Andric case 'E': 25605f757f3fSDimitry Andric case 'f': 25615f757f3fSDimitry Andric case 'F': 25625f757f3fSDimitry Andric case 'g': 25635f757f3fSDimitry Andric case 'G': 25645f757f3fSDimitry Andric if (formatter.skip) { 25655f757f3fSDimitry Andric read_count = formatter.scan(); 25665f757f3fSDimitry Andric } else { 25675f757f3fSDimitry Andric if (*(formatter.fmt_cur - 1) == 'L') { 25685f757f3fSDimitry Andric dst_ptr = va_arg(ap, long double *); 25695f757f3fSDimitry Andric read_count = formatter.scan((long double *)dst_ptr); 25705f757f3fSDimitry Andric write_size = sizeof(long double); 25715f757f3fSDimitry Andric } else if (*(formatter.fmt_cur - 1) == 'l') { 25725f757f3fSDimitry Andric dst_ptr = va_arg(ap, double *); 25735f757f3fSDimitry Andric read_count = formatter.scan((double *)dst_ptr); 25745f757f3fSDimitry Andric write_size = sizeof(double); 25755f757f3fSDimitry Andric } else { 25765f757f3fSDimitry Andric dst_ptr = va_arg(ap, float *); 25775f757f3fSDimitry Andric read_count = formatter.scan((float *)dst_ptr); 25785f757f3fSDimitry Andric write_size = sizeof(float); 25795f757f3fSDimitry Andric } 25805f757f3fSDimitry Andric dfsan_label l = dfsan_read_label( 25815f757f3fSDimitry Andric formatter.str_cur(), formatter.num_written_bytes(read_count)); 25825f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 25835f757f3fSDimitry Andric if (str_origin != nullptr) { 25845f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 25855f757f3fSDimitry Andric size_t scan_count = formatter.num_written_bytes(read_count); 25865f757f3fSDimitry Andric size_t size = scan_count > write_size ? write_size : scan_count; 25875f757f3fSDimitry Andric dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size); 25885f757f3fSDimitry Andric } 25895f757f3fSDimitry Andric } 25905f757f3fSDimitry Andric end_fmt = true; 25915f757f3fSDimitry Andric break; 25925f757f3fSDimitry Andric 25935f757f3fSDimitry Andric case 'c': 25945f757f3fSDimitry Andric if (formatter.skip) { 25955f757f3fSDimitry Andric read_count = formatter.scan(); 25965f757f3fSDimitry Andric } else { 25975f757f3fSDimitry Andric dst_ptr = va_arg(ap, char *); 25985f757f3fSDimitry Andric read_count = formatter.scan((char *)dst_ptr); 25995f757f3fSDimitry Andric write_size = sizeof(char); 26005f757f3fSDimitry Andric dfsan_label l = dfsan_read_label( 26015f757f3fSDimitry Andric formatter.str_cur(), formatter.num_written_bytes(read_count)); 26025f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 26035f757f3fSDimitry Andric if (str_origin != nullptr) { 26045f757f3fSDimitry Andric size_t scan_count = formatter.num_written_bytes(read_count); 26055f757f3fSDimitry Andric size_t size = scan_count > write_size ? write_size : scan_count; 26065f757f3fSDimitry Andric dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size); 26075f757f3fSDimitry Andric } 26085f757f3fSDimitry Andric } 26095f757f3fSDimitry Andric end_fmt = true; 26105f757f3fSDimitry Andric break; 26115f757f3fSDimitry Andric 26125f757f3fSDimitry Andric case 's': { 26135f757f3fSDimitry Andric if (formatter.skip) { 26145f757f3fSDimitry Andric read_count = formatter.scan(); 26155f757f3fSDimitry Andric } else { 26165f757f3fSDimitry Andric dst_ptr = va_arg(ap, char *); 26175f757f3fSDimitry Andric read_count = formatter.scan((char *)dst_ptr); 26185f757f3fSDimitry Andric if (1 == read_count) { 26195f757f3fSDimitry Andric // special case: we have parsed a single string and we need to 26205f757f3fSDimitry Andric // update read_count with the string size 26215f757f3fSDimitry Andric read_count = strlen((char *)dst_ptr); 26225f757f3fSDimitry Andric } 26235f757f3fSDimitry Andric if (str_origin) 26245f757f3fSDimitry Andric dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), 26255f757f3fSDimitry Andric formatter.num_written_bytes(read_count)); 26265f757f3fSDimitry Andric va_labels++; 26275f757f3fSDimitry Andric dfsan_mem_shadow_transfer(dst_ptr, formatter.str_cur(), 26285f757f3fSDimitry Andric formatter.num_written_bytes(read_count)); 26295f757f3fSDimitry Andric } 26305f757f3fSDimitry Andric end_fmt = true; 26315f757f3fSDimitry Andric break; 26325f757f3fSDimitry Andric } 26335f757f3fSDimitry Andric 26345f757f3fSDimitry Andric case 'p': 26355f757f3fSDimitry Andric if (formatter.skip) { 26365f757f3fSDimitry Andric read_count = formatter.scan(); 26375f757f3fSDimitry Andric } else { 26385f757f3fSDimitry Andric dst_ptr = va_arg(ap, void *); 26395f757f3fSDimitry Andric read_count = 26405f757f3fSDimitry Andric formatter.scan((int *)dst_ptr); // note: changing void* to int* 26415f757f3fSDimitry Andric // since we need to call sizeof 26425f757f3fSDimitry Andric write_size = sizeof(int); 26435f757f3fSDimitry Andric 26445f757f3fSDimitry Andric dfsan_label l = dfsan_read_label( 26455f757f3fSDimitry Andric formatter.str_cur(), formatter.num_written_bytes(read_count)); 26465f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 26475f757f3fSDimitry Andric if (str_origin != nullptr) { 26485f757f3fSDimitry Andric dfsan_set_label(l, dst_ptr, write_size); 26495f757f3fSDimitry Andric size_t scan_count = formatter.num_written_bytes(read_count); 26505f757f3fSDimitry Andric size_t size = scan_count > write_size ? write_size : scan_count; 26515f757f3fSDimitry Andric dfsan_mem_origin_transfer(dst_ptr, formatter.str_cur(), size); 26525f757f3fSDimitry Andric } 26535f757f3fSDimitry Andric } 26545f757f3fSDimitry Andric end_fmt = true; 26555f757f3fSDimitry Andric break; 26565f757f3fSDimitry Andric 26575f757f3fSDimitry Andric case 'n': { 26585f757f3fSDimitry Andric if (!formatter.skip) { 26595f757f3fSDimitry Andric int *ptr = va_arg(ap, int *); 26605f757f3fSDimitry Andric *ptr = (int)formatter.str_off; 26615f757f3fSDimitry Andric *va_labels++ = 0; 26625f757f3fSDimitry Andric dfsan_set_label(0, ptr, sizeof(*ptr)); 26635f757f3fSDimitry Andric if (str_origin != nullptr) 26645f757f3fSDimitry Andric *str_origin++ = 0; 26655f757f3fSDimitry Andric } 26665f757f3fSDimitry Andric end_fmt = true; 26675f757f3fSDimitry Andric break; 26685f757f3fSDimitry Andric } 26695f757f3fSDimitry Andric 26705f757f3fSDimitry Andric case '%': 26715f757f3fSDimitry Andric read_count = formatter.scan(); 26725f757f3fSDimitry Andric end_fmt = true; 26735f757f3fSDimitry Andric break; 26745f757f3fSDimitry Andric 26755f757f3fSDimitry Andric case '*': 26765f757f3fSDimitry Andric formatter.skip = true; 26775f757f3fSDimitry Andric break; 26785f757f3fSDimitry Andric 26795f757f3fSDimitry Andric default: 26805f757f3fSDimitry Andric break; 26815f757f3fSDimitry Andric } 26825f757f3fSDimitry Andric } 26835f757f3fSDimitry Andric } 26845f757f3fSDimitry Andric 26855f757f3fSDimitry Andric if (read_count < 0) { 26865f757f3fSDimitry Andric // There was an error. 26875f757f3fSDimitry Andric return read_count; 26885f757f3fSDimitry Andric } 26895f757f3fSDimitry Andric 26905f757f3fSDimitry Andric formatter.fmt_cur++; 26915f757f3fSDimitry Andric formatter.str_off += read_count; 26925f757f3fSDimitry Andric } 26935f757f3fSDimitry Andric 26945f757f3fSDimitry Andric (void)va_labels; // Silence unused-but-set-parameter warning 26955f757f3fSDimitry Andric *ret_label = 0; 26965f757f3fSDimitry Andric if (ret_origin) 26975f757f3fSDimitry Andric *ret_origin = 0; 26985f757f3fSDimitry Andric 26995f757f3fSDimitry Andric // Number of items scanned in total. 27005f757f3fSDimitry Andric return formatter.num_scanned; 27015f757f3fSDimitry Andric } 27025f757f3fSDimitry Andric 270368d75effSDimitry Andric extern "C" { 270468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 270568d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label, 270668d75effSDimitry Andric dfsan_label format_label, dfsan_label *va_labels, 270768d75effSDimitry Andric dfsan_label *ret_label, ...) { 270868d75effSDimitry Andric va_list ap; 270968d75effSDimitry Andric va_start(ap, ret_label); 27105f757f3fSDimitry Andric 27117a6dacacSDimitry Andric int ret = format_buffer(str, INT32_MAX, format, va_labels, ret_label, nullptr, 2712fe6060f1SDimitry Andric nullptr, ap); 2713fe6060f1SDimitry Andric va_end(ap); 2714fe6060f1SDimitry Andric return ret; 2715fe6060f1SDimitry Andric } 2716fe6060f1SDimitry Andric 2717fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 2718fe6060f1SDimitry Andric int __dfso_sprintf(char *str, const char *format, dfsan_label str_label, 2719fe6060f1SDimitry Andric dfsan_label format_label, dfsan_label *va_labels, 2720fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin str_origin, 2721fe6060f1SDimitry Andric dfsan_origin format_origin, dfsan_origin *va_origins, 2722fe6060f1SDimitry Andric dfsan_origin *ret_origin, ...) { 2723fe6060f1SDimitry Andric va_list ap; 2724fe6060f1SDimitry Andric va_start(ap, ret_origin); 27257a6dacacSDimitry Andric int ret = format_buffer(str, INT32_MAX, format, va_labels, ret_label, 27267a6dacacSDimitry Andric va_origins, ret_origin, ap); 272768d75effSDimitry Andric va_end(ap); 272868d75effSDimitry Andric return ret; 272968d75effSDimitry Andric } 273068d75effSDimitry Andric 273168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 273268d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format, 273368d75effSDimitry Andric dfsan_label str_label, dfsan_label size_label, 273468d75effSDimitry Andric dfsan_label format_label, dfsan_label *va_labels, 273568d75effSDimitry Andric dfsan_label *ret_label, ...) { 273668d75effSDimitry Andric va_list ap; 273768d75effSDimitry Andric va_start(ap, ret_label); 2738fe6060f1SDimitry Andric int ret = format_buffer(str, size, format, va_labels, ret_label, nullptr, 2739fe6060f1SDimitry Andric nullptr, ap); 274068d75effSDimitry Andric va_end(ap); 274168d75effSDimitry Andric return ret; 274268d75effSDimitry Andric } 274368d75effSDimitry Andric 2744fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 2745fe6060f1SDimitry Andric int __dfso_snprintf(char *str, size_t size, const char *format, 2746fe6060f1SDimitry Andric dfsan_label str_label, dfsan_label size_label, 2747fe6060f1SDimitry Andric dfsan_label format_label, dfsan_label *va_labels, 2748fe6060f1SDimitry Andric dfsan_label *ret_label, dfsan_origin str_origin, 2749fe6060f1SDimitry Andric dfsan_origin size_origin, dfsan_origin format_origin, 2750fe6060f1SDimitry Andric dfsan_origin *va_origins, dfsan_origin *ret_origin, ...) { 2751fe6060f1SDimitry Andric va_list ap; 2752fe6060f1SDimitry Andric va_start(ap, ret_origin); 2753fe6060f1SDimitry Andric int ret = format_buffer(str, size, format, va_labels, ret_label, va_origins, 2754fe6060f1SDimitry Andric ret_origin, ap); 2755fe6060f1SDimitry Andric va_end(ap); 2756fe6060f1SDimitry Andric return ret; 2757fe6060f1SDimitry Andric } 2758fe6060f1SDimitry Andric 27595f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 27605f757f3fSDimitry Andric int __dfsw_sscanf(char *str, const char *format, dfsan_label str_label, 27615f757f3fSDimitry Andric dfsan_label format_label, dfsan_label *va_labels, 27625f757f3fSDimitry Andric dfsan_label *ret_label, ...) { 27635f757f3fSDimitry Andric va_list ap; 27645f757f3fSDimitry Andric va_start(ap, ret_label); 27655f757f3fSDimitry Andric int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, nullptr, 27665f757f3fSDimitry Andric nullptr, ap); 27675f757f3fSDimitry Andric va_end(ap); 27685f757f3fSDimitry Andric return ret; 27695f757f3fSDimitry Andric } 27705f757f3fSDimitry Andric 27715f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 27725f757f3fSDimitry Andric int __dfso_sscanf(char *str, const char *format, dfsan_label str_label, 27735f757f3fSDimitry Andric dfsan_label format_label, dfsan_label *va_labels, 27745f757f3fSDimitry Andric dfsan_label *ret_label, dfsan_origin str_origin, 27755f757f3fSDimitry Andric dfsan_origin format_origin, dfsan_origin *va_origins, 27765f757f3fSDimitry Andric dfsan_origin *ret_origin, ...) { 27775f757f3fSDimitry Andric va_list ap; 27785f757f3fSDimitry Andric va_start(ap, ret_origin); 27795f757f3fSDimitry Andric int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, &str_origin, 27805f757f3fSDimitry Andric ret_origin, ap); 27815f757f3fSDimitry Andric va_end(ap); 27825f757f3fSDimitry Andric return ret; 27835f757f3fSDimitry Andric } 27845f757f3fSDimitry Andric 2785*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc99_sscanf, sscanf) 2786*74626c16SDimitry Andric WRAPPER_ALIAS(__isoc23_sscanf, sscanf) 27875f757f3fSDimitry Andric 2788fe6060f1SDimitry Andric static void BeforeFork() { 2789cb14a3feSDimitry Andric StackDepotLockBeforeFork(); 2790cb14a3feSDimitry Andric ChainedOriginDepotLockBeforeFork(); 2791fe6060f1SDimitry Andric } 2792fe6060f1SDimitry Andric 2793cb14a3feSDimitry Andric static void AfterFork(bool fork_child) { 2794cb14a3feSDimitry Andric ChainedOriginDepotUnlockAfterFork(fork_child); 2795cb14a3feSDimitry Andric StackDepotUnlockAfterFork(fork_child); 2796fe6060f1SDimitry Andric } 2797fe6060f1SDimitry Andric 2798fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 2799fe6060f1SDimitry Andric pid_t __dfsw_fork(dfsan_label *ret_label) { 2800fe6060f1SDimitry Andric pid_t pid = fork(); 2801fe6060f1SDimitry Andric *ret_label = 0; 2802fe6060f1SDimitry Andric return pid; 2803fe6060f1SDimitry Andric } 2804fe6060f1SDimitry Andric 2805fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 2806fe6060f1SDimitry Andric pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) { 2807fe6060f1SDimitry Andric BeforeFork(); 2808fe6060f1SDimitry Andric pid_t pid = __dfsw_fork(ret_label); 2809cb14a3feSDimitry Andric AfterFork(/* fork_child= */ pid == 0); 2810fe6060f1SDimitry Andric return pid; 2811fe6060f1SDimitry Andric } 2812fe6060f1SDimitry Andric 281368d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them. 281468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {} 281568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *, 281668d75effSDimitry Andric u32 *) {} 2817349cc55cSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg, 2818349cc55cSDimitry Andric const uptr *end) {} 281968d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} 282068d75effSDimitry Andric 282168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {} 282268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {} 282368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {} 282468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {} 282568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {} 282668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1, 282768d75effSDimitry Andric void) {} 282868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2, 282968d75effSDimitry Andric void) {} 283068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4, 283168d75effSDimitry Andric void) {} 283268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8, 283368d75effSDimitry Andric void) {} 283468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {} 283568d75effSDimitry Andric } // extern "C" 2836