Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion dkms.in
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ readonly dkms_framework_nonsigning_variables="source_tree dkms_tree install_tree
verbose symlink_modules autoinstall_all_kernels modprobe_on_install parallel_jobs
compress_gzip_opts compress_xz_opts compress_zstd_opts build_environment post_transaction"
# All of the signing related variables we will accept from framework.conf.
readonly dkms_framework_signing_variables="sign_file mok_signing_key mok_certificate"
readonly dkms_framework_signing_variables="sign_file mok_signing_key mok_certificate
try_sign_modules"

# The post transaction command we will accept from framework.conf
readonly dkms_framework_post_transaction="post_transaction"
Expand Down Expand Up @@ -1174,6 +1175,37 @@ run_build_script() {
fi
}

# A relatively straightforward port of the Linux-kernel-specific part of
# Debian's "ischroot" command
# (https://salsa.debian.org/debian/debianutils/-/blob/9d4fc3502659adc02ed7b0457bf77e88be3a971a/ischroot.c)
# to Bash. Used for determining whether or not to sign kernel modules. Returns
# 0 when running in a chroot, 1 when likely running outside of a chroot.
running_in_chroot() {
# Check for fakechroot usage. Works without root.
# shellcheck disable=SC2076
[[ "${FAKECHROOT-}" == 'true' && -v FAKECHROOT_BASE && "${LD_PRELOAD-}" =~ 'libfakechroot.so' ]] && return 0

# Check if our view of /proc/PID/mountinfo differs from the init process's view. Works without root.
if [[ -r /proc/1/mountinfo && -r /proc/self/mountinfo ]]; then
local init_mountinfo
local our_mountinfo
IFS= read -rd '' init_mountinfo < '/proc/1/mountinfo'
IFS= read -rd '' our_mountinfo < '/proc/self/mountinfo'
[[ "${init_mountinfo}" != "${our_mountinfo}" ]] && return 0
fi

# Check if our root directory differs from the init process's root directory, using inode and device numbers. Requires root.
if [[ "$(id -u)" = 0 ]]; then
local init_rootdir_info
local our_rootdir_info
init_rootdir_info="$(stat -L --format='%d %i' /proc/1/root)"
our_rootdir_info="$(stat -L --format='%d %i' /)"
[[ "${init_rootdir_info}" != "${our_rootdir_info}" ]] && return 0
fi

return 1
}

# Register a DKMS-ified source tree with DKMS.
# This function is smart enough to register the module if we
# passed a source tree or a tarball instead of relying on the source tree
Expand Down Expand Up @@ -1343,6 +1375,17 @@ prepare_signing()

do_signing=0

if [[ "${try_sign_modules-}" = 'false' ]]; then
echo "Module signing is disabled by policy, modules won't be signed"
return
fi

# if try_sign_modules is not "true" here, always act as if it is set to "not_in_chroot"
if [[ "${try_sign_modules-}" != 'true' ]] && running_in_chroot; then
echo "Running in chroot, modules won't be signed"
return
fi

if [[ ! -f ${kernel_config} ]]; then
echo "Kernel config ${kernel_config} not found, modules won't be signed"
return
Expand Down
4 changes: 4 additions & 0 deletions dkms_framework.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
# represent the target kernel version. (default: depends on distribution):
# sign_file="/path/to/sign-file"

# Whether to try to sign modules. May be set to "true", "false", or
# "not_in_chroot". (default: not_in_chroot)
# try_sign_modules=not_in_chroot

# Location of the key and certificate files used for Secure boot. $kernelver
# can be used in path to represent the target kernel version.
#
Expand Down
87 changes: 87 additions & 0 deletions run_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,33 @@ file_not_exists() {
fi
}

# Check if the tests are running in a chroot. Copied from dkms main script.
running_in_chroot() {
# Check for fakechroot usage. Works without root.
# shellcheck disable=SC2076
[[ "${FAKECHROOT-}" == 'true' && -v FAKECHROOT_BASE && "${LD_PRELOAD-}" =~ 'libfakechroot.so' ]] && return 0

# Check if our view of /proc/PID/mountinfo differs from the init process's view. Works without root.
if [[ -r /proc/1/mountinfo && -r /proc/self/mountinfo ]]; then
local init_mountinfo
local our_mountinfo
IFS= read -rd '' init_mountinfo < '/proc/1/mountinfo'
IFS= read -rd '' our_mountinfo < '/proc/self/mountinfo'
[[ "${init_mountinfo}" != "${our_mountinfo}" ]] && return 0
fi

# Check if our root directory differs from the init process's root directory, using inode and device numbers. Requires root.
if [[ "$(id -u)" = 0 ]]; then
local init_rootdir_info
local our_rootdir_info
init_rootdir_info="$(stat -L --format='%d %i' /proc/1/root)"
our_rootdir_info="$(stat -L --format='%d %i' /)"
[[ "${init_rootdir_info}" != "${our_rootdir_info}" ]] && return 0
fi

return 1
}

mod_compression_ext=
kernel_config="/lib/modules/${KERNEL_VER}/build/.config"
if [[ -f $kernel_config ]]; then
Expand All @@ -353,6 +380,12 @@ if [[ -f $kernel_config ]]; then
fi
fi

is_running_in_chroot=false
if running_in_chroot; then
is_running_in_chroot=true
fi
try_sign_modules_file='/etc/dkms/framework.conf.d/try_sign_modules.conf'

# Compute the expected destination module location
os_id="$(sed -n 's/^ID\s*=\s*\(.*\)$/\1/p' /etc/os-release | tr -d '"')"
distro_sign_file_candidates=
Expand Down Expand Up @@ -431,6 +464,11 @@ DKMS_VERSION="$(dkms --version)"
echo 'Preparing a clean test environment'
clean_dkms_env

if [[ $is_running_in_chroot = true ]] && (( NO_SIGNING_TOOL == 0 )); then
echo 'Enabling module signing in chroot'
install_framework_conf test/framework/try_sign_modules_true.conf "${try_sign_modules_file}"
fi

echo 'Test that there are no dkms modules installed'
run_with_expected_output dkms status -k "${KERNEL_VER}" << EOF
EOF
Expand Down Expand Up @@ -967,6 +1005,55 @@ Before uninstall, this module version was ACTIVE on this kernel.
Deleting /lib/modules/${KERNEL_VER}/${expected_dest_loc}/dkms_test.ko${mod_compression_ext}
Running depmod... done.

Deleting module dkms_test/1.0 completely from the DKMS tree.
EOF
run_status_with_expected_output 'dkms_test' << EOF
EOF

echo 'Adding the test module'
run_with_expected_output dkms add test/dkms_test-1.0 << EOF
Creating symlink /var/lib/dkms/dkms_test/1.0/source -> /usr/src/dkms_test-1.0
EOF
check_module_source_tree_created /usr/src/dkms_test-1.0
run_status_with_expected_output 'dkms_test' << EOF
dkms_test/1.0: added
EOF

echo 'Building the test module with try_sign_modules=false'
install_framework_conf test/framework/try_sign_modules_false.conf "${try_sign_modules_file}"
run_with_expected_output dkms build -k "${KERNEL_VER}" -m dkms_test -v 1.0 --force << EOF
Module signing is disabled by policy, modules won't be signed

Building module(s)... done.
EOF

echo 'Building the test module with try_sign_modules=true'
install_framework_conf test/framework/try_sign_modules_true.conf "${try_sign_modules_file}"
run_with_expected_output dkms build -k "${KERNEL_VER}" -m dkms_test -v 1.0 --force << EOF
${SIGNING_PROLOGUE_tmp_key_cert}
Building module(s)... done.${SIGNING_MESSAGE}
EOF

if [[ $is_running_in_chroot = true ]]; then
echo 'Building the test module in a chroot with try_sign_modules=not_in_chroot'
install_framework_conf test/framework/try_sign_modules_not_in_chroot.conf "${try_sign_modules_file}"
run_with_expected_output dkms build -k "${KERNEL_VER}" -m dkms_test -v 1.0 --force << EOF
Running in chroot, modules won't be signed

Building module(s)... done.
EOF

echo 'Re-enabling module signing in chroot'
install_framework_conf test/framework/try_sign_modules_true.conf "${try_sign_modules_file}"
else
echo 'Removing try_sign_modules configuration'
rm "${try_sign_modules_file}"
fi

echo 'Removing the test module'
run_with_expected_output dkms remove -k "${KERNEL_VER}" -m dkms_test -v 1.0 << EOF
Module dkms_test/1.0 is not installed for kernel ${KERNEL_VER} (${KERNEL_ARCH}). Skipping...

Deleting module dkms_test/1.0 completely from the DKMS tree.
EOF
run_status_with_expected_output 'dkms_test' << EOF
Expand Down
1 change: 1 addition & 0 deletions test/framework/try_sign_modules_false.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
try_sign_modules=false
1 change: 1 addition & 0 deletions test/framework/try_sign_modules_not_in_chroot.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
try_sign_modules=not_in_chroot
1 change: 1 addition & 0 deletions test/framework/try_sign_modules_true.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
try_sign_modules=true