PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH
-LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE" = "debian" ]] && echo yes || true)
-LOOKS_LIKE_ARCH=$(source /etc/os-release && [[ "$ID" = "arch" ]] && echo yes || true)
-LOOKS_LIKE_SUSE=$(source /etc/os-release && [[ "$ID_LIKE" = "suse" ]] && echo yes || true)
+LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || " $ID_LIKE " = *" debian "* ]] && echo yes || true)
+LOOKS_LIKE_ARCH=$(source /etc/os-release && [[ "$ID" = "arch" || " $ID_LIKE " = *" arch "* ]] && echo yes || true)
+LOOKS_LIKE_SUSE=$(source /etc/os-release && [[ " $ID_LIKE " = *" suse "* ]] && echo yes || true)
KERNEL_VER=${KERNEL_VER-$(uname -r)}
KERNEL_MODS="/lib/modules/$KERNEL_VER/"
QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out
-[[ "$LOOKS_LIKE_SUSE" ]] && FSTYPE="${FSTYPE:-btrfs}" || FSTYPE="${FSTYPE:-ext3}"
+[[ "$LOOKS_LIKE_SUSE" ]] && FSTYPE="${FSTYPE:-btrfs}" || FSTYPE="${FSTYPE:-ext4}"
UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}"
+EFI_MOUNT="$(bootctl -p 2>/dev/null || echo /boot)"
if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
ROOTLIBDIR=/usr/lib/systemd
fi
-BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm"
+BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs"
DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"
STATEFILE="$STATEDIR/.testdir"
TESTLOG="$STATEDIR/test.log"
+is_built_with_asan() {
+ if ! type -P objdump >/dev/null; then
+ ddebug "Failed to find objdump. Assuming systemd hasn't been built with ASAN."
+ return 1
+ fi
+
+ # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
+ local _asan_calls=$(objdump -dC $BUILD_DIR/systemd | egrep "callq\s+[0-9a-f]+\s+<__asan" -c)
+ if (( $_asan_calls < 1000 )); then
+ return 1
+ else
+ return 0
+ fi
+}
+
+IS_BUILT_WITH_ASAN=$(is_built_with_asan && echo yes || echo no)
+
+if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
+ STRIP_BINARIES=no
+fi
+
function find_qemu_bin() {
- # SUSE and Red Hat call the binary qemu-kvm
- # Debian and Gentoo call it kvm
- [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1)
+ # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
+ # Either way, only use this version if we aren't running in KVM, because
+ # nested KVM is flaky still.
+ if [ `systemd-detect-virt -v` != kvm ] ; then
+ [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1)
+ fi
[ "$ARCH" ] || ARCH=$(uname -m)
case $ARCH in
run_qemu() {
if [ -f /etc/machine-id ]; then
read MACHINE_ID < /etc/machine-id
- [ -z "$INITRD" ] && [ -e "/boot/$MACHINE_ID/$KERNEL_VER/initrd" ] \
- && INITRD="/boot/$MACHINE_ID/$KERNEL_VER/initrd"
- [ -z "$KERNEL_BIN" ] && [ -e "/boot/$MACHINE_ID/$KERNEL_VER/linux" ] \
- && KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux"
+ [ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
+ && INITRD="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd"
+ [ -z "$KERNEL_BIN" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux" ] \
+ && KERNEL_BIN="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux"
fi
if [[ ! "$KERNEL_BIN" ]]; then
init=$ROOTLIBDIR/systemd \
console=ttyS0 \
selinux=0 \
+printk.devkmsg=on \
$_cgroup_args \
$KERNEL_APPEND \
"
QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD"
fi
- if [ -c /dev/kvm ]; then
+ # Let's use KVM if it is available, but let's avoid using nested KVM as that is still flaky
+ if [ -c /dev/kvm -a `systemd-detect-virt -v` != kvm ]; then
QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
fi
strip_binaries
install_depmod_files
generate_module_dependencies
+ if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
+ create_asan_wrapper
+ fi
}
setup_selinux() {
chmod 0755 $_valgrind_wrapper
}
+create_asan_wrapper() {
+ local _asan_wrapper=$initdir/$ROOTLIBDIR/systemd-under-asan
+ ddebug "Create $_asan_wrapper"
+ cat >$_asan_wrapper <<EOF
+#!/bin/bash
+
+set -x
+
+DEFAULT_ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
+DEFAULT_ENVIRONMENT=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS
+
+mount -t proc proc /proc
+mount -t sysfs sysfs /sys
+mount -o remount,rw /
+
+PATH_TO_ASAN=\$(find / -name '*libasan*' | sed 1q)
+if [[ "\$PATH_TO_ASAN" ]]; then
+ # A lot of services (most notably dbus) won't start without preloading libasan
+ # See https://github.com/systemd/systemd/issues/5004
+ DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN"
+fi
+echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
+
+# ASAN and syscall filters aren't compatible with each other.
+find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
+
+# 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\n" >"\$JOURNALD_CONF_DIR/env.conf"
+
+export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log
+exec $ROOTLIBDIR/systemd "\$@"
+EOF
+
+ chmod 0755 $_asan_wrapper
+}
+
create_strace_wrapper() {
local _strace_wrapper=$initdir/$ROOTLIBDIR/systemd-under-strace
ddebug "Create $_strace_wrapper"
inst_libdir_file "libdevmapper-event.so*"
if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
# dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
- # see https://anonscm.debian.org/cgit/pkg-lvm/lvm2.git/tree/debian/patches/0007-udev.patch
- inst_rules 55-dm.rules 60-persistent-storage-dm.rules
+ # and since buster/bionic 95-dm-notify.rules
+ # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
+ inst_rules 55-dm.rules 60-persistent-storage-dm.rules 95-dm-notify.rules
else
inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
fi
}
create_empty_image() {
+ local _size=500
+ if [[ "$STRIP_BINARIES" = "no" ]]; then
+ _size=$((2*_size))
+ fi
rm -f "$TESTDIR/rootdisk.img"
# Create the blank file to use as a root filesystem
- dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400
+ dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek="$_size"
LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img)
[ -b "$LOOPDEV" ] || return 1
echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
sfdisk "$LOOPDEV" <<EOF
-,390M
+,$((_size-10))M
,
EOF
+ udevadm settle
+
local _label="-L systemd"
# mkfs.reiserfs doesn't know -L. so, use --label instead
[[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd"
fi
done
[[ $_found ]] || dinfo "Skipping udev rule: $_rule"
+ _found=
done
}
}
setup_suse() {
- ln -s ../usr/bin/systemctl $initdir/bin/systemctl
- ln -s ../usr/lib/systemd $initdir/lib/systemd
+ ln -fs ../usr/bin/systemctl $initdir/bin/
+ ln -fs ../usr/lib/systemd $initdir/lib/
inst_simple "/usr/lib/systemd/system/haveged.service"
}