diff --git a/docs/HACKING.md b/docs/HACKING.md index 9e5313e07a..2015a40193 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -66,7 +66,7 @@ reuse the host's package cache. To do this, create a mkosi override file in mkosi.default.d/ (e.g 20-local.conf) and add the following contents: ``` -[Packages] +[Content] Cache= # (e.g. /var/cache/dnf) ``` @@ -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 @@ -224,7 +229,7 @@ mkosi's config. The easiest way to set the option is to create a file 20-local.c add the following contents: ``` -[Packages] +[Content] IncludeDirectory=mkosi.includedir ``` @@ -233,7 +238,7 @@ We already configured clangd to map any paths in /usr/include in the build image host in the mkosi-clangd.sh script. We also need to make sure clangd is installed in the build image. To have mkosi install clangd in the build -image, edit the 20-local.conf file we created earlier and add the following contents under the `[Packages]` +image, edit the 20-local.conf file we created earlier and add the following contents under the `[Content]` section: ``` diff --git a/docs/TESTING_WITH_SANITIZERS.md b/docs/TESTING_WITH_SANITIZERS.md index 4f965c9617..642e1f19c9 100644 --- a/docs/TESTING_WITH_SANITIZERS.md +++ b/docs/TESTING_WITH_SANITIZERS.md @@ -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 diff --git a/mkosi.build b/mkosi.build index 5855868acc..27e5b1c65c 100755 --- a/mkosi.build +++ b/mkosi.build @@ -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 @@ -49,10 +52,10 @@ if [ ! -f "$BUILDDIR"/build.ninja ] ; then init_path=$(realpath /sbin/init 2>/dev/null) if [ -z "$init_path" ] ; then - rootprefix="" + rootprefix="" else - rootprefix=${init_path%/lib/systemd/systemd} - rootprefix=/${rootprefix#/} + rootprefix=${init_path%/lib/systemd/systemd} + rootprefix=/${rootprefix#/} fi meson "$BUILDDIR" \ @@ -60,7 +63,9 @@ if [ ! -f "$BUILDDIR"/build.ninja ] ; then -D "rootprefix=$rootprefix" \ -D man=false \ -D translations=false \ - -D version-tag="${VERSION_TAG}" + -D version-tag="${VERSION_TAG}" \ + -D mode=developer \ + -D b_sanitize="${SANITIZERS:-none}" fi cd "$BUILDDIR" @@ -70,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" @@ -90,32 +103,71 @@ Kernel \r on an \m (\l) EOF if [ -n "$IMAGE_ID" ] ; then - mkdir -p "$DESTDIR"/usr/lib - sed -n \ - -e '/^IMAGE_ID=/!p' \ - -e "\$aIMAGE_ID=$IMAGE_ID" <"/usr/lib/os-release" >"${DESTDIR}/usr/lib/os-release" + mkdir -p "$DESTDIR"/usr/lib + sed -n \ + -e '/^IMAGE_ID=/!p' \ + -e "\$aIMAGE_ID=$IMAGE_ID" <"/usr/lib/os-release" >"${DESTDIR}/usr/lib/os-release" - OSRELEASEFILE="$DESTDIR"/usr/lib/os-release + OSRELEASEFILE="$DESTDIR"/usr/lib/os-release else - OSRELEASEFILE=/usr/lib/os-release + OSRELEASEFILE=/usr/lib/os-release fi if [ -n "$IMAGE_VERSION" ] ; then - mkdir -p "$DESTDIR"/usr/lib - sed -n \ - -e '/^IMAGE_VERSION=/!p' \ - -e "\$aIMAGE_VERSION=$IMAGE_VERSION" <$OSRELEASEFILE >"/tmp/os-release.tmp" + mkdir -p "$DESTDIR"/usr/lib + sed -n \ + -e '/^IMAGE_VERSION=/!p' \ + -e "\$aIMAGE_VERSION=$IMAGE_VERSION" <$OSRELEASEFILE >"/tmp/os-release.tmp" - cat /tmp/os-release.tmp > "$DESTDIR"/usr/lib/os-release - rm /tmp/os-release.tmp + cat /tmp/os-release.tmp > "$DESTDIR"/usr/lib/os-release + rm /tmp/os-release.tmp fi # If $CI_BUILD is set, copy over the CI service which executes a service check # after boot and then shuts down the machine if [ -n "$CI_BUILD" ]; then - mkdir -p "$DESTDIR/usr/lib/systemd/system" - cp -v "$SRCDIR/test/mkosi-check-and-shutdown.service" "$DESTDIR/usr/lib/systemd/system/mkosi-check-and-shutdown.service" - 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" + mkdir -p "$DESTDIR/usr/lib/systemd/system" + cp -v "$SRCDIR/test/mkosi-check-and-shutdown.service" "$DESTDIR/usr/lib/systemd/system/mkosi-check-and-shutdown.service" + 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" < "$DESTDIR/etc/systemd/system/systemd-journald.service.d/10-stdout-tty.conf" < "$DESTDIR/etc/systemd/system/console-getty.service.d/10-no-vhangup.conf" < /dev/null; 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 diff --git a/test/mkosi.default.networkd-test b/test/mkosi.default.networkd-test index 6423417b81..ed3604ccdf 100644 --- a/test/mkosi.default.networkd-test +++ b/test/mkosi.default.networkd-test @@ -21,7 +21,7 @@ Output=networkd-test.raw [Partitions] RootSize=3G -[Packages] +[Content] BuildPackages= audit-libs-devel bzip2-devel