]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mkosi: Changes to allow booting with sanitizers in mkosi
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 15 Jul 2022 00:26:52 +0000 (02:26 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 18 Jul 2022 14:54:56 +0000 (16:54 +0200)
- Extra memory because ASAN needs it
- The environment variables to make the sanitizers more useful
- LD_PRELOAD because the ASAN DSO needs to be the first in the list
- The sanitizer library packages
- Disable syscall filters because they interfere with ASAN
- Disable systemd-hwdb-update because it's super slow when systemd-hwdb
  is built with sanitizers
- Take the value for meson's b_sanitize option from the SANITIZERS
  environment variable

docs/HACKING.md
docs/TESTING_WITH_SANITIZERS.md
mkosi.build
mkosi.default.d/10-systemd.conf
mkosi.default.d/centos_epel/10-mkosi.centos_epel
mkosi.default.d/debian/10-mkosi.debian
mkosi.default.d/fedora/10-mkosi.fedora
mkosi.default.d/opensuse/10-mkosi.opensuse
mkosi.default.d/ubuntu/10-mkosi.ubuntu
mkosi.postinst

index 9e5313e07a2f5fcbf94290bcb1f0d52a82dae278..a74d0468e5e2f81176807e12e5dc5276e60157e9 100644 (file)
@@ -140,6 +140,11 @@ enabled that are suitable when hacking on systemd (such as internal
 documentation consistency checks). Those are not useful when compiling for
 distribution and can be disabled by setting `-Dmode=release`.
 
+## Sanitizers in mkosi
+
+See [Testing systemd using sanitizers](TESTING_WITH_SANITIZERS.md) for more information
+on how to build with sanitizers enabled in mkosi.
+
 ## Fuzzers
 
 systemd includes fuzzers in `src/fuzz/` that use libFuzzer and are automatically
index 4f965c961785e5e432b325e720f11f23e0aafe0e..642e1f19c9776af811965cb3fcf8a1356c372598 100644 (file)
@@ -13,6 +13,22 @@ This is mostly done automagically by various CI systems for each PR, but you may
 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
index 2be8fdbda1836b86323806da14e839f5103bd45e..27e5b1c65c575b515646f5d3390a85bfe6c8df56 100755 (executable)
@@ -5,6 +5,9 @@ set -e
 # 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
@@ -61,7 +64,8 @@ if [ ! -f "$BUILDDIR"/build.ninja ] ; then
                 -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"
@@ -71,7 +75,15 @@ if [ "$WITH_TESTS" = 1 ] ; then
                 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"
 
@@ -120,3 +132,42 @@ if [ -n "$CI_BUILD" ]; then
         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
index 08a03f489b02279c4d0b9b290552cf072bfe32f5..24b85ddd0bb3eae64fdcd04f210f69f8bc316389 100644 (file)
@@ -6,6 +6,8 @@
 Format=gpt_btrfs
 Bootable=yes
 HostonlyInitrd=yes
+# Prevent ASAN warnings when building the image
+Environment=ASAN_OPTIONS=verify_asan_link_order=false
 
 [Packages]
 BuildDirectory=mkosi.builddir
@@ -16,6 +18,7 @@ SourceFileTransferFinal=copy-git-others
 [Host]
 QemuHeadless=yes
 NetworkVeth=yes
+QemuMem=2G
 
 [Validation]
 Password=
index 42b3c11629365dd6c3e5d850ade66e28a282da94..086fcdb555e13a28a4974e126e308f1225522eb3 100644 (file)
@@ -78,6 +78,8 @@ Packages=
         e2fsprogs
         # xxd is provided by the vim-common package
         vim-common
+        libasan
+        libubsan
         # Required to run systemd-networkd-tests.py
         python3
         iproute
index 44e8521d9a8dfd450a2b51d5179190d1271af56a..9b77b5b832695611f42ab5e63f3ef55e71c31ec4 100644 (file)
@@ -74,6 +74,8 @@ Packages=
         nano
         strace
         xxd
+        # Provides libasan/libubsan
+        gcc
         # Required to run systemd-networkd-tests.py
         python3
         iproute2
index a6b58c758953d9ad2a38fe57ece3fe0e37661801..0314a2faab3affd006b0ec64a47d68900fae2698 100644 (file)
@@ -77,6 +77,9 @@ Packages=
         compsize
         # xxd is provided by the vim-common package
         vim-common
+        # Sanitizers
+        libasan
+        libubsan
         # Required to run systemd-networkd-tests.py
         python
         iproute
index 53fe2f3c9388e78ce5c1833f69b21a40cc8dceaf..b1ca38175940df7d6abc482c16fe8858d8c68301 100644 (file)
@@ -75,3 +75,5 @@ Packages=
         util-linux
         # xxd is provided by the vim package
         vim
+        # Provides libasan/libubsan
+        gcc
index 0a54547f8724d17fe64412049608e545e0d3469a..dfb0ec0fd5f32763dbd5903a2fb15c6419cb2f0c 100644 (file)
@@ -72,6 +72,8 @@ Packages=
         nano
         strace
         xxd
+        # Provides libasan/libubsan
+        gcc
         # Required to run systemd-networkd-tests.py
         python3
         iproute2
index 6eddadfea8c4393207e0c88abeab48ae712cb978..8817818a949c8d04948158786ddaeb55383e0099 100755 (executable)
@@ -1,8 +1,18 @@
 #!/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