ci: deal with uninstrumented binaries using instrumented libs
All `eject` tests were failing under ASan, since they call /bin/mount, which is uninstrumented, but it picks up the instrumented `libblkid` library, causing ASan to complain: gcc: 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. eject: unmount of `/home/runner/work/util-linux/util-linux/tests/output/eject/umount-by-disk-mounted-mnt' failed clang: /bin/umount: symbol lookup error: /home/runner/work/util-linux/util-linux/.libs/libblkid.so.1: undefined symbol: __sancov_lowest_stack eject: unmount of `/home/runner/work/util-linux/util-linux/tests/output/eject/umount-by-disk-mounted-mnt' failed Subsequently, all tests which require the `scsi_debug` module get skipped, since it's still in use due to the failed umount: fdisk: align 512/4K ... SKIPPED (cannot remove scsi_debug module (rmmod)) fdisk: align 512/4K +alignment_offset ... SKIPPED (cannot remove scsi_debug module (rmmod)) fdisk: align 512/4K +MD ... SKIPPED (cannot remove scsi_debug module (rmmod)) In case of gcc this can be easily resolved by setting $LD_PRELOAD to the respective ASan library. clang makes this a bit more difficult, since it compiles the ASan library statically, so firstly we need to force dynamic linking (via -shared-asan), and then add the runtime DSO path to the linker cache, since it's in a non-standard path.
This commit is contained in:
parent
c40b3cd03d
commit
81edf9f0da
|
@ -7,9 +7,13 @@ COMPILER_VERSION="${COMPILER_VERSION}"
|
|||
if [[ "$COMPILER" == clang ]]; then
|
||||
CC="clang${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
CXX="clang++${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
CFLAGS="-shared-libasan -O1 -g -fno-omit-frame-pointer"
|
||||
CXXFLAGS="-shared-libasan -O1 -g -fno-omit-frame-pointer"
|
||||
elif [[ "$COMPILER" == gcc ]]; then
|
||||
CC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
CXX="g++${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
CFLAGS="-O1 -g -fno-omit-frame-pointer"
|
||||
CXXFLAGS="-O1 -g -fno-omit-frame-pointer"
|
||||
fi
|
||||
|
||||
set -ex
|
||||
|
@ -35,7 +39,7 @@ for phase in "${PHASES[@]}"; do
|
|||
sudo -E git clean -xdf
|
||||
|
||||
./autogen.sh
|
||||
CC=$CC CXX=$CXX ./configure $opts
|
||||
CC=$CC CXX=$CXX CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" ./configure $opts
|
||||
;;
|
||||
MAKE)
|
||||
make -j
|
||||
|
@ -45,6 +49,34 @@ for phase in "${PHASES[@]}"; do
|
|||
make install DESTDIR=/tmp/dest
|
||||
;;
|
||||
CHECK)
|
||||
# All the following black magic is to make test/eject/umount work, since
|
||||
# eject execl()s the uninstrumented /bin/umount binary, which confuses
|
||||
# ASan. The workaround for this is to set $LD_PRELOAD to the ASan's
|
||||
# runtime DSO, which works well with gcc without any additional hassle.
|
||||
# However, since clang, by default, links ASan statically, we need to
|
||||
# explicitly state we want dynamic linking (see -shared-libasan above).
|
||||
# That, however, introduces another issue - clang's ASan runtime is in
|
||||
# a non-standard path, so all binaries compiled in such way refuse
|
||||
# to start. That's what the following blob of code is for - it detects
|
||||
# the ASan's runtime path and adds the respective directory to
|
||||
# the dynamic linker cache.
|
||||
#
|
||||
# The actual $LD_PRELOAD sheanigans are done directly in
|
||||
# tests/ts/eject/umount.
|
||||
asan_rt_name="$(ldd ./kill | awk '/lib.+asan.*.so/ {print $1; exit}')"
|
||||
asan_rt_path="$($CC --print-file-name "$asan_rt_name")"
|
||||
echo "Detected ASan runtime: $asan_rt_name ($asan_rt_path)"
|
||||
if [[ -z "$asan_rt_name" || -z "$asan_rt_path" ]]; then
|
||||
echo >&2 "Couldn't detect ASan runtime, can't continue"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$COMPILER" == clang* ]]; then
|
||||
mkdir -p /etc/ld.so.conf.d/
|
||||
echo "${asan_rt_path%/*}" > /etc/ld.so.conf.d/99-clang-libasan.conf
|
||||
ldconfig
|
||||
fi
|
||||
|
||||
./tests/run.sh --show-diff
|
||||
;;
|
||||
DISTCHECK)
|
||||
|
|
|
@ -103,7 +103,7 @@ nodist_EXTRA_test_fdisk_script_fuzz_SOURCES = dummy.cxx
|
|||
|
||||
test_fdisk_script_fuzz_SOURCES = libfdisk/src/script.c
|
||||
test_fdisk_script_fuzz_CFLAGS = -DFUZZ_TARGET $(libfdisk_la_CFLAGS) $(NO_UNUSED_WARN_CFLAGS)
|
||||
test_fdisk_script_fuzz_LDFLAGS = $(libfdisk_tests_ldflags)
|
||||
test_fdisk_script_fuzz_LDFLAGS = $(libfdisk_tests_ldflags) -lpthread
|
||||
test_fdisk_script_fuzz_LDADD = $(libfdisk_tests_ldadd) $(LIB_FUZZING_ENGINE)
|
||||
endif
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ test_mount_fuzz_SOURCES = libmount/src/fuzz.c
|
|||
nodist_EXTRA_test_mount_fuzz_SOURCES = dummy.cxx
|
||||
|
||||
test_mount_fuzz_CFLAGS = $(libmount_tests_cflags)
|
||||
test_mount_fuzz_LDFLAGS = $(libmount_tests_ldflags)
|
||||
test_mount_fuzz_LDFLAGS = $(libmount_tests_ldflags) -lpthread
|
||||
test_mount_fuzz_LDADD = $(libmount_tests_ldadd) $(LIB_FUZZING_ENGINE)
|
||||
endif
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ nodist_EXTRA_test_last_fuzz_SOURCES = dummy.cxx
|
|||
|
||||
test_last_fuzz_SOURCES = login-utils/last.c
|
||||
test_last_fuzz_CFLAGS = $(AM_CFLAGS) -DFUZZ_TARGET
|
||||
test_last_fuzz_LDFLAGS = -lpthread
|
||||
test_last_fuzz_LDADD = $(LDADD) libcommon.la $(LIB_FUZZING_ENGINE)
|
||||
endif
|
||||
|
||||
|
|
|
@ -1078,3 +1078,17 @@ function ts_has_ncurses_support {
|
|||
echo "no"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get path to the ASan runtime DSO the given binary was compiled with
|
||||
function ts_get_asan_rt_path {
|
||||
local binary="${1?}"
|
||||
local rt_path
|
||||
|
||||
ts_check_prog "ldd"
|
||||
ts_check_prog "awk"
|
||||
|
||||
rt_path="$(ldd "$binary" | awk '/lib.+asan.*.so/ {print $3; exit}')"
|
||||
if [ -n "$rt_path" -a -f "$rt_path" ]; then
|
||||
echo "$rt_path"
|
||||
fi
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ ts_init "$*"
|
|||
|
||||
ts_check_test_command "$TS_CMD_FDISK"
|
||||
ts_check_test_command "$TS_CMD_EJECT"
|
||||
ts_check_test_command "$TS_CMD_KILL"
|
||||
ts_check_test_command "$TS_CMD_MOUNT"
|
||||
|
||||
ts_skip_nonroot
|
||||
|
@ -59,6 +60,13 @@ function deinit_device {
|
|||
ts_scsi_debug_rmmod
|
||||
}
|
||||
|
||||
# As the eject binary execl()s an uninstrumented /bin/umount binary, we need
|
||||
# to explicitly $LD_PRELOAD the ASan's runtime DSO, otherwise ASan will complain.
|
||||
# Since all three utilities used by this test (eject, fdisk, mount) are just
|
||||
# libtool wrappers, let's check the kill binary instead, which should have
|
||||
# the needed DSO information.
|
||||
ASAN_RT_PATH="$(ts_get_asan_rt_path "$TS_CMD_KILL")"
|
||||
[ -n "$ASAN_RT_PATH" ] && export LD_PRELOAD="$ASAN_RT_PATH:$LD_PRELOAD"
|
||||
|
||||
ts_init_subtest "by-disk"
|
||||
init_device
|
||||
|
|
|
@ -20,6 +20,9 @@ ts_init "$*"
|
|||
|
||||
ts_check_test_command "$TS_HELPER_LIBFDISK_SCRIPT_FUZZ"
|
||||
|
||||
ASAN_RT_PATH="$(ts_get_asan_rt_path "$TS_HELPER_LIBFDISK_SCRIPT_FUZZ")"
|
||||
[ -n "$ASAN_RT_PATH" ] && export LD_PRELOAD="$ASAN_RT_PATH:$LD_PRELOAD"
|
||||
|
||||
mkdir -p ${TS_OUTPUT}_workdir
|
||||
ts_run $TS_HELPER_LIBFDISK_SCRIPT_FUZZ ${TS_OUTPUT}_workdir ${TS_SCRIPT}_files -max_total_time=10 >$TS_OUTPUT 2>$TS_ERRLOG
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ ts_init "$*"
|
|||
|
||||
ts_check_test_command "$TS_HELPER_LAST_FUZZ"
|
||||
|
||||
ASAN_RT_PATH="$(ts_get_asan_rt_path "$TS_HELPER_LAST_FUZZ")"
|
||||
[ -n "$ASAN_RT_PATH" ] && export LD_PRELOAD="$ASAN_RT_PATH:$LD_PRELOAD"
|
||||
|
||||
mkdir -p ${TS_OUTPUT}_workdir
|
||||
ts_run $TS_HELPER_LAST_FUZZ ${TS_OUTPUT}_workdir ${TS_SCRIPT}_files -max_total_time=10 >$TS_OUTPUT 2>$TS_ERRLOG
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ ts_init "$*"
|
|||
|
||||
ts_check_test_command "$TS_HELPER_LIBMOUNT_FUZZ"
|
||||
|
||||
ASAN_RT_PATH="$(ts_get_asan_rt_path "$TS_HELPER_LIBMOUNT_FUZZ")"
|
||||
[ -n "$ASAN_RT_PATH" ] && export LD_PRELOAD="$ASAN_RT_PATH:$LD_PRELOAD"
|
||||
|
||||
mkdir -p ${TS_OUTPUT}_workdir
|
||||
ts_run $TS_HELPER_LIBMOUNT_FUZZ ${TS_OUTPUT}_workdir ${TS_SCRIPT}_files -max_total_time=10 >$TS_OUTPUT 2>$TS_ERRLOG
|
||||
|
||||
|
|
Loading…
Reference in New Issue