want to do it locally as well. The process slightly varies depending on the
compiler you want to use and which part of the test suite you want to run.
+## mkosi
+
+To build with sanitizers in mkosi, create a file 20-local.conf in mkosi.default.d/ and add the following
+contents:
+
+```
+[Content]
+Environment=SANITIZERS=address,undefined
+```
+
+The value of `SANITIZERS` is passed directly to meson's `b_sanitize` option, See
+https://mesonbuild.com/Builtin-options.html#base-options for the format expected by the option. Currently,
+only the sanitizers supported by gcc can be used, which are `address` and `undefined`.
+
+Note that this will only work with a recent version of mkosi (>= 14 or by running mkosi directly from source).
+
## gcc
gcc compiles in sanitizer libraries dynamically by default, so you need to get
the shared libraries first - on Fedora these are shipped as a separate packages
# This is a build script for OS image generation using mkosi (https://github.com/systemd/mkosi).
# Simply invoke "mkosi" in the project directory to build an OS image.
+ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:disable_coredump=0:use_madv_dontdump=1
+UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
+
# On Fedora "ld" is (unfortunately — if you ask me) managed via
# "alternatives". Since we'd like to support building images in environments
# with only /usr/ around (e.g. mkosi's UsrOnly=1 option), we have the problem
-D man=false \
-D translations=false \
-D version-tag="${VERSION_TAG}" \
- -D mode=developer
+ -D mode=developer \
+ -D b_sanitize="${SANITIZERS:-none}"
fi
cd "$BUILDDIR"
getent group $id >/dev/null || groupadd -g $id testgroup$id
done
- ninja test
+ if [ -n "$SANITIZERS" ]; then
+ export ASAN_OPTIONS="$ASAN_OPTIONS"
+ export UBSAN_OPTIONS="$UBSAN_OPTIONS"
+ TIMEOUT_MULTIPLIER=3
+ else
+ TIMEOUT_MULTIPLIER=1
+ fi
+
+ meson test --timeout-multiplier=$TIMEOUT_MULTIPLIER
fi
cd "$SRCDIR"
cp -v "$SRCDIR/test/mkosi-check-and-shutdown.sh" "$DESTDIR/usr/lib/systemd/mkosi-check-and-shutdown.sh"
chmod +x "$DESTDIR/usr/lib/systemd/mkosi-check-and-shutdown.sh"
fi
+
+if [ -n "$SANITIZERS" ]; then
+ LD_PRELOAD=$(ldd $BUILDDIR/systemd | grep libasan.so | awk '{print $3}')
+
+ mkdir -p "$DESTDIR/etc/systemd/system.conf.d"
+
+ cat > "$DESTDIR/etc/systemd/system.conf.d/10-asan.conf" <<EOF
+[Manager]
+ManagerEnvironment=ASAN_OPTIONS=$ASAN_OPTIONS\\
+ UBSAN_OPTIONS=$UBSAN_OPTIONS\\
+ LD_PRELOAD=$LD_PRELOAD
+DefaultEnvironment=ASAN_OPTIONS=$ASAN_OPTIONS\\
+ UBSAN_OPTIONS=$UBSAN_OPTIONS\\
+ LD_PRELOAD=$LD_PRELOAD
+EOF
+
+ # ASAN logs to stderr by default. However, journald's stderr is connected to /dev/null, so we lose
+ # all the ASAN logs. To rectify that, let's connect journald's stdout to the console so that any
+ # sanitizer failures appear directly on the user's console.
+ mkdir -p "$DESTDIR/etc/systemd/system/systemd-journald.service.d"
+
+ cat > "$DESTDIR/etc/systemd/system/systemd-journald.service.d/10-stdout-tty.conf" <<EOF
+[Service]
+StandardOutput=tty
+EOF
+
+ # Both systemd and util-linux's login call vhangup() on /dev/console which disconnects all users.
+ # This means systemd-journald can't log to /dev/console even if we configure `StandardOutput=tty`. As
+ # a workaround, we modify console-getty.service to disable systemd's vhangup() and disallow login
+ # from calling vhangup() so that journald's ASAN logs correctly end up in the console.
+
+ mkdir -p "$DESTDIR/etc/systemd/system/console-getty.service.d"
+
+ cat > "$DESTDIR/etc/systemd/system/console-getty.service.d/10-no-vhangup.conf" <<EOF
+[Service]
+TTYVHangup=no
+CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
+EOF
+fi
#!/bin/sh
# SPDX-License-Identifier: LGPL-2.1-or-later
-if [ "$1" = "final" ] && command -v bootctl > /dev/null && [ -d "/efi" ]; then
- bootctl install
+if [ "$1" = "final" ]; then
+ if command -v bootctl > /dev/null && [ -d "/efi" ]; then
+ bootctl install
+ fi
+
+ if [ -n "$SANITIZERS" ]; then
+ # ASAN and syscall filters aren't compatible with each other.
+ find / -name '*.service' -type f -exec sed -i 's/^\(MemoryDeny\|SystemCall\)/# \1/' {} +
+
+ # `systemd-hwdb update` takes > 50s when built with sanitizers so let's not run it by default.
+ systemctl mask systemd-hwdb-update.service
+ fi
fi
# Temporary workaround until https://github.com/openSUSE/suse-module-tools/commit/158643414ddb8d8208016a5f03a4484d58944d7a