*************** Code Sanitizers *************** Building Packages with Code Sanitizers -------------------------------------- Many times CVEs and other security-related bugs that are reported make use of `Code Sanitizers `_ in order to identify the defective behavior. A few examples of such tools are `AddressSanitizer (ASan) `_, `UndefinedBehaviorSanitizer (UBSan) `_, `ThreadSanitizer (TSan) `_ and `LeakSanitizer (LSan) `_. Frequently, the reporter of a bug or issue will provide a proof of concept or working example that relies on the program or library having been built with code sanitizers support. This article describes what is necessary for building a package with code sanitizers support. ========================= Passing Appropriate Flags ========================= Generally, what is necessary to enable code sanitizers is to pass the appropriate compiler and linker flags to the build. Here AddressSanitizer will be used as example, but the ideas can be generalized for other types of sanitizers. Many Debian packages use ``dpkg-buildflags`` and so the build can be adjusted without modifying ``debian/rules`` by setting environment variables like this:: export DEB_BUILD_OPTIONS='sanitize=+address' # or, for finer control: export DEB_CFLAGS_APPEND=-fsanitize=address export DEB_CPPFLAGS_APPEND=-fsanitize=address export DEB_CXXFLAGS_APPEND=-fsanitize=address export DEB_LDFLAGS_APPEND='-fsanitize=address -static-libasan' # test with: dpkg-buildflags The point of the ``-static-libasan`` flag is to have GCC statically link ASAN without also statically linking everything else. Adding that flag makes installation of the resulting packages easier as they will not depend on the ``libasan`` shared library. That seems to cause issues with C++ programs though ("Your application is linked against incompatible ASan runtimes."). There are instances, depending on the build system, particular compiler, compiler version, and perhaps other factors, where the ``-static-libasan`` flag might lead to linking failures. The failures in that case are of the form undefined reference to ``__asan_[...]``. If that happens, one possible (hacky?) way to address the failure is by modifying the ``LDFLAGS``:: export DEB_LDFLAGS_APPEND='-fsanitize=address -lasan -ldl' ASan may also disturb the build checks, typically from ``./configure``, due to LeakSanitizer (which is enabled with ASan). You can temporarily disable it with: .. code-block:: bash ASAN_OPTIONS=detect_leaks=0 dpkg-buildpackage ... debuild -e ASAN_OPTIONS=detect_leaks=0 ... # For more options: ASAN_OPTIONS=help=1 ./asan-executable There are other flags, like ``-fsanitize=thread``, ``-fsanitize=leak``, ``-fsanitize=undefined``, along with their corresponding ``-static-*`` flags which may be useful depending on the nature of the bug report or vulnerability, for instance with ASAN+UBSAN:: export DEB_BUILD_OPTIONS='sanitize=+address,+undefined' export DEB_CFLAGS_APPEND='-fsanitize=address,undefined' export DEB_CPPFLAGS_APPEND='-fsanitize=address,undefined' export DEB_CXXFLAGS_APPEND='-fsanitize=address,undefined' export DEB_LDFLAGS_APPEND='-fsanitize=address,undefined -static-libasan -static-libubsan' .. note:: GCC `does not support the unsigned-integer-overflow check `_, so one needs to use clang/clang++ to check for that and pass ``-fsanitize=unsigned-integer-overflow`` in addition to ``-fsanitize=undefined``. .. note:: libtool may filter the ``LDFLAGS``; you may need `a patch `_ .. attention:: Beware that ``FORTIFY_SOURCE`` is not officially supported, see `FAQ `_ This approach works for cowbuilder, pbuilder, sbuild, and other build chroot-type environments (including those invoked by git-buildpackage, for example) which will pass the environment variables through. If the package being built does not properly support dpkg-buildflags or if a build method is being used which does not properly handle the environment, then it may be necessary to temporarily modify ``debian/rules`` in order to insert the necessary flags at the appropriate locations. Depending on the package being updated and whether the source is available in Git or some other VCS, it might make sense to create a branch for the temporary modifications to the build. It is also a good idea to leave the changelog in a state that will prevent accidental upload of the package built with ASAN. This can be accomplished by starting a new changelog entry and leaving the suite set to ``UNRELEASED``. Alternatively, `valgrind `_ may be used to assess the presence of an invalid memory access before/after patching. ================ Further Readings ================ Some links which might provide additional information: - `FAQ `_ - `Clang ASAN documentation `_ - `Clang UBSAN documentation `_ - `Whitepaper `_