#49609 Add memory and thread sanitizers
Closed 3 years ago by spichugi. Opened 6 years ago by vashirov.
vashirov/389-ds-base add-sanitizers  into  master

file modified
+47 -18
@@ -18,6 +18,9 @@ 

  DEBUG_DEFINES = @debug_defs@

  GCCSEC_DEFINES = @gccsec_defs@

  ASAN_DEFINES = @asan_defs@

+ MSAN_DEFINES = @msan_defs@

+ TSAN_DEFINES = @tsan_defs@

+ UBSAN_DEFINES = @ubsan_defs@

  

  SYSTEMD_DEFINES = @systemd_defs@

  
@@ -33,7 +36,7 @@ 

  if RUST_ENABLE

  RUST_ON = 1

  CARGO_FLAGS = @cargo_defs@

- RUSTC_FLAGS = @asan_rust_defs@ @debug_rust_defs@

+ RUSTC_FLAGS = @asan_rust_defs@ @msan_rust_defs@ @tsan_rust_defs@ @debug_rust_defs@

  RUST_LDFLAGS = -ldl -lpthread -lgcc_s -lc -lm -lrt -lutil

  RUST_DEFINES = -DRUST_ENABLE

  else
@@ -79,10 +82,32 @@ 

  

  if enable_asan

  ASAN_ON = 1

+ SANITIZER = ASAN

  else

  ASAN_ON = 0

  endif

  

+ if enable_msan

+ MSAN_ON = 1

+ SANITIZER = MSAN

+ else

+ MSAN_ON = 0

+ endif

+ 

+ if enable_tsan

+ TSAN_ON = 1

+ SANITIZER = TSAN

+ else

+ TSAN_ON = 0

+ endif

+ 

+ if enable_ubsan

+ UBSAN_ON = 1

+ SANITIZER = UBSAN

+ else

+ UBSAN_ON = 0

+ endif

+ 

  if with_systemd

  WITH_SYSTEMD = 1

  else
@@ -108,7 +133,7 @@ 

  # Now that we have all our defines in place, setup the CPPFLAGS

  

  # These flags are the "must have" for all components

- AM_CPPFLAGS = $(DEBUG_DEFINES) $(GCCSEC_DEFINES) $(ASAN_DEFINES) $(PROFILING_DEFINES) $(RUST_DEFINES)

+ AM_CPPFLAGS = $(DEBUG_DEFINES) $(GCCSEC_DEFINES) $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_DEFINES) $(RUST_DEFINES)

  # Flags for Directory Server

  # WARNING: This needs a clean up, because slap.h is a horrible mess and is publically exposed!

  DSPLUGIN_CPPFLAGS = $(DS_DEFINES) $(DS_INCLUDES) $(PATH_DEFINES) $(SYSTEMD_DEFINES) $(NUNCSTANS_INCLUDES) @openldap_inc@ @ldapsdk_inc@ @nss_inc@ $(NSPR_INCLUDES) @systemd_inc@
@@ -165,7 +190,7 @@ 

  else

  #AM_LDFLAGS = -Wl,-z,defs

  # Provide the tcmalloc links if needed

- AM_LDFLAGS = $(RUST_LDFLAGS) $(ASAN_DEFINES) $(PROFILING_LINKS) $(TCMALLOC_LINK) $(CLANG_LDFLAGS)

+ AM_LDFLAGS = $(RUST_LDFLAGS) $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(TCMALLOC_LINK) $(CLANG_LDFLAGS)

  endif #end hpux

  

  # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
@@ -2173,37 +2198,37 @@ 

  	src/libsds/test/test_sds_ht.c \

  	src/libsds/test/test_fixtures.c

  

- test_libsds_LDFLAGS = $(ASAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS)

+ test_libsds_LDFLAGS = $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS)

  test_libsds_LDADD = libsds.la $(NSPR_LINK)

  test_libsds_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(SDS_CPPFLAGS)

  

  benchmark_sds_SOURCES =  src/libsds/test/benchmark.c \

  	$(libavl_a_SOURCES)

- benchmark_sds_LDFLAGS = $(ASAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS)

+ benchmark_sds_LDFLAGS = $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS)

  benchmark_sds_LDADD = libsds.la $(NSPR_LINK)

  benchmark_sds_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(SDS_CPPFLAGS) $(DS_INCLUDES)

  

  benchmark_par_sds_SOURCES = src/libsds/test/benchmark_parwrap.c \

  	src/libsds/test/benchmark_par.c \

  	$(libavl_a_SOURCES)

- benchmark_par_sds_LDFLAGS = $(ASAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS)

+ benchmark_par_sds_LDFLAGS = $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS)

  benchmark_par_sds_LDADD = libsds.la $(NSPR_LINK)

  benchmark_par_sds_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(SDS_CPPFLAGS) $(DS_INCLUDES)

  

  test_nuncstans_SOURCES = src/nunc-stans/test/test_nuncstans.c

  test_nuncstans_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(NUNCSTANS_CPPFLAGS)

  test_nuncstans_LDADD = libnunc-stans.la libsds.la $(NSPR_LINK)

- test_nuncstans_LDFLAGS = $(ASAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

+ test_nuncstans_LDFLAGS = $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

  

  test_nuncstans_stress_large_SOURCES = src/nunc-stans/test/test_nuncstans_stress_large.c src/nunc-stans/test/test_nuncstans_stress_core.c

  test_nuncstans_stress_large_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(NUNCSTANS_CPPFLAGS)

  test_nuncstans_stress_large_LDADD = libnunc-stans.la libsds.la $(NSPR_LINK)

- test_nuncstans_stress_large_LDFLAGS = $(ASAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

+ test_nuncstans_stress_large_LDFLAGS = $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

  

  test_nuncstans_stress_small_SOURCES = src/nunc-stans/test/test_nuncstans_stress_small.c src/nunc-stans/test/test_nuncstans_stress_core.c

  test_nuncstans_stress_small_CPPFLAGS = $(AM_CPPFLAGS) $(CMOCKA_INCLUDES) $(NUNCSTANS_CPPFLAGS)

  test_nuncstans_stress_small_LDADD = libnunc-stans.la libsds.la $(NSPR_LINK)

- test_nuncstans_stress_small_LDFLAGS = $(ASAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

+ test_nuncstans_stress_small_LDFLAGS = $(ASAN_DEFINES) $(MSAN_DEFINES) $(TSAN_DEFINES) $(UBSAN_DEFINES) $(PROFILING_LINKS) $(CMOCKA_LINKS) $(EVENT_LINK)

  

  

  endif
@@ -2260,6 +2285,10 @@ 

  	-e 's,@enable_auto_dn_suffix\@,$(enable_auto_dn_suffix),g' \

  	-e 's,@enable_presence\@,$(enable_presence),g' \

  	-e 's,@enable_asan\@,$(ASAN_ON),g' \

+ 	-e 's,@enable_msan\@,$(MSAN_ON),g' \

+ 	-e 's,@enable_tsan\@,$(TSAN_ON),g' \

+ 	-e 's,@enable_ubsan\@,$(UBSAN_ON),g' \

+ 	-e 's,@SANITIZER\@,$(SANITIZER),g' \

  	-e 's,@enable_perl\@,@enable_perl@,g' \

  	-e 's,@ECHO_N\@,$(ECHO_N),g' \

  	-e 's,@ECHO_C\@,$(ECHO_C),g' \
@@ -2321,18 +2350,15 @@ 

  	if [ ! -d $(dir $@) ] ; then mkdir -p $(dir $@) ; fi

  	$(fixupcmd) $^ > $@

  

- 

- if enable_asan

- # yes, that is an @ in the filename . . .

- %/$(PACKAGE_NAME)@.service: %/systemd.template.asan.service.in

- 	if [ ! -d $(dir $@) ] ; then mkdir -p $(dir $@) ; fi

- 	$(fixupcmd) $^ > $@

- else

  # yes, that is an @ in the filename . . .

  %/$(PACKAGE_NAME)@.service: %/systemd.template.service.in

  	if [ ! -d $(dir $@) ] ; then mkdir -p $(dir $@) ; fi

- 	$(fixupcmd) $^ > $@

- endif

+ 	if [ ! -z ${SANITIZER} ] ; then \

+ 		service_template=$(shell echo $^ | sed 's/template/template.xsan/g'); \

+ 		else \

+ 		service_template=$^; \

+ 	fi; \

+ 	$(fixupcmd) $$service_template > $@

  

  %/$(PACKAGE_NAME).systemd: %/systemd.template.sysconfig

  	if [ ! -d $(dir $@) ] ; then mkdir -p $(dir $@) ; fi
@@ -2399,6 +2425,9 @@ 

  		-e "s/__RUST_ON__/$(RUST_ON)/" \

  		-e "s/__CLANG_ON__/$(CLANG_ON)/" \

  		-e "s/__PERL_ON__/$(PERL_ON)/" \

+ 		-e "s/__MSAN_ON__/$(MSAN_ON)/" \

+ 		-e "s/__TSAN_ON__/$(TSAN_ON)/" \

+ 		-e "s/__UBSAN_ON__/$(UBSAN_ON)/" \

  		-e "s/__ASAN_ON__/$(ASAN_ON)/" < $(abs_builddir)/rpm/389-ds-base.spec > $(RPMBUILD)/SPECS/389-ds-base.spec

  

  # Requires rpmdevtools. Consider making this a dependancy of rpms.

file modified
+49 -1
@@ -122,7 +122,7 @@ 

  AM_CONDITIONAL([DEBUG],[test -n "$with_debug"])

  

  AC_MSG_CHECKING(for --enable-asan)

- AC_ARG_ENABLE(asan, AS_HELP_STRING([--enable-asan], [Enable gcc address sanitizer options (default: no)]),

+ AC_ARG_ENABLE(asan, AS_HELP_STRING([--enable-asan], [Enable gcc/clang address sanitizer options (default: no)]),

  [

    AC_MSG_RESULT(yes)

    asan_defs="-fsanitize=address -fno-omit-frame-pointer"
@@ -137,6 +137,54 @@ 

  AC_SUBST([asan_rust_defs])

  AM_CONDITIONAL(enable_asan,test "$enable_asan" = "yes")

  

+ AC_MSG_CHECKING(for --enable-msan)

+ AC_ARG_ENABLE(msan, AS_HELP_STRING([--enable-msan], [Enable gcc/clang memory sanitizer options (default: no)]),

+ [

+   AC_MSG_RESULT(yes)

+   msan_defs="-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer"

+   msan_rust_defs="-Z sanitizer=memory"

+ ],

+ [

+   AC_MSG_RESULT(no)

+   msan_defs=""

+   msan_rust_defs=""

+ ])

+ AC_SUBST([msan_defs])

+ AC_SUBST([msan_rust_defs])

+ AM_CONDITIONAL(enable_msan,test "$enable_msan" = "yes")

+ 

+ AC_MSG_CHECKING(for --enable-tsan)

+ AC_ARG_ENABLE(tsan, AS_HELP_STRING([--enable-tsan], [Enable gcc/clang thread sanitizer options (default: no)]),

+ [

+   AC_MSG_RESULT(yes)

+   tsan_defs="-fsanitize=thread -fno-omit-frame-pointer"

+   tsan_rust_defs="-Z sanitizer=thread"

+ ],

+ [

+   AC_MSG_RESULT(no)

+   tsan_defs=""

+   tsan_rust_defs=""

+ ])

+ AC_SUBST([tsan_defs])

+ AC_SUBST([tsan_rust_defs])

+ AM_CONDITIONAL(enable_tsan,test "$enable_tsan" = "yes")

+ 

+ AC_MSG_CHECKING(for --enable-ubsan)

+ AC_ARG_ENABLE(ubsan, AS_HELP_STRING([--enable-tsan], [Enable gcc/clang undefined behaviour sanitizer options (default: no)]),

+ [

+   AC_MSG_RESULT(yes)

+   ubsan_defs="-fsanitize=undefined -fno-omit-frame-pointer"

+   ubsan_rust_defs=""

+ ],

+ [

+   AC_MSG_RESULT(no)

+   ubsan_defs=""

+   ubsan_rust_defs=""

+ ])

+ AC_SUBST([ubsan_defs])

+ AC_SUBST([ubsan_rust_defs])

+ AM_CONDITIONAL(enable_ubsan,test "$enable_ubsan" = "yes")

+ 

  # Enable CLANG

  AC_MSG_CHECKING(for --enable-clang)

  AC_ARG_ENABLE(clang, AS_HELP_STRING([--enable-clang], [Enable clang (default: no)]),

file modified
+14 -1
@@ -9,10 +9,20 @@ 

  NAME_VERSION = $(PACKAGE)-$(RPM_VERSION)$(VERSION_PREREL)

  TARBALL = $(NAME_VERSION).tar.bz2

  NUNC_STANS_ON = 1

+ 

+ # Some sanitizers are supported only by clang

+ CLANG_ON = 0

+ # Address Sanitizer

  ASAN_ON = 0

+ # Memory Sanitizer (clang only)

+ MSAN_ON = 0

+ # Thread Sanitizer

+ TSAN_ON = 0

+ # Undefined Behaviour Sanitizer

+ UBSAN_ON = 0

+ 

  RUST_ON = 0

  PERL_ON = 1

- CLANG_ON = 0

  

  clean:

  	rm -rf dist
@@ -40,6 +50,9 @@ 

  	-e s/__NUNC_STANS_ON__/$(NUNC_STANS_ON)/ \

  	-e s/__RUST_ON__/$(RUST_ON)/ \

  	-e s/__ASAN_ON__/$(ASAN_ON)/ \

+ 	-e s/__MSAN_ON__/$(MSAN_ON)/ \

+ 	-e s/__TSAN_ON__/$(TSAN_ON)/ \

+ 	-e s/__UBSAN_ON__/$(UBSAN_ON)/ \

  	-e s/__PERL_ON__/$(PERL_ON)/ \

  	-e s/__CLANG_ON__/$(CLANG_ON)/ \

  	rpm/$(PACKAGE).spec.in > $(RPMBUILD)/SPECS/$(PACKAGE).spec

file modified
+44 -9
@@ -14,8 +14,11 @@ 

  # If perl-Socket-2.000 or newer is available, set 0 to use_Socket6.

  %global use_Socket6 0

  

- # This enables an ASAN build. This should not go to production, so we rename.

+ # This enables a sanitized build. This should not go to production, so we rename.

  %global use_asan __ASAN_ON__

+ %global use_msan __MSAN_ON__

+ %global use_tsan __TSAN_ON__

+ %global use_ubsan __UBSAN_ON__

  

  # This enables rust in the build.

  %global use_rust __RUST_ON__
@@ -25,9 +28,9 @@ 

  %define nspr_version 4.6

  %define nss_version 3.11

  

- %if %{use_asan}

+ %if %{use_asan} || %{use_msan} || %{use_tsan} || %{use_ubsan}

  %global use_tcmalloc 0

- %global variant base-asan

+ %global variant base-xsan

  %else

  %if %{_arch} != "s390x" && %{_arch} != "s390" && !%{use_rust}

  %global use_tcmalloc 1
@@ -76,8 +79,18 @@ 

  %if %{use_clang}

  BuildRequires:    libatomic

  BuildRequires:    clang

+ BuildRequires:    compiler-rt

  %else

  BuildRequires:    gcc-c++

+ %if %{use_asan}

+ BuildRequires:    libasan

+ %endif

+ %if %{use_tsan}

+ BuildRequires:    libtsan

+ %endif

+ %if %{use_ubsan}

+ BuildRequires:    libubsan

+ %endif

  %endif

  # The following are needed to build the snmp ldap-agent

  BuildRequires:    net-snmp-devel
@@ -89,9 +102,6 @@ 

  BuildRequires:    pam-devel

  BuildRequires:    systemd-units

  BuildRequires:    systemd-devel

- %if %{use_asan}

- BuildRequires:    libasan

- %endif

  # If rust is enabled

  %if %{use_rust}

  BuildRequires: cargo
@@ -200,9 +210,19 @@ 

  Requires:         cyrus-sasl-lib

  # KRB

  Requires:         krb5-libs

+ %if %{use_clang}

+ Requires:         llvm

+ Requires:         compiler-rt

+ %else

  %if %{use_asan}

- Requires:    libasan

- Requires:    llvm

+ Requires:         libasan

+ %endif

+ %if %{use_tsan}

+ Requires:         libtsan

+ %endif

+ %if %{use_ubsan}

+ Requires:         libubsan

+ %endif

  %endif

  

  %description      libs
@@ -294,6 +314,18 @@ 

  ASAN_FLAGS="--enable-asan --enable-debug"

  %endif

  

+ %if %{use_msan} && !%{use_rust}

+ MSAN_FLAGS="--enable-msan --enable-debug"

+ %endif

+ 

+ %if %{use_tsan} && !%{use_rust}

+ TSAN_FLAGS="--enable-tsan --enable-debug"

+ %endif

+ 

+ %if %{use_ubsan} && !%{use_rust}

+ UBSAN_FLAGS="--enable-ubsan --enable-debug"

+ %endif

+ 

  %if %{use_tcmalloc}

  TCMALLOC_FLAGS="--enable-tcmalloc"

  %endif
@@ -314,7 +346,7 @@ 

             --with-systemdsystemunitdir=%{_unitdir} \

             --with-systemdsystemconfdir=%{_sysconfdir}/systemd/system \

             --with-systemdgroupname=%{groupname} \

-            $NSSARGS $TCMALLOC_FLAGS $ASAN_FLAGS $RUST_FLAGS $PERL_FLAGS $CLANG_FLAGS \

+            $NSSARGS $TCMALLOC_FLAGS $ASAN_FLAGS $MSAN_FLAGS $TSAN_FLAGS $UBSAN_FLAGS $RUST_FLAGS $PERL_FLAGS $CLANG_FLAGS \

             --enable-cmocka

  

  %if 0%{?rhel} > 7 || 0%{?fedora}
@@ -376,6 +408,9 @@ 

  

  %check

  # This checks the code, if it fails it prints why, then re-raises the fail to shortcircuit the rpm build.

+ %if %{use_tsan}

+ export TSAN_OPTIONS=print_stacktrace=1:second_deadlock_stack=1:history_size=7

+ %endif

  if ! make DESTDIR="$RPM_BUILD_ROOT" check; then cat ./test-suite.log && false; fi

  

  %clean

wrappers/systemd.template.xsan.service.in wrappers/systemd.template.asan.service.in
file renamed
+12 -2
@@ -13,7 +13,7 @@ 

  # systemctl daemon-reload 

  # systemctl (re)start @systemdgroupname@

  [Unit]

- Description=@capbrand@ Directory Server with ASAN %i.

+ Description=@capbrand@ Directory Server with @SANITIZER@ %i.

  PartOf=@systemdgroupname@

  After=chronyd.service ntpd.service network-online.target syslog.target

  Before=radiusd.service
@@ -27,10 +27,20 @@ 

  EnvironmentFile=@initconfigdir@/@package_name@-%i

  PIDFile=@localstatedir@/run/@package_name@/slapd-%i.pid

  # We can't symbolize here, as llvm symbolize crashes when it goes near systemd.

- Environment=ASAN_OPTIONS=log_path=@localstatedir@/run/@package_name@/ns-slapd-%i.asan

+ Environment=ASAN_OPTIONS=log_path=@localstatedir@/run/@package_name@/ns-slapd-%i.asan:print_stacktrace=1

+ Environment=TSAN_OPTIONS=log_path=@localstatedir@/run/@package_name@/ns-slapd-%i.tsan:print_stacktrace=1:second_deadlock_stack=1:history_size=7

+ Environment=MSAN_OPTIONS=log_path=@localstatedir@/run/@package_name@/ns-slapd-%i.msan:print_stacktrace=1

+ Environment=UBSAN_OPTIONS=log_path=@localstatedir@/run/@package_name@/ns-slapd-%i.ubsan:print_stacktrace=1

  LimitCORE=infinity

  ExecStartPre=@sbindir@/ds_systemd_ask_password_acl @instconfigdir@/slapd-%i/dse.ldif

  ExecStart=@sbindir@/ns-slapd -D @instconfigdir@/slapd-%i -i @localstatedir@/run/@package_name@/slapd-%i.pid

+ 

+ # Hardening options:

+ # PrivateDevices=true

+ # ProtectSystem=true

+ # ProtectHome=true

+ # PrivateTmp=true

+ 

  # if you need to set other directives e.g. LimitNOFILE=8192

  # set them in this file

  .include @initconfigdir@/@package_name@.systemd

Both gcc and clang provide memory and thread sanitizers, see
https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
https://clang.llvm.org/docs/MemorySanitizer.html
https://clang.llvm.org/docs/ThreadSanitizer.html

This adds configure options --enable-msan and --enable-tsan for memory
and thread sanitizer respectively. These options can't be used together (only one sanitizer at a time: ASAN, MSAN or TSAN).

With TSAN nunc-stans tests fail (during make check) with potential deadlock warning; setup-ds.pl fails to create an instance because of data race warnings and potential deadlocks in nunc-stans.
With MSAN server fails to start and instance can't be created. But that's possibly due to many false positives that come from non-instrumented libraries (nss and nspr in particular).

https://pagure.io/389-ds-base/issue/49608

This looks great! Ack from me :) Can't wait to fix up some of the TSAN issues :)

rebased onto 819c4bcb247d7b92dd1d40f09fac393ea4c052cd

6 years ago

@firstyear, thanks! I've added support for undefined behaviour sanitizer as well, please check the updated commit.

ubsan looks good too, another ack from me.

rebased onto 5ba0181

6 years ago

Pull-Request has been merged by vashirov

6 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/2668

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago