IS_BUILT_WITH_COVERAGE=$(is_built_with_coverage && echo yes || echo no)
if get_bool "$IS_BUILT_WITH_ASAN"; then
+ PATH_TO_INIT="$ROOTLIBDIR/systemd-under-asan"
SKIP_INITRD="${SKIP_INITRD:-yes}"
- PATH_TO_INIT=$ROOTLIBDIR/systemd-under-asan
QEMU_MEM="${QEMU_MEM:-2G}"
QEMU_SMP="${QEMU_SMP:-4}"
}
create_asan_wrapper() {
- local asan_wrapper="$initdir/$ROOTLIBDIR/systemd-under-asan"
- dinfo "Create ASan wrapper as '$asan_wrapper'"
+ local asan_wrapper default_asan_options default_ubsan_options default_environment
[[ -z "$ASAN_RT_PATH" ]] && dfatal "ASAN_RT_PATH is empty, but it shouldn't be"
- # clang: install llvm-symbolizer to generate useful reports
- # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
- [[ "$ASAN_COMPILER" == "clang" ]] && image_install "llvm-symbolizer"
+ default_asan_options="${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1}"
+ default_ubsan_options="${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1}"
- cat >"$asan_wrapper" <<EOF
-#!/usr/bin/env bash
+ if [[ "$ASAN_COMPILER" == "clang" ]]; then
+ # clang: install llvm-symbolizer to generate useful reports
+ # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
+ image_install "llvm-symbolizer"
-set -x
-
-echo "ASan RT: $ASAN_RT_PATH"
-if [[ ! -e "$ASAN_RT_PATH" ]]; then
- echo >&2 "Couldn't find ASan RT at '$ASAN_RT_PATH', can't continue"
- exit 1
-fi
-
-DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1}
-DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1}
-DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
+ # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
+ # unnecessary for gcc & libasan, however, for clang this is crucial, as its
+ # runtime ASan DSO is in a non-standard (library) path.
+ mkdir -p "${initdir:?}/etc/ld.so.conf.d/"
+ echo "${ASAN_RT_PATH%/*}" >"${initdir:?}/etc/ld.so.conf.d/asan-path-override.conf"
+ fi
-# Create a simple environment file which can be included by systemd services
-# that need it (i.e. services that utilize DynamicUser=true and bash, etc.)
-cat >/usr/lib/systemd/systemd-asan-env <<INNER_EOF
+ # Create a simple environment file which can be included by systemd services
+ # that need it (i.e. services that utilize DynamicUser=true and bash, etc.)
+ cat >"${initdir:?}/usr/lib/systemd/systemd-asan-env" <<EOF
LD_PRELOAD=$ASAN_RT_PATH
-ASAN_OPTIONS=$DEFAULT_ASAN_OPTIONS
+ASAN_OPTIONS=$default_asan_options
LSAN_OPTIONS=detect_leaks=0
-UBSAN_OPTIONS=$DEFAULT_UBSAN_OPTIONS
-INNER_EOF
-
-# As right now bash is the PID 1, we can't expect PATH to have a sane value.
-# Let's make one to prevent unexpected "<bin> not found" issues in the future
-export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
-
-mountpoint -q /proc || mount -t proc proc /proc
-mountpoint -q /sys || mount -t sysfs sysfs /sys
-mount -o remount,rw /
+UBSAN_OPTIONS=$default_ubsan_options
+EOF
-DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT ASAN_RT_PATH=$ASAN_RT_PATH"
+ default_environment=(
+ "ASAN_OPTIONS='$default_asan_options'"
+ "UBSAN_OPTIONS='$default_ubsan_options'"
+ "ASAN_RT_PATH='$ASAN_RT_PATH'"
+ )
-if [[ "$ASAN_COMPILER" == "clang" ]]; then
- # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
- # unnecessary for gcc & libasan, however, for clang this is crucial, as its
- # runtime ASan DSO is in a non-standard (library) path.
- echo "${ASAN_RT_PATH%/*}" >/etc/ld.so.conf.d/asan-path-override.conf
- ldconfig
-fi
-echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
-echo DefaultTimeoutStartSec=180s >>/etc/systemd/system.conf
-echo DefaultStandardOutput=journal+console >>/etc/systemd/system.conf
+ mkdir -p "${initdir:?}/etc/systemd/system.conf.d/"
+ cat >"${initdir:?}/etc/systemd/system.conf.d/asan.conf" <<EOF
+[Manager]
+DefaultEnvironment=${default_environment[*]}
+ManagerEnvironment=${default_environment[*]}
+DefaultTimeoutStartSec=180s
+DefaultStandardOutput=journal+console
+EOF
-# ASAN and syscall filters aren't compatible with each other.
-find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
+ # ASAN and syscall filters aren't compatible with each other.
+ find "${initdir:?}" -name '*.service' -type f -print0 | xargs -0 sed -i 's/^\(MemoryDeny\|SystemCall\)/#\1/'
+ mkdir -p "${initdir:?}/etc/systemd/system/systemd-journald.service.d/"
+ cat >"${initdir:?}/etc/systemd/system/systemd-journald.service.d/asan-env.conf" <<EOF
+[Service]
# The redirection of ASAN reports to a file prevents them from ending up in /dev/null.
# But, apparently, sometimes it doesn't work: https://github.com/google/sanitizers/issues/886.
-JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
-mkdir -p "\$JOURNALD_CONF_DIR"
-printf "[Service]\nEnvironment=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd-journald.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS:log_path=/systemd-journald.ubsan.log\n" >"\$JOURNALD_CONF_DIR/env.conf"
+Environment=ASAN_OPTIONS=$default_asan_options:log_path=/systemd-journald.asan.log UBSAN_OPTIONS=$default_ubsan_options:log_path=/systemd-journald.ubsan.log
# Sometimes UBSan sends its reports to stderr regardless of what is specified in log_path
# Let's try to catch them by redirecting stderr (and stdout just in case) to a file
# See https://github.com/systemd/systemd/pull/12524#issuecomment-491108821
-printf "[Service]\nStandardOutput=file:/systemd-journald.out\n" >"\$JOURNALD_CONF_DIR/out.conf"
+StandardOutput=file:/systemd-journald.out
+EOF
-# 90s isn't enough for some services to finish when literally everything is run
-# under ASan+UBSan in containers, which, in turn, are run in VMs.
-# Let's limit which environments such services should be executed in.
-mkdir -p /etc/systemd/system/systemd-hwdb-update.service.d
-printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=240s\n" >/etc/systemd/system/systemd-hwdb-update.service.d/env-override.conf
+ # 90s isn't enough for some services to finish when literally everything is run
+ # under ASan+UBSan in containers, which, in turn, are run in VMs.
+ # Let's limit which environments such services should be executed in.
+ mkdir -p "${initdir:?}/etc/systemd/system/systemd-hwdb-update.service.d/"
+ cat >"${initdir:?}/etc/systemd/system/systemd-hwdb-update.service.d/asan.conf" <<EOF
+[Unit]
+ConditionVirtualization=container
-# Let's override another hard-coded timeout that kicks in too early
-mkdir -p /etc/systemd/system/systemd-journal-flush.service.d
-printf "[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-journal-flush.service.d/timeout.conf
+[Service]
+TimeoutSec=240s
+EOF
-export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
-exec "$ROOTLIBDIR/systemd" "\$@"
+ # Let's override another hard-coded timeout that kicks in too early
+ mkdir -p "${initdir:?}/etc/systemd/system/systemd-journal-flush.service.d/"
+ cat >"${initdir:?}/etc/systemd/system/systemd-journal-flush.service.d/asan.conf" <<EOF
+[Service]
+TimeoutSec=180s
EOF
+ asan_wrapper="${initdir:?}/${PATH_TO_INIT:?}"
+ # Sanity check to make sure we don't overwrite something we shouldn't.
+ [[ "$asan_wrapper" =~ systemd-under-asan$ ]]
+
+ cat >"$asan_wrapper" <<EOF
+#!/usr/bin/env bash
+set -eux
+
+export ${default_environment[@]}
+[[ -n "\$ASAN_OPTIONS" && -n "\$UBSAN_OPTIONS" ]]
+exec "$ROOTLIBDIR/systemd" "\$@"
+EOF
chmod 0755 "$asan_wrapper"
}