xref: /NextBSD/contrib/compiler-rt/lib/dfsan/dfsan_custom.cc (revision 84d351007654069f9643c8e4b4802a7f5f08ee42)
1 //===-- dfsan.cc ----------------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of DataFlowSanitizer.
11 //
12 // This file defines the custom functions listed in done_abilist.txt.
13 //===----------------------------------------------------------------------===//
14 
15 #include "sanitizer_common/sanitizer_common.h"
16 #include "sanitizer_common/sanitizer_internal_defs.h"
17 #include "sanitizer_common/sanitizer_linux.h"
18 
19 #include "dfsan/dfsan.h"
20 
21 #include <arpa/inet.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <dlfcn.h>
25 #include <link.h>
26 #include <poll.h>
27 #include <pthread.h>
28 #include <pwd.h>
29 #include <sched.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/resource.h>
37 #include <sys/select.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <time.h>
42 #include <unistd.h>
43 
44 using namespace __dfsan;
45 
46 extern "C" {
47 SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_stat(const char * path,struct stat * buf,dfsan_label path_label,dfsan_label buf_label,dfsan_label * ret_label)48 __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
49             dfsan_label buf_label, dfsan_label *ret_label) {
50   int ret = stat(path, buf);
51   if (ret == 0)
52     dfsan_set_label(0, buf, sizeof(struct stat));
53   *ret_label = 0;
54   return ret;
55 }
56 
__dfsw_fstat(int fd,struct stat * buf,dfsan_label fd_label,dfsan_label buf_label,dfsan_label * ret_label)57 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
58                                                dfsan_label fd_label,
59                                                dfsan_label buf_label,
60                                                dfsan_label *ret_label) {
61   int ret = fstat(fd, buf);
62   if (ret == 0)
63     dfsan_set_label(0, buf, sizeof(struct stat));
64   *ret_label = 0;
65   return ret;
66 }
67 
__dfsw_strchr(const char * s,int c,dfsan_label s_label,dfsan_label c_label,dfsan_label * ret_label)68 SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
69                                                   dfsan_label s_label,
70                                                   dfsan_label c_label,
71                                                   dfsan_label *ret_label) {
72   for (size_t i = 0;; ++i) {
73     if (s[i] == c || s[i] == 0) {
74       if (flags().strict_data_dependencies) {
75         *ret_label = s_label;
76       } else {
77         *ret_label = dfsan_union(dfsan_read_label(s, i + 1),
78                                  dfsan_union(s_label, c_label));
79       }
80       return s[i] == 0 ? 0 : const_cast<char *>(s+i);
81     }
82   }
83 }
84 
85 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
86 void
87 dfsan_weak_hook_memcmp(uptr caller_pc, const void *s1, const void *s2, size_t n,
88                        dfsan_label s1_label, dfsan_label s2_label,
89                        dfsan_label n_label);
90 
__dfsw_memcmp(const void * s1,const void * s2,size_t n,dfsan_label s1_label,dfsan_label s2_label,dfsan_label n_label,dfsan_label * ret_label)91 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
92                                                 size_t n, dfsan_label s1_label,
93                                                 dfsan_label s2_label,
94                                                 dfsan_label n_label,
95                                                 dfsan_label *ret_label) {
96   if (dfsan_weak_hook_memcmp)
97     dfsan_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, s1_label, s2_label,
98                            n_label);
99   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
100   for (size_t i = 0; i != n; ++i) {
101     if (cs1[i] != cs2[i]) {
102       if (flags().strict_data_dependencies) {
103         *ret_label = 0;
104       } else {
105         *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
106                                  dfsan_read_label(cs2, i + 1));
107       }
108       return cs1[i] - cs2[i];
109     }
110   }
111 
112   if (flags().strict_data_dependencies) {
113     *ret_label = 0;
114   } else {
115     *ret_label = dfsan_union(dfsan_read_label(cs1, n),
116                              dfsan_read_label(cs2, n));
117   }
118   return 0;
119 }
120 
__dfsw_strcmp(const char * s1,const char * s2,dfsan_label s1_label,dfsan_label s2_label,dfsan_label * ret_label)121 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
122                                                 dfsan_label s1_label,
123                                                 dfsan_label s2_label,
124                                                 dfsan_label *ret_label) {
125   for (size_t i = 0;; ++i) {
126     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
127       if (flags().strict_data_dependencies) {
128         *ret_label = 0;
129       } else {
130         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
131                                  dfsan_read_label(s2, i + 1));
132       }
133       return s1[i] - s2[i];
134     }
135   }
136   return 0;
137 }
138 
139 SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_strcasecmp(const char * s1,const char * s2,dfsan_label s1_label,dfsan_label s2_label,dfsan_label * ret_label)140 __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
141                   dfsan_label s2_label, dfsan_label *ret_label) {
142   for (size_t i = 0;; ++i) {
143     if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) {
144       if (flags().strict_data_dependencies) {
145         *ret_label = 0;
146       } else {
147         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
148                                  dfsan_read_label(s2, i + 1));
149       }
150       return s1[i] - s2[i];
151     }
152   }
153   return 0;
154 }
155 
__dfsw_strncmp(const char * s1,const char * s2,size_t n,dfsan_label s1_label,dfsan_label s2_label,dfsan_label n_label,dfsan_label * ret_label)156 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
157                                                  size_t n, dfsan_label s1_label,
158                                                  dfsan_label s2_label,
159                                                  dfsan_label n_label,
160                                                  dfsan_label *ret_label) {
161   if (n == 0) {
162     *ret_label = 0;
163     return 0;
164   }
165 
166   for (size_t i = 0;; ++i) {
167     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
168       if (flags().strict_data_dependencies) {
169         *ret_label = 0;
170       } else {
171         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
172                                  dfsan_read_label(s2, i + 1));
173       }
174       return s1[i] - s2[i];
175     }
176   }
177   return 0;
178 }
179 
180 SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_strncasecmp(const char * s1,const char * s2,size_t n,dfsan_label s1_label,dfsan_label s2_label,dfsan_label n_label,dfsan_label * ret_label)181 __dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
182                    dfsan_label s1_label, dfsan_label s2_label,
183                    dfsan_label n_label, dfsan_label *ret_label) {
184   if (n == 0) {
185     *ret_label = 0;
186     return 0;
187   }
188 
189   for (size_t i = 0;; ++i) {
190     if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0 ||
191         i == n - 1) {
192       if (flags().strict_data_dependencies) {
193         *ret_label = 0;
194       } else {
195         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
196                                  dfsan_read_label(s2, i + 1));
197       }
198       return s1[i] - s2[i];
199     }
200   }
201   return 0;
202 }
203 
__dfsw_calloc(size_t nmemb,size_t size,dfsan_label nmemb_label,dfsan_label size_label,dfsan_label * ret_label)204 SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
205                                                   dfsan_label nmemb_label,
206                                                   dfsan_label size_label,
207                                                   dfsan_label *ret_label) {
208   void *p = calloc(nmemb, size);
209   dfsan_set_label(0, p, nmemb * size);
210   *ret_label = 0;
211   return p;
212 }
213 
214 SANITIZER_INTERFACE_ATTRIBUTE size_t
__dfsw_strlen(const char * s,dfsan_label s_label,dfsan_label * ret_label)215 __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
216   size_t ret = strlen(s);
217   if (flags().strict_data_dependencies) {
218     *ret_label = 0;
219   } else {
220     *ret_label = dfsan_read_label(s, ret + 1);
221   }
222   return ret;
223 }
224 
225 
dfsan_memcpy(void * dest,const void * src,size_t n)226 static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
227   dfsan_label *sdest = shadow_for(dest);
228   const dfsan_label *ssrc = shadow_for(src);
229   internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
230   return internal_memcpy(dest, src, n);
231 }
232 
dfsan_memset(void * s,int c,dfsan_label c_label,size_t n)233 static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
234   internal_memset(s, c, n);
235   dfsan_set_label(c_label, s, n);
236 }
237 
238 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_memcpy(void * dest,const void * src,size_t n,dfsan_label dest_label,dfsan_label src_label,dfsan_label n_label,dfsan_label * ret_label)239 void *__dfsw_memcpy(void *dest, const void *src, size_t n,
240                     dfsan_label dest_label, dfsan_label src_label,
241                     dfsan_label n_label, dfsan_label *ret_label) {
242   *ret_label = dest_label;
243   return dfsan_memcpy(dest, src, n);
244 }
245 
246 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_memset(void * s,int c,size_t n,dfsan_label s_label,dfsan_label c_label,dfsan_label n_label,dfsan_label * ret_label)247 void *__dfsw_memset(void *s, int c, size_t n,
248                     dfsan_label s_label, dfsan_label c_label,
249                     dfsan_label n_label, dfsan_label *ret_label) {
250   dfsan_memset(s, c, c_label, n);
251   *ret_label = s_label;
252   return s;
253 }
254 
255 SANITIZER_INTERFACE_ATTRIBUTE char *
__dfsw_strdup(const char * s,dfsan_label s_label,dfsan_label * ret_label)256 __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
257   size_t len = strlen(s);
258   void *p = malloc(len+1);
259   dfsan_memcpy(p, s, len+1);
260   *ret_label = 0;
261   return static_cast<char *>(p);
262 }
263 
264 SANITIZER_INTERFACE_ATTRIBUTE char *
__dfsw_strncpy(char * s1,const char * s2,size_t n,dfsan_label s1_label,dfsan_label s2_label,dfsan_label n_label,dfsan_label * ret_label)265 __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
266                dfsan_label s2_label, dfsan_label n_label,
267                dfsan_label *ret_label) {
268   size_t len = strlen(s2);
269   if (len < n) {
270     dfsan_memcpy(s1, s2, len+1);
271     dfsan_memset(s1+len+1, 0, 0, n-len-1);
272   } else {
273     dfsan_memcpy(s1, s2, n);
274   }
275 
276   *ret_label = s1_label;
277   return s1;
278 }
279 
280 SANITIZER_INTERFACE_ATTRIBUTE ssize_t
__dfsw_pread(int fd,void * buf,size_t count,off_t offset,dfsan_label fd_label,dfsan_label buf_label,dfsan_label count_label,dfsan_label offset_label,dfsan_label * ret_label)281 __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
282              dfsan_label fd_label, dfsan_label buf_label,
283              dfsan_label count_label, dfsan_label offset_label,
284              dfsan_label *ret_label) {
285   ssize_t ret = pread(fd, buf, count, offset);
286   if (ret > 0)
287     dfsan_set_label(0, buf, ret);
288   *ret_label = 0;
289   return ret;
290 }
291 
292 SANITIZER_INTERFACE_ATTRIBUTE ssize_t
__dfsw_read(int fd,void * buf,size_t count,dfsan_label fd_label,dfsan_label buf_label,dfsan_label count_label,dfsan_label * ret_label)293 __dfsw_read(int fd, void *buf, size_t count,
294              dfsan_label fd_label, dfsan_label buf_label,
295              dfsan_label count_label,
296              dfsan_label *ret_label) {
297   ssize_t ret = read(fd, buf, count);
298   if (ret > 0)
299     dfsan_set_label(0, buf, ret);
300   *ret_label = 0;
301   return ret;
302 }
303 
__dfsw_clock_gettime(clockid_t clk_id,struct timespec * tp,dfsan_label clk_id_label,dfsan_label tp_label,dfsan_label * ret_label)304 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
305                                                        struct timespec *tp,
306                                                        dfsan_label clk_id_label,
307                                                        dfsan_label tp_label,
308                                                        dfsan_label *ret_label) {
309   int ret = clock_gettime(clk_id, tp);
310   if (ret == 0)
311     dfsan_set_label(0, tp, sizeof(struct timespec));
312   *ret_label = 0;
313   return ret;
314 }
315 
unpoison(const void * ptr,uptr size)316 static void unpoison(const void *ptr, uptr size) {
317   dfsan_set_label(0, const_cast<void *>(ptr), size);
318 }
319 
320 // dlopen() ultimately calls mmap() down inside the loader, which generally
321 // doesn't participate in dynamic symbol resolution.  Therefore we won't
322 // intercept its calls to mmap, and we have to hook it here.
323 SANITIZER_INTERFACE_ATTRIBUTE void *
__dfsw_dlopen(const char * filename,int flag,dfsan_label filename_label,dfsan_label flag_label,dfsan_label * ret_label)324 __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
325               dfsan_label flag_label, dfsan_label *ret_label) {
326   void *handle = dlopen(filename, flag);
327   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
328   if (map)
329     ForEachMappedRegion(map, unpoison);
330   *ret_label = 0;
331   return handle;
332 }
333 
334 struct pthread_create_info {
335   void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
336   void *start_routine;
337   void *arg;
338 };
339 
pthread_create_cb(void * p)340 static void *pthread_create_cb(void *p) {
341   pthread_create_info pci(*(pthread_create_info *)p);
342   free(p);
343   dfsan_label ret_label;
344   return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
345                                       &ret_label);
346 }
347 
__dfsw_pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine_trampoline)(void *,void *,dfsan_label,dfsan_label *),void * start_routine,void * arg,dfsan_label thread_label,dfsan_label attr_label,dfsan_label start_routine_label,dfsan_label arg_label,dfsan_label * ret_label)348 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
349     pthread_t *thread, const pthread_attr_t *attr,
350     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
351                                       dfsan_label *),
352     void *start_routine, void *arg, dfsan_label thread_label,
353     dfsan_label attr_label, dfsan_label start_routine_label,
354     dfsan_label arg_label, dfsan_label *ret_label) {
355   pthread_create_info *pci =
356       (pthread_create_info *)malloc(sizeof(pthread_create_info));
357   pci->start_routine_trampoline = start_routine_trampoline;
358   pci->start_routine = start_routine;
359   pci->arg = arg;
360   int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
361   if (rv != 0)
362     free(pci);
363   *ret_label = 0;
364   return rv;
365 }
366 
367 struct dl_iterate_phdr_info {
368   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
369                              size_t size, void *data, dfsan_label info_label,
370                              dfsan_label size_label, dfsan_label data_label,
371                              dfsan_label *ret_label);
372   void *callback;
373   void *data;
374 };
375 
dl_iterate_phdr_cb(struct dl_phdr_info * info,size_t size,void * data)376 int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
377   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
378   dfsan_set_label(0, *info);
379   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
380                   strlen(info->dlpi_name) + 1);
381   dfsan_set_label(
382       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
383       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
384   dfsan_label ret_label;
385   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
386                                    0, &ret_label);
387 }
388 
__dfsw_dl_iterate_phdr(int (* callback_trampoline)(void * callback,struct dl_phdr_info * info,size_t size,void * data,dfsan_label info_label,dfsan_label size_label,dfsan_label data_label,dfsan_label * ret_label),void * callback,void * data,dfsan_label callback_label,dfsan_label data_label,dfsan_label * ret_label)389 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
390     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
391                                size_t size, void *data, dfsan_label info_label,
392                                dfsan_label size_label, dfsan_label data_label,
393                                dfsan_label *ret_label),
394     void *callback, void *data, dfsan_label callback_label,
395     dfsan_label data_label, dfsan_label *ret_label) {
396   dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
397   *ret_label = 0;
398   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
399 }
400 
401 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_ctime_r(const time_t * timep,char * buf,dfsan_label timep_label,dfsan_label buf_label,dfsan_label * ret_label)402 char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
403                      dfsan_label buf_label, dfsan_label *ret_label) {
404   char *ret = ctime_r(timep, buf);
405   if (ret) {
406     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
407                     strlen(buf) + 1);
408     *ret_label = buf_label;
409   } else {
410     *ret_label = 0;
411   }
412   return ret;
413 }
414 
415 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_fgets(char * s,int size,FILE * stream,dfsan_label s_label,dfsan_label size_label,dfsan_label stream_label,dfsan_label * ret_label)416 char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
417                    dfsan_label size_label, dfsan_label stream_label,
418                    dfsan_label *ret_label) {
419   char *ret = fgets(s, size, stream);
420   if (ret) {
421     dfsan_set_label(0, ret, strlen(ret) + 1);
422     *ret_label = s_label;
423   } else {
424     *ret_label = 0;
425   }
426   return ret;
427 }
428 
429 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_getcwd(char * buf,size_t size,dfsan_label buf_label,dfsan_label size_label,dfsan_label * ret_label)430 char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
431                     dfsan_label size_label, dfsan_label *ret_label) {
432   char *ret = getcwd(buf, size);
433   if (ret) {
434     dfsan_set_label(0, ret, strlen(ret) + 1);
435     *ret_label = buf_label;
436   } else {
437     *ret_label = 0;
438   }
439   return ret;
440 }
441 
442 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_get_current_dir_name(dfsan_label * ret_label)443 char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
444   char *ret = get_current_dir_name();
445   if (ret) {
446     dfsan_set_label(0, ret, strlen(ret) + 1);
447   }
448   *ret_label = 0;
449   return ret;
450 }
451 
452 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_gethostname(char * name,size_t len,dfsan_label name_label,dfsan_label len_label,dfsan_label * ret_label)453 int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
454                        dfsan_label len_label, dfsan_label *ret_label) {
455   int ret = gethostname(name, len);
456   if (ret == 0) {
457     dfsan_set_label(0, name, strlen(name) + 1);
458   }
459   *ret_label = 0;
460   return ret;
461 }
462 
463 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_getrlimit(int resource,struct rlimit * rlim,dfsan_label resource_label,dfsan_label rlim_label,dfsan_label * ret_label)464 int __dfsw_getrlimit(int resource, struct rlimit *rlim,
465                      dfsan_label resource_label, dfsan_label rlim_label,
466                      dfsan_label *ret_label) {
467   int ret = getrlimit(resource, rlim);
468   if (ret == 0) {
469     dfsan_set_label(0, rlim, sizeof(struct rlimit));
470   }
471   *ret_label = 0;
472   return ret;
473 }
474 
475 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_getrusage(int who,struct rusage * usage,dfsan_label who_label,dfsan_label usage_label,dfsan_label * ret_label)476 int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
477                      dfsan_label usage_label, dfsan_label *ret_label) {
478   int ret = getrusage(who, usage);
479   if (ret == 0) {
480     dfsan_set_label(0, usage, sizeof(struct rusage));
481   }
482   *ret_label = 0;
483   return ret;
484 }
485 
486 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_strcpy(char * dest,const char * src,dfsan_label dst_label,dfsan_label src_label,dfsan_label * ret_label)487 char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
488                     dfsan_label src_label, dfsan_label *ret_label) {
489   char *ret = strcpy(dest, src);
490   if (ret) {
491     internal_memcpy(shadow_for(dest), shadow_for(src),
492                     sizeof(dfsan_label) * (strlen(src) + 1));
493   }
494   *ret_label = dst_label;
495   return ret;
496 }
497 
498 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_strtol(const char * nptr,char ** endptr,int base,dfsan_label nptr_label,dfsan_label endptr_label,dfsan_label base_label,dfsan_label * ret_label)499 long int __dfsw_strtol(const char *nptr, char **endptr, int base,
500                        dfsan_label nptr_label, dfsan_label endptr_label,
501                        dfsan_label base_label, dfsan_label *ret_label) {
502   char *tmp_endptr;
503   long int ret = strtol(nptr, &tmp_endptr, base);
504   if (endptr) {
505     *endptr = tmp_endptr;
506   }
507   if (tmp_endptr > nptr) {
508     // If *tmp_endptr is '\0' include its label as well.
509     *ret_label = dfsan_union(
510         base_label,
511         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
512   } else {
513     *ret_label = 0;
514   }
515   return ret;
516 }
517 
518 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_strtod(const char * nptr,char ** endptr,dfsan_label nptr_label,dfsan_label endptr_label,dfsan_label * ret_label)519 double __dfsw_strtod(const char *nptr, char **endptr,
520                        dfsan_label nptr_label, dfsan_label endptr_label,
521                        dfsan_label *ret_label) {
522   char *tmp_endptr;
523   double ret = strtod(nptr, &tmp_endptr);
524   if (endptr) {
525     *endptr = tmp_endptr;
526   }
527   if (tmp_endptr > nptr) {
528     // If *tmp_endptr is '\0' include its label as well.
529     *ret_label = dfsan_read_label(
530         nptr,
531         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
532   } else {
533     *ret_label = 0;
534   }
535   return ret;
536 }
537 
538 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_strtoll(const char * nptr,char ** endptr,int base,dfsan_label nptr_label,dfsan_label endptr_label,dfsan_label base_label,dfsan_label * ret_label)539 long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
540                        dfsan_label nptr_label, dfsan_label endptr_label,
541                        dfsan_label base_label, dfsan_label *ret_label) {
542   char *tmp_endptr;
543   long long int ret = strtoll(nptr, &tmp_endptr, base);
544   if (endptr) {
545     *endptr = tmp_endptr;
546   }
547   if (tmp_endptr > nptr) {
548     // If *tmp_endptr is '\0' include its label as well.
549     *ret_label = dfsan_union(
550         base_label,
551         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
552   } else {
553     *ret_label = 0;
554   }
555   return ret;
556 }
557 
558 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_strtoul(const char * nptr,char ** endptr,int base,dfsan_label nptr_label,dfsan_label endptr_label,dfsan_label base_label,dfsan_label * ret_label)559 unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
560                        dfsan_label nptr_label, dfsan_label endptr_label,
561                        dfsan_label base_label, dfsan_label *ret_label) {
562   char *tmp_endptr;
563   unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
564   if (endptr) {
565     *endptr = tmp_endptr;
566   }
567   if (tmp_endptr > nptr) {
568     // If *tmp_endptr is '\0' include its label as well.
569     *ret_label = dfsan_union(
570         base_label,
571         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
572   } else {
573     *ret_label = 0;
574   }
575   return ret;
576 }
577 
578 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_strtoull(const char * nptr,char ** endptr,dfsan_label nptr_label,int base,dfsan_label endptr_label,dfsan_label base_label,dfsan_label * ret_label)579 long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
580                                        dfsan_label nptr_label,
581                                        int base, dfsan_label endptr_label,
582                                        dfsan_label base_label,
583                                        dfsan_label *ret_label) {
584   char *tmp_endptr;
585   long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
586   if (endptr) {
587     *endptr = tmp_endptr;
588   }
589   if (tmp_endptr > nptr) {
590     // If *tmp_endptr is '\0' include its label as well.
591     *ret_label = dfsan_union(
592         base_label,
593         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
594   } else {
595     *ret_label = 0;
596   }
597   return ret;
598 }
599 
600 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_time(time_t * t,dfsan_label t_label,dfsan_label * ret_label)601 time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
602   time_t ret = time(t);
603   if (ret != (time_t) -1 && t) {
604     dfsan_set_label(0, t, sizeof(time_t));
605   }
606   *ret_label = 0;
607   return ret;
608 }
609 
610 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_inet_pton(int af,const char * src,void * dst,dfsan_label af_label,dfsan_label src_label,dfsan_label dst_label,dfsan_label * ret_label)611 int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
612                      dfsan_label src_label, dfsan_label dst_label,
613                      dfsan_label *ret_label) {
614   int ret = inet_pton(af, src, dst);
615   if (ret == 1) {
616     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
617                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
618   }
619   *ret_label = 0;
620   return ret;
621 }
622 
623 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_localtime_r(const time_t * timep,struct tm * result,dfsan_label timep_label,dfsan_label result_label,dfsan_label * ret_label)624 struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
625                               dfsan_label timep_label, dfsan_label result_label,
626                               dfsan_label *ret_label) {
627   struct tm *ret = localtime_r(timep, result);
628   if (ret) {
629     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
630                     sizeof(struct tm));
631     *ret_label = result_label;
632   } else {
633     *ret_label = 0;
634   }
635   return ret;
636 }
637 
638 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_getpwuid_r(id_t uid,struct passwd * pwd,char * buf,size_t buflen,struct passwd ** result,dfsan_label uid_label,dfsan_label pwd_label,dfsan_label buf_label,dfsan_label buflen_label,dfsan_label result_label,dfsan_label * ret_label)639 int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
640                       char *buf, size_t buflen, struct passwd **result,
641                       dfsan_label uid_label, dfsan_label pwd_label,
642                       dfsan_label buf_label, dfsan_label buflen_label,
643                       dfsan_label result_label, dfsan_label *ret_label) {
644   // Store the data in pwd, the strings referenced from pwd in buf, and the
645   // address of pwd in *result.  On failure, NULL is stored in *result.
646   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
647   if (ret == 0) {
648     dfsan_set_label(0, pwd, sizeof(struct passwd));
649     dfsan_set_label(0, buf, strlen(buf) + 1);
650   }
651   *ret_label = 0;
652   dfsan_set_label(0, result, sizeof(struct passwd*));
653   return ret;
654 }
655 
656 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_poll(struct pollfd * fds,nfds_t nfds,int timeout,dfsan_label dfs_label,dfsan_label nfds_label,dfsan_label timeout_label,dfsan_label * ret_label)657 int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
658                 dfsan_label dfs_label, dfsan_label nfds_label,
659                 dfsan_label timeout_label, dfsan_label *ret_label) {
660   int ret = poll(fds, nfds, timeout);
661   if (ret >= 0) {
662     for (; nfds > 0; --nfds) {
663       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
664     }
665   }
666   *ret_label = 0;
667   return ret;
668 }
669 
670 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout,dfsan_label nfds_label,dfsan_label readfds_label,dfsan_label writefds_label,dfsan_label exceptfds_label,dfsan_label timeout_label,dfsan_label * ret_label)671 int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
672                   fd_set *exceptfds, struct timeval *timeout,
673                   dfsan_label nfds_label, dfsan_label readfds_label,
674                   dfsan_label writefds_label, dfsan_label exceptfds_label,
675                   dfsan_label timeout_label, dfsan_label *ret_label) {
676   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
677   // Clear everything (also on error) since their content is either set or
678   // undefined.
679   if (readfds) {
680     dfsan_set_label(0, readfds, sizeof(fd_set));
681   }
682   if (writefds) {
683     dfsan_set_label(0, writefds, sizeof(fd_set));
684   }
685   if (exceptfds) {
686     dfsan_set_label(0, exceptfds, sizeof(fd_set));
687   }
688   dfsan_set_label(0, timeout, sizeof(struct timeval));
689   *ret_label = 0;
690   return ret;
691 }
692 
693 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_sched_getaffinity(pid_t pid,size_t cpusetsize,cpu_set_t * mask,dfsan_label pid_label,dfsan_label cpusetsize_label,dfsan_label mask_label,dfsan_label * ret_label)694 int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
695                              dfsan_label pid_label,
696                              dfsan_label cpusetsize_label,
697                              dfsan_label mask_label, dfsan_label *ret_label) {
698   int ret = sched_getaffinity(pid, cpusetsize, mask);
699   if (ret == 0) {
700     dfsan_set_label(0, mask, cpusetsize);
701   }
702   *ret_label = 0;
703   return ret;
704 }
705 
706 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_sigemptyset(sigset_t * set,dfsan_label set_label,dfsan_label * ret_label)707 int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
708                        dfsan_label *ret_label) {
709   int ret = sigemptyset(set);
710   dfsan_set_label(0, set, sizeof(sigset_t));
711   return ret;
712 }
713 
714 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_sigaction(int signum,const struct sigaction * act,struct sigaction * oldact,dfsan_label signum_label,dfsan_label act_label,dfsan_label oldact_label,dfsan_label * ret_label)715 int __dfsw_sigaction(int signum, const struct sigaction *act,
716                      struct sigaction *oldact, dfsan_label signum_label,
717                      dfsan_label act_label, dfsan_label oldact_label,
718                      dfsan_label *ret_label) {
719   int ret = sigaction(signum, act, oldact);
720   if (oldact) {
721     dfsan_set_label(0, oldact, sizeof(struct sigaction));
722   }
723   *ret_label = 0;
724   return ret;
725 }
726 
727 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_gettimeofday(struct timeval * tv,struct timezone * tz,dfsan_label tv_label,dfsan_label tz_label,dfsan_label * ret_label)728 int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
729                         dfsan_label tv_label, dfsan_label tz_label,
730                         dfsan_label *ret_label) {
731   int ret = gettimeofday(tv, tz);
732   if (tv) {
733     dfsan_set_label(0, tv, sizeof(struct timeval));
734   }
735   if (tz) {
736     dfsan_set_label(0, tz, sizeof(struct timezone));
737   }
738   *ret_label = 0;
739   return ret;
740 }
741 
__dfsw_memchr(void * s,int c,size_t n,dfsan_label s_label,dfsan_label c_label,dfsan_label n_label,dfsan_label * ret_label)742 SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
743                                                   dfsan_label s_label,
744                                                   dfsan_label c_label,
745                                                   dfsan_label n_label,
746                                                   dfsan_label *ret_label) {
747   void *ret = memchr(s, c, n);
748   if (flags().strict_data_dependencies) {
749     *ret_label = ret ? s_label : 0;
750   } else {
751     size_t len =
752         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
753             : n;
754     *ret_label =
755         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
756   }
757   return ret;
758 }
759 
__dfsw_strrchr(char * s,int c,dfsan_label s_label,dfsan_label c_label,dfsan_label * ret_label)760 SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
761                                                    dfsan_label s_label,
762                                                    dfsan_label c_label,
763                                                    dfsan_label *ret_label) {
764   char *ret = strrchr(s, c);
765   if (flags().strict_data_dependencies) {
766     *ret_label = ret ? s_label : 0;
767   } else {
768     *ret_label =
769         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
770                     dfsan_union(s_label, c_label));
771   }
772 
773   return ret;
774 }
775 
__dfsw_strstr(char * haystack,char * needle,dfsan_label haystack_label,dfsan_label needle_label,dfsan_label * ret_label)776 SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
777                                                   dfsan_label haystack_label,
778                                                   dfsan_label needle_label,
779                                                   dfsan_label *ret_label) {
780   char *ret = strstr(haystack, needle);
781   if (flags().strict_data_dependencies) {
782     *ret_label = ret ? haystack_label : 0;
783   } else {
784     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
785     *ret_label =
786         dfsan_union(dfsan_read_label(haystack, len),
787                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
788                                 dfsan_union(haystack_label, needle_label)));
789   }
790 
791   return ret;
792 }
793 
__dfsw_nanosleep(const struct timespec * req,struct timespec * rem,dfsan_label req_label,dfsan_label rem_label,dfsan_label * ret_label)794 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
795                                                    struct timespec *rem,
796                                                    dfsan_label req_label,
797                                                    dfsan_label rem_label,
798                                                    dfsan_label *ret_label) {
799   int ret = nanosleep(req, rem);
800   *ret_label = 0;
801   if (ret == -1) {
802     // Interrupted by a signal, rem is filled with the remaining time.
803     dfsan_set_label(0, rem, sizeof(struct timespec));
804   }
805   return ret;
806 }
807 
808 SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_socketpair(int domain,int type,int protocol,int sv[2],dfsan_label domain_label,dfsan_label type_label,dfsan_label protocol_label,dfsan_label sv_label,dfsan_label * ret_label)809 __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
810                   dfsan_label domain_label, dfsan_label type_label,
811                   dfsan_label protocol_label, dfsan_label sv_label,
812                   dfsan_label *ret_label) {
813   int ret = socketpair(domain, type, protocol, sv);
814   *ret_label = 0;
815   if (ret == 0) {
816     dfsan_set_label(0, sv, sizeof(*sv) * 2);
817   }
818   return ret;
819 }
820 
821 // Type of the trampoline function passed to the custom version of
822 // dfsan_set_write_callback.
823 typedef void (*write_trampoline_t)(
824     void *callback,
825     int fd, const void *buf, ssize_t count,
826     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
827 
828 // Calls to dfsan_set_write_callback() set the values in this struct.
829 // Calls to the custom version of write() read (and invoke) them.
830 static struct {
831   write_trampoline_t write_callback_trampoline = NULL;
832   void *write_callback = NULL;
833 } write_callback_info;
834 
835 SANITIZER_INTERFACE_ATTRIBUTE void
__dfsw_dfsan_set_write_callback(write_trampoline_t write_callback_trampoline,void * write_callback,dfsan_label write_callback_label,dfsan_label * ret_label)836 __dfsw_dfsan_set_write_callback(
837     write_trampoline_t write_callback_trampoline,
838     void *write_callback,
839     dfsan_label write_callback_label,
840     dfsan_label *ret_label) {
841   write_callback_info.write_callback_trampoline = write_callback_trampoline;
842   write_callback_info.write_callback = write_callback;
843 }
844 
845 SANITIZER_INTERFACE_ATTRIBUTE int
__dfsw_write(int fd,const void * buf,size_t count,dfsan_label fd_label,dfsan_label buf_label,dfsan_label count_label,dfsan_label * ret_label)846 __dfsw_write(int fd, const void *buf, size_t count,
847              dfsan_label fd_label, dfsan_label buf_label,
848              dfsan_label count_label, dfsan_label *ret_label) {
849   if (write_callback_info.write_callback != NULL) {
850     write_callback_info.write_callback_trampoline(
851         write_callback_info.write_callback,
852         fd, buf, count,
853         fd_label, buf_label, count_label);
854   }
855 
856   *ret_label = 0;
857   return write(fd, buf, count);
858 }
859 }
860 
861 // Type used to extract a dfsan_label with va_arg()
862 typedef int dfsan_label_va;
863 
864 // Formats a chunk either a constant string or a single format directive (e.g.,
865 // '%.3f').
866 struct Formatter {
FormatterFormatter867   Formatter(char *str_, const char *fmt_, size_t size_)
868       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
869         width(-1) {}
870 
formatFormatter871   int format() {
872     char *tmp_fmt = build_format_string();
873     int retval =
874         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
875                  0 /* used only to avoid warnings */);
876     free(tmp_fmt);
877     return retval;
878   }
879 
formatFormatter880   template <typename T> int format(T arg) {
881     char *tmp_fmt = build_format_string();
882     int retval;
883     if (width >= 0) {
884       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
885                         tmp_fmt, width, arg);
886     } else {
887       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
888                         tmp_fmt, arg);
889     }
890     free(tmp_fmt);
891     return retval;
892   }
893 
build_format_stringFormatter894   char *build_format_string() {
895     size_t fmt_size = fmt_cur - fmt_start + 1;
896     char *new_fmt = (char *)malloc(fmt_size + 1);
897     assert(new_fmt);
898     internal_memcpy(new_fmt, fmt_start, fmt_size);
899     new_fmt[fmt_size] = '\0';
900     return new_fmt;
901   }
902 
str_curFormatter903   char *str_cur() { return str + str_off; }
904 
num_written_bytesFormatter905   size_t num_written_bytes(int retval) {
906     if (retval < 0) {
907       return 0;
908     }
909 
910     size_t num_avail = str_off < size ? size - str_off : 0;
911     if (num_avail == 0) {
912       return 0;
913     }
914 
915     size_t num_written = retval;
916     // A return value of {v,}snprintf of size or more means that the output was
917     // truncated.
918     if (num_written >= num_avail) {
919       num_written -= num_avail;
920     }
921 
922     return num_written;
923   }
924 
925   char *str;
926   size_t str_off;
927   size_t size;
928   const char *fmt_start;
929   const char *fmt_cur;
930   int width;
931 };
932 
933 // Formats the input and propagates the input labels to the output. The output
934 // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
935 // 'ap' are the format string and the list of arguments for formatting. Returns
936 // the return value vsnprintf would return.
937 //
938 // The function tokenizes the format string in chunks representing either a
939 // constant string or a single format directive (e.g., '%.3f') and formats each
940 // chunk independently into the output string. This approach allows to figure
941 // out which bytes of the output string depends on which argument and thus to
942 // propagate labels more precisely.
943 //
944 // WARNING: This implementation does not support conversion specifiers with
945 // positional arguments.
format_buffer(char * str,size_t size,const char * fmt,dfsan_label * va_labels,dfsan_label * ret_label,va_list ap)946 static int format_buffer(char *str, size_t size, const char *fmt,
947                          dfsan_label *va_labels, dfsan_label *ret_label,
948                          va_list ap) {
949   Formatter formatter(str, fmt, size);
950 
951   while (*formatter.fmt_cur) {
952     formatter.fmt_start = formatter.fmt_cur;
953     formatter.width = -1;
954     int retval = 0;
955 
956     if (*formatter.fmt_cur != '%') {
957       // Ordinary character. Consume all the characters until a '%' or the end
958       // of the string.
959       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
960            ++formatter.fmt_cur) {}
961       retval = formatter.format();
962       dfsan_set_label(0, formatter.str_cur(),
963                       formatter.num_written_bytes(retval));
964     } else {
965       // Conversion directive. Consume all the characters until a conversion
966       // specifier or the end of the string.
967       bool end_fmt = false;
968       for (; *formatter.fmt_cur && !end_fmt; ) {
969         switch (*++formatter.fmt_cur) {
970         case 'd':
971         case 'i':
972         case 'o':
973         case 'u':
974         case 'x':
975         case 'X':
976           switch (*(formatter.fmt_cur - 1)) {
977           case 'h':
978             // Also covers the 'hh' case (since the size of the arg is still
979             // an int).
980             retval = formatter.format(va_arg(ap, int));
981             break;
982           case 'l':
983             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
984                 *(formatter.fmt_cur - 2) == 'l') {
985               retval = formatter.format(va_arg(ap, long long int));
986             } else {
987               retval = formatter.format(va_arg(ap, long int));
988             }
989             break;
990           case 'q':
991             retval = formatter.format(va_arg(ap, long long int));
992             break;
993           case 'j':
994             retval = formatter.format(va_arg(ap, intmax_t));
995             break;
996           case 'z':
997           case 't':
998             retval = formatter.format(va_arg(ap, size_t));
999             break;
1000           default:
1001             retval = formatter.format(va_arg(ap, int));
1002           }
1003           dfsan_set_label(*va_labels++, formatter.str_cur(),
1004                           formatter.num_written_bytes(retval));
1005           end_fmt = true;
1006           break;
1007 
1008         case 'a':
1009         case 'A':
1010         case 'e':
1011         case 'E':
1012         case 'f':
1013         case 'F':
1014         case 'g':
1015         case 'G':
1016           if (*(formatter.fmt_cur - 1) == 'L') {
1017             retval = formatter.format(va_arg(ap, long double));
1018           } else {
1019             retval = formatter.format(va_arg(ap, double));
1020           }
1021           dfsan_set_label(*va_labels++, formatter.str_cur(),
1022                           formatter.num_written_bytes(retval));
1023           end_fmt = true;
1024           break;
1025 
1026         case 'c':
1027           retval = formatter.format(va_arg(ap, int));
1028           dfsan_set_label(*va_labels++, formatter.str_cur(),
1029                           formatter.num_written_bytes(retval));
1030           end_fmt = true;
1031           break;
1032 
1033         case 's': {
1034           char *arg = va_arg(ap, char *);
1035           retval = formatter.format(arg);
1036           va_labels++;
1037           internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
1038                           sizeof(dfsan_label) *
1039                               formatter.num_written_bytes(retval));
1040           end_fmt = true;
1041           break;
1042         }
1043 
1044         case 'p':
1045           retval = formatter.format(va_arg(ap, void *));
1046           dfsan_set_label(*va_labels++, formatter.str_cur(),
1047                           formatter.num_written_bytes(retval));
1048           end_fmt = true;
1049           break;
1050 
1051         case 'n': {
1052           int *ptr = va_arg(ap, int *);
1053           *ptr = (int)formatter.str_off;
1054           va_labels++;
1055           dfsan_set_label(0, ptr, sizeof(ptr));
1056           end_fmt = true;
1057           break;
1058         }
1059 
1060         case '%':
1061           retval = formatter.format();
1062           dfsan_set_label(0, formatter.str_cur(),
1063                           formatter.num_written_bytes(retval));
1064           end_fmt = true;
1065           break;
1066 
1067         case '*':
1068           formatter.width = va_arg(ap, int);
1069           va_labels++;
1070           break;
1071 
1072         default:
1073           break;
1074         }
1075       }
1076     }
1077 
1078     if (retval < 0) {
1079       return retval;
1080     }
1081 
1082     formatter.fmt_cur++;
1083     formatter.str_off += retval;
1084   }
1085 
1086   *ret_label = 0;
1087 
1088   // Number of bytes written in total.
1089   return formatter.str_off;
1090 }
1091 
1092 extern "C" {
1093 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_sprintf(char * str,const char * format,dfsan_label str_label,dfsan_label format_label,dfsan_label * va_labels,dfsan_label * ret_label,...)1094 int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
1095                    dfsan_label format_label, dfsan_label *va_labels,
1096                    dfsan_label *ret_label, ...) {
1097   va_list ap;
1098   va_start(ap, ret_label);
1099   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, ap);
1100   va_end(ap);
1101   return ret;
1102 }
1103 
1104 SANITIZER_INTERFACE_ATTRIBUTE
__dfsw_snprintf(char * str,size_t size,const char * format,dfsan_label str_label,dfsan_label size_label,dfsan_label format_label,dfsan_label * va_labels,dfsan_label * ret_label,...)1105 int __dfsw_snprintf(char *str, size_t size, const char *format,
1106                     dfsan_label str_label, dfsan_label size_label,
1107                     dfsan_label format_label, dfsan_label *va_labels,
1108                     dfsan_label *ret_label, ...) {
1109   va_list ap;
1110   va_start(ap, ret_label);
1111   int ret = format_buffer(str, size, format, va_labels, ret_label, ap);
1112   va_end(ap);
1113   return ret;
1114 }
1115 }
1116