On 05.06.2018 20:47, Valery Ushakov wrote: > Kamil Rytarowski <n54%gmx.com@localhost> wrote: > >> On 05.06.2018 18:14, Valery Ushakov wrote: >>> Kamil Rytarowski <n54%gmx.com@localhost> wrote: >>> >>>> We've faced a problem with sanitizing part of the NetBSD userland, as we >>>> need to use helper functions to make sanitization possible in some >>>> narrow cases that aren't clear for sanitizers. >>>> >>>> The current problem is the usage of callback functions defined in >>>> programs and executed from the internals of libc. >>> [...] >>>> Once a callback function is executed from the internals of libc, a >>>> sanitized program does not know whether the arguments passed to it are >>>> properly initialized. >>> >>> Why? What makes calling from libc special? It's probably obvious to >>> you since you've been workign on this for a while, but most of us have >>> no clue. > [...] >> In the fts_open(3) case, there is performed allocation of FTSENT >> entries inside libc and this buffer is passed to the callback >> function without prior notifying the user of fts_open(3) about these >> elements (their address and size of initialized buffer). MSan does >> not know whether the passed arguments to the arguments of the >> callback are initialized or not. > > So the issue is that libc is compiled without sanitizer and > allocations done inside libc are not known to a sanitizer? For libc > functions that return allocated memory I guess you mark it in the > sanitizer's interposed wrapper ("interceptor"?), but in the case of > callbacks there is no interceptor between libc and the callback to do > that. Is that about right? > > -uwe > libc is compiled without sanitizer. This is the design of sanitizers that libc, libm, libpthread and librt (+ libdl for Linux) are treated mostly as blackbox libraries. Sanitizers mostly want to look at them from high level API and install interceptors for their public symbols - unless a symbol is out of interest (most of them aren't interesting, the interesting ones are mostly the ones that pass or receive anything over a pointer). If someone intends to find bugs in libc, the proper tool is Valgrind. This means that sanitizers are not a replacement for Valgrind, but a different tool, however both can detect similar bugs. Actually sanitizers might know about part of allocations inside libc (malloc(3) interceptor, mmap(2) interceptor), and can know about some initialization inside libc.. but in general the sanitizers have no information what happens inside libc, treating it as a blackbox. Every sanitizer behaves differently and is optimized for its purpose to detect leaks, unitialized memory, out of bounds access, threading issues etc - some of them might disable e.g. recursive interceptors, others not. The most senstive one is Memory Sanitizer and we are now using it to detect integration bugs, we can already chroot into a functional memory sanitized userland.. however the set of programs is still restricted. As a part of sanitization of userland there is a process of building all other libraries with a dedicated sanitizer, as e.g. editline(3) can call a sigaction(3) internally, with initialized arguments using inlined code. Interceptos mostly have rules of type PreRead/PostRead and PreWrite/PostWrite arguments passed to functions in libc (pthread, ..). In the MSan case during PreWrite there is a check whether arguments passed to a function are properly initialized, and in PostRead phase mark the buffers as initialized. In the fts_open(3) case there is no stage between the time of being aware about initialzed (not just allocated) FTSENT buffers and executing callback function that already needs this information. In this case, there is need to help to Memory Sanitizer with explicit __msan_unpoison(). There are similar cases when someone is using syscall(2) directly. There are helper macros and functions to make usage of syscall(2)-like API easier, e.g. for write(2): __sanitizer_syscall_pre_write(fd, buf, nbyte) res = write(fd, buf, nbyte) __sanitizer_syscall_post_write(res, fd, buf, nbyte) There are also other helper functions for other sanitizers, but so far nothing else was detected to be required. I don't want to keep redefining preprocessor ifdefs in every base userland program (unless in external/), so I've exported the ifdefing switches to a dedicated header.
Attachment:
signature.asc
Description: OpenPGP digital signature