=====Sanitizers===== ====memory==== int main(int argc, char **argv) { int x[10]; x[0] = 1; return x[argc]; } clang -fsanitize=memory -g main.c -o main $ clang -fsanitize=memory -g main5.c -o main5 && ./main5==3981==WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x492d5e in main /tmp/main5.c:4:3 #1 0x7f592c432461 in __libc_start_main .../sys-libs/glibc-2.25-r9/work/glibc-2.25/csu/../csu/libc-start.c:295 #2 0x41a129 in _start (/tmp/main5+0x41a129) SUMMARY: MemorySanitizer: use-of-uninitialized-value /tmp/main5.c:4:3 in main [[prog:valgrind|valgrind]] détecte l'erreur. ==4011== Syscall param exit_group(status) contains uninitialised byte(s) ==4011== at 0x4F002B8: _Exit (_exit.c:31) ==4011== by 0x4E70423: __run_exit_handlers (exit.c:98) ==4011== by 0x4E704DC: exit (exit.c:105) ==4011== by 0x4E58468: (below main) (libc-start.c:329) ==4011== Uninitialised value was created by a stack allocation ==4011== at 0x400470: main (main5.c:1) Instrumentation de la stdlib : L'utilisation de la libraire standard crée de nombreux faux positifs si la stdlib n'est pas instrumentée. Pour l'instrumenter, il faut suivre les instructions de [[https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo|MemorySanitizerLibcxxHowTo]] {{ :prog:clang:memorysanitizerlibcxxhowto_google_sanitizers_wiki_2020-02-13_22_56_51_.html |Archive du 29/01/2016 le 13/02/2020}} Ma tentative : * unwind de gcc sans sanitize : [[https://github.com/llvm-mirror/libunwind/blob/master/docs/BuildingLibunwind.rst|Building libunwind]] {{ :prog:clang:libunwind_buildinglibunwind.rst_at_master_llvm-mirror_libunwind_2020-02-13_22_58_36_.html |Archive du 29/01/2019 le 13/02/2020}} * libc++ and libc++abi avec -fsanitizer ([[https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo|MemorySanitizerLibcxxHowTo]]). Ajouter ''LDFLAGS=%%"%%-L .../llvm-project/build/lib/clang/8.0.0/x86_64-unknown-linux-gnu/lib -lunwind%%"%%'' si nécessaire. * compilation de poppler avec libc++ de clang [[https://github.com/google/oss-fuzz/blob/master/projects/poppler/build.sh]] LDFLAGS="-L .../llvm-project/build/lib/clang/8.0.0/x86_64-unknown-linux-gnu/lib -lunwind -L.../llvm-project_libcxx_msan/build/lib -lc++abi" CFLAGS="-fsanitize=memory -stdlib=libc++ -I.../llvm-project_libcxx_msan/build/include -I.../llvm-project_libcxx_msan/build/include/c++/v1" CXXFLAGS="-fsanitize=memory -stdlib=libc++ -I.../llvm-project_libcxx_msan/build/include -I.../llvm-project_libcxx_msan/build/include/c++/v1" cmake .. -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ * Compilation du programme de test sans succès : clang++ -L .../llvm-project/build/lib/clang/8.0.0/x86_64-unknown-linux-gnu/lib -lunwind -L .../llvm-project_libcxx_msan/build/lib -lc++abi -fsanitize=memory,fuzzer -stdlib=libc++ -I.../llvm-project_libcxx_msan/build/include -I.../llvm-project_libcxx_msan/build/include/c++/v1 -I ~/info/programmation/poppler/cpp/ pdf_fuzzer.cc -o fuzz_target -L ~/info/programmation/poppler/build/ -lpoppler -L ~/info/programmation/poppler/build/cpp/ -lpoppler-cpp ====Control Flow Integrity==== [[https://www.usenix.org/sites/default/files/conference/protected-files/enigma_slides_serebryany.pdf|Sanitize, Fuzz, and Harden Your C++ Code]], {{ :prog:clang:enigma_slides_serebryany.pdf |Archive}} Nécessite l'option ''Gold'' de ''llvm''. Il est possible d'activer tous les cfi-* (''cfi-vcall'', ''cfi-ncall'', ''cfi-icall'', ''cfi-derived-cast'', ''cfi-unrelated-cast'') en une seule fois : ''-fsanitize=cfi''. ===Exemple 1=== #include void Bad() { puts("BOOO"); } struct Expr { long a[2]; long (*Op)(long *); }; int main(int argc, char **argv) { struct Expr e; // On écrit indirectement sur la variable Op. e.a[2 * argc] = (long)&Bad; e.Op(e.a); } * Sans le sanitizer clang a.c && ./a.out BOOO * Avec le sanitizer clang -flto -fsanitize=cfi -fvisibility=hidden -fno-sanitize-trap=cfi -g a.c && ./a.out file.cpp:11:3: runtime error: control flow integrity check for type 'long (long *)' failed during indirect function call file.cpp:2: note: Bad() defined here SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior cfi_cast_strict.cpp:11:3 in [[prog:valgrind|valgrind]] ne détecte pas l'erreur. ===Exemple 2=== void Bad() { puts("BOOO"); exit(0); } int main(int argc, char **argv) { long array[10]; array[argc * 13] = (long)&Bad; } Nécessite l'option ''Gold'' de ''llvm''. L'exemple ne marche que pour du 64 bits. * Sans protection clang a.c && ./a.out BOOO Segmentation fault * Avec protection ''safe-stack'' clang -fsanitize=safe-stack a.c && ./a.out Pas de message d'erreur... * Avec protection ''cfi'' clang++ cfi_cast_strict.cpp -O0 -fsanitize=cfi -flto=thin -fvisibility=hidden -fno-sanitize-trap=cfi BOOO UndefinedBehaviorSanitizer:DEADLYSIGNAL ==12856==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x7f6e125389a0 (pc 0x7f6e125389a0 bp 0x7ffcbb5f9370 sp 0x7ffcbb5f92a8 T12856) ==12856==The signal is caused by a READ memory access. ==12856==Hint: PC is at a non-executable region. Maybe a wild jump? #0 0x7f6e125389a0 (/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libstdc++.so.6+0x2209a0) UndefinedBehaviorSanitizer can not provide additional info. SUMMARY: UndefinedBehaviorSanitizer: SEGV (/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libstdc++.so.6+0x2209a0) ==12856==ABORTING [[prog:valgrind|valgrind]] détecte l'erreur. =====Erreurs===== ====runtime error: control flow integrity check for type '...' failed during cast to unrelated type (vtable address 0x000000000000)==== Le fait que l'adresse de la ''vtable'' soit nulle indique que la classe n'en a pas. Si une ou plusieurs méthodes sont déclarés virtuelles, elles ont été optimisées par le compilateur. La solution est donc de supprimer (après vérification) la déclaration ''virtual''. [[https://bugs.chromium.org/p/chromium/issues/detail?id=515973|Issue 515973: Invalid cast in SkTArray.h]] {{ :prog:clang:515973_-_invalid_cast_in_sktarray.h_-_chromium_2021-06-20_12_00_33_.html |Archive du 31/07/2015 le 20/06/2021}} [[https://codereview.chromium.org/1259143006/patch/1/10001|Unified Diff: include/core/SkTArray.h]] {{ :prog:clang:include_core_sktarray.h_-_issue_1259143006_remove_unnecessary_virtual_destructor_on_sktarray_-_code_review_2021-06-20_12_02_40_.html |Archive du 31/07/2015 le 20/06/2021}} ====cast to unrelated type aligned_buffer.h==== /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/include/g++-v11/ext/aligned_buffer.h:115:16: runtime error: control flow integrity check for type '...' failed during cast to unrelated type (vtable address 0x747365742f617461) 0x747365742f617461: note: invalid vtable /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/include/g++-v11/ext/aligned_buffer.h:115:16: note: check failed in ..., vtable located in (unknown) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/include/g++-v11/ext/aligned_buffer.h:115:16 in L'utilisation de ''std::make_shared'' couplé avec le ''-fsanitize=cfi'' peu poser problème. Le constructeur de ''shared_ptr'' va vouloir caster la zone mémoire avant d'appeler le constructeur. La zone mémoire étant non initialisée, le sanitizer ne va pas reconnaitre le pointeur ''vtable''. Ce problème existe dans l'implémentation sous clang et gcc. ''clang'' a résolu le problème en ajoutant '' _LIBCPP_NO_CFI'' à la fonction ''%%_Storage::__get_elem%%'' dans le fichier ''memory''. Pour ''gcc'', il faut faire la même chose avec ''%%__attribute__((__no_sanitize__("cfi")))%%'' pour les fonctions ''%%__aligned_buffer::%%_M_ptr'' dans le fichier ''aligned_buffer.h''. [[https://www.mail-archive.com/llvm-bugs@lists.llvm.org/msg48282.html|New: Recent shared_ptr storage change causes CFI cast failures during make_shared]] {{ :prog:clang:llvm-bugs_bug_48993_new_recent_shared_ptr_storage_change_https_reviews.llvm.org_d91201_causes_cfi_cast_failures_during_make_shared_2021-06-23_21_13_22_.html |Archive du 01/02/2021 le 23/06/2021}} [[https://reviews.llvm.org/D95827|Avoid cast before T is constructed to pacify CFI checks]] {{ :prog:clang:⚙_d95827_avoid_cast_t_before_t_is_constructed_to_pacify_cfi_checks_2021-06-23_21_13_34_.html |Archive du 01/02/2021 le 23/06/2021}} [[https://reviews.llvm.org/D96063|Disable CFI in __get_elem to allow casting a pointer to uninitialized memory]] {{ :prog:clang:⚙_d96063_🍒_disable_cfi_in_get_elem_to_allow_casting_a_pointer_to_uninitialized_memory_2021-06-23_21_14_00_.html |Archive du 04/02/2021 le 23/06/2021}} ====RTTI symbol not found for class==== Pour diagnostiquer une erreur de sanitizer, il est possible de mettre un point d'arrêt avec [[prog:clang#gdb|gdb]]. Il est possible d'avoir des warnings de la part de gdb à propos de RTTI (''warning: RTTI symbol not found for class''). Dans ce cas, le plantage du sanitizer cfi est probablement un faux positif car il travaille sur les informations RTTI. Exemple de message d'erreur généré par le sanitizer à l'exécution. /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.1/include/g++-v11/bits/std_function.h:590:9: runtime error: control flow integrity check for type 'std::unique_ptr (const std::_Any_data &)' failed during indirect function call /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.1/include/g++-v11/bits/std_function.h:289: note: std::_Function_handler (), std::__future_base::_State_baseV2::_Setter, std::shared_ptr const&> >::_M_invoke(std::_Any_data const&) defined here /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.1/include/g++-v11/bits/std_function.h:590:9: note: check failed in /mnt/c/j/build/clang_cfi/test/backend/data/test_load_vertical_eccentric, destination function located in /mnt/c/j/build/clang_cfi/_deps/restbed-build/librestbed.so.4 SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.1/include/g++-v11/bits/std_function.h:590:9 in Dans cet exemple, la classe ''restbed::Response'' a bien été compilée avec l'option ''%%__attribute__((visibility ("default")))%%''. Ces erreurs peuvent apparaître quand le sanitizer travaille avec une librairie dynamique. Pour que le sanitizer cfi réussisse son travail, il faut que les librairies compilées avec le sanitizer cfi soient liées statiquement. ====ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.==== Comme le titre l'indique, il faut définir ''LD_PRELOAD''. Cela peut être le cas si un module python utilise une extension en C++ qui a été compilé via un sanitizer. export LD_PRELOAD=$(g++ -print-file-name=libasan.so) [[https://stackoverflow.com/questions/75847374/using-memory-sanitizer-asan-on-c-c-library-loaded-to-python-with-ctypes|Using memory sanitizer (asan) on C/C++ library loaded to python with ctypes]] {{ :prog:clang:gcc_-_using_memory_sanitizer_asan_on_c_c_library_loaded_to_python_with_ctypes_-_stack_overflow_15_11_2023_10_00_17_.html |Archive du 26/03/2023 le 15/11/2023}} =====gdb===== Pour arrêter le debug lors d'une erreur, on peut utiliser les symboles : __ubsan::ScopedReport::~ScopedReport __tsan::ReportRace [[https://stackoverflow.com/questions/30809022/how-can-i-break-on-ubsan-reports-in-gdb-and-continue|How can I break on UBSan reports in gdb and continue?]] {{ :prog:gcc:c_-_how_can_i_break_on_ubsan_reports_in_gdb_and_continue_-_stack_overflow_2021-04-18_19_24_58_.html |Archive du 12/06/2015 le 18/04/2021}}