diff options
Diffstat (limited to '')
-rwxr-xr-x | mkosi.images/system/mkosi.sanitizers.chroot | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/mkosi.images/system/mkosi.sanitizers.chroot b/mkosi.images/system/mkosi.sanitizers.chroot new file mode 100755 index 0000000..524e3da --- /dev/null +++ b/mkosi.images/system/mkosi.sanitizers.chroot @@ -0,0 +1,127 @@ +#!/bin/bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -e +set -o nounset + +if [[ -z "${SANITIZERS:-}" ]]; then + exit 0 +fi + +# Sanitizers log to stderr by default. However, journald's stderr is connected to /dev/null, so we lose +# all the sanitizer logs. To rectify that, let's connect journald's stdout to kmsg so that the sanitizer +# failures end up in the journal. +mkdir -p /etc/systemd/system/systemd-journald.service.d +cat >/etc/systemd/system/systemd-journald.service.d/10-stdout-tty.conf <<EOF +[Service] +StandardOutput=kmsg +EOF + +# ASAN and syscall filters aren't compatible with each other. +find /usr /etc -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 + +ASAN_RT_PATH="$(grep libasan.so < <(ldd /usr/lib/systemd/systemd) | cut -d ' ' -f 3)" +if [[ -z "$ASAN_RT_PATH" ]]; then + ASAN_RT_PATH="$(grep libclang_rt.asan < <(ldd /usr/lib/systemd/systemd) | cut -d ' ' -f 3)" + + # As clang's ASan DSO is usually in a non-standard path, let's check if the RUNPATH is set accordingly. + if ldd /usr/lib/systemd/systemd | grep -q "libclang_rt.asan.*not found"; then + echo >&2 "clang's ASan DSO libclang_rt.asan is not present in the runtime library path" + exit 1 + fi +fi +if [[ -z "$ASAN_RT_PATH" ]]; then + echo >&2 "systemd is not linked against the ASan DSO" + echo >&2 "gcc does this by default, for clang compile with -shared-libasan" + exit 1 +fi + +wrap=( + /usr/lib/polkit-1/polkitd + /usr/libexec/polkit-1/polkitd + agetty + btrfs + capsh + chgrp + chown + cryptsetup + curl + dbus-broker-launch + dbus-daemon + delv + dhcpd + dig + dmsetup + dnsmasq + findmnt + getent + getfacl + id + integritysetup + iscsid + kpartx + logger + login + ls + lsblk + lvm + mdadm + mkfs.btrfs + mkfs.erofs + mkfs.ext4 + mkfs.vfat + mkfs.xfs + mksquashfs + mkswap + multipath + multipathd + nvme + p11-kit + pkill + ps + setfacl + setpriv + sshd + stat + su + tar + tgtd + useradd + userdel + veritysetup +) + +for bin in "${wrap[@]}"; do + if ! command -v "$bin" >/dev/null; then + continue + fi + + if [[ "$bin" == getent ]]; then + enable_lsan=1 + else + enable_lsan=0 + fi + + target="$(command -v "$bin")" + + mv "$target" "$target.orig" + + cat >"$target" <<EOF +#!/bin/bash +# Preload the ASan runtime DSO, otherwise ASAn will complain +export LD_PRELOAD="$ASAN_RT_PATH" +# Disable LSan to speed things up, since we don't care about leak reports +# from 'external' binaries +export ASAN_OPTIONS=detect_leaks=$enable_lsan +# Set argv[0] to the original binary name without the ".orig" suffix +exec -a "\$0" -- "${target}.orig" "\$@" +EOF + chmod +x "$target" +done + +cat >/usr/lib/systemd/systemd-asan-env <<EOF +LD_PRELOAD=$ASAN_RT_PATH +LSAN_OPTIONS=detect_leaks=0 +EOF |