Skip to content

Commit f7cf59e

Browse files
ArrayBolt3scaronni
authored andcommitted
Add configuration option for enabling and disabling module signing
In some situations (such as when building a redistributable system image), it is desirable to suppress module signing and the generation of a Machine Owner Key, even if the system supports module signing. Introduce a new configuration option, "try_sign_modules", which allows one to explicitly enable or disable the module signing system. As publicly redistributable images are often built in a chroot, and should virtually never have a MOK generated at image build time, disable module signing by default when running in a chroot. Fixes: #574
1 parent 1efec99 commit f7cf59e

File tree

6 files changed

+138
-1
lines changed

6 files changed

+138
-1
lines changed

dkms.in

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ readonly dkms_framework_nonsigning_variables="source_tree dkms_tree install_tree
105105
verbose symlink_modules autoinstall_all_kernels modprobe_on_install parallel_jobs
106106
compress_gzip_opts compress_xz_opts compress_zstd_opts build_environment post_transaction"
107107
# All of the signing related variables we will accept from framework.conf.
108-
readonly dkms_framework_signing_variables="sign_file mok_signing_key mok_certificate"
108+
readonly dkms_framework_signing_variables="sign_file mok_signing_key mok_certificate
109+
try_sign_modules"
109110

110111
# The post transaction command we will accept from framework.conf
111112
readonly dkms_framework_post_transaction="post_transaction"
@@ -1174,6 +1175,37 @@ run_build_script() {
11741175
fi
11751176
}
11761177

1178+
# A relatively straightforward port of the Linux-kernel-specific part of
1179+
# Debian's "ischroot" command
1180+
# (https://salsa.debian.org/debian/debianutils/-/blob/9d4fc3502659adc02ed7b0457bf77e88be3a971a/ischroot.c)
1181+
# to Bash. Used for determining whether or not to sign kernel modules. Returns
1182+
# 0 when running in a chroot, 1 when likely running outside of a chroot.
1183+
running_in_chroot() {
1184+
# Check for fakechroot usage. Works without root.
1185+
# shellcheck disable=SC2076
1186+
[[ "${FAKECHROOT-}" == 'true' && -v FAKECHROOT_BASE && "${LD_PRELOAD-}" =~ 'libfakechroot.so' ]] && return 0
1187+
1188+
# Check if our view of /proc/PID/mountinfo differs from the init process's view. Works without root.
1189+
if [[ -r /proc/1/mountinfo && -r /proc/self/mountinfo ]]; then
1190+
local init_mountinfo
1191+
local our_mountinfo
1192+
IFS= read -rd '' init_mountinfo < '/proc/1/mountinfo'
1193+
IFS= read -rd '' our_mountinfo < '/proc/self/mountinfo'
1194+
[[ "${init_mountinfo}" != "${our_mountinfo}" ]] && return 0
1195+
fi
1196+
1197+
# Check if our root directory differs from the init process's root directory, using inode and device numbers. Requires root.
1198+
if [[ "$(id -u)" = 0 ]]; then
1199+
local init_rootdir_info
1200+
local our_rootdir_info
1201+
init_rootdir_info="$(stat -L --format='%d %i' /proc/1/root)"
1202+
our_rootdir_info="$(stat -L --format='%d %i' /)"
1203+
[[ "${init_rootdir_info}" != "${our_rootdir_info}" ]] && return 0
1204+
fi
1205+
1206+
return 1
1207+
}
1208+
11771209
# Register a DKMS-ified source tree with DKMS.
11781210
# This function is smart enough to register the module if we
11791211
# passed a source tree or a tarball instead of relying on the source tree
@@ -1343,6 +1375,17 @@ prepare_signing()
13431375

13441376
do_signing=0
13451377

1378+
if [[ "${try_sign_modules-}" = 'false' ]]; then
1379+
echo "Module signing is disabled by policy, modules won't be signed"
1380+
return
1381+
fi
1382+
1383+
# if try_sign_modules is not "true" here, always act as if it is set to "not_in_chroot"
1384+
if [[ "${try_sign_modules-}" != 'true' ]] && running_in_chroot; then
1385+
echo "Running in chroot, modules won't be signed"
1386+
return
1387+
fi
1388+
13461389
if [[ ! -f ${kernel_config} ]]; then
13471390
echo "Kernel config ${kernel_config} not found, modules won't be signed"
13481391
return

dkms_framework.conf.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
# represent the target kernel version. (default: depends on distribution):
3232
# sign_file="/path/to/sign-file"
3333

34+
# Whether to try to sign modules. May be set to "true", "false", or
35+
# "not_in_chroot". (default: not_in_chroot)
36+
# try_sign_modules=not_in_chroot
37+
3438
# Location of the key and certificate files used for Secure boot. $kernelver
3539
# can be used in path to represent the target kernel version.
3640
#

run_test.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,33 @@ file_not_exists() {
339339
fi
340340
}
341341

342+
# Check if the tests are running in a chroot. Copied from dkms main script.
343+
running_in_chroot() {
344+
# Check for fakechroot usage. Works without root.
345+
# shellcheck disable=SC2076
346+
[[ "${FAKECHROOT-}" == 'true' && -v FAKECHROOT_BASE && "${LD_PRELOAD-}" =~ 'libfakechroot.so' ]] && return 0
347+
348+
# Check if our view of /proc/PID/mountinfo differs from the init process's view. Works without root.
349+
if [[ -r /proc/1/mountinfo && -r /proc/self/mountinfo ]]; then
350+
local init_mountinfo
351+
local our_mountinfo
352+
IFS= read -rd '' init_mountinfo < '/proc/1/mountinfo'
353+
IFS= read -rd '' our_mountinfo < '/proc/self/mountinfo'
354+
[[ "${init_mountinfo}" != "${our_mountinfo}" ]] && return 0
355+
fi
356+
357+
# Check if our root directory differs from the init process's root directory, using inode and device numbers. Requires root.
358+
if [[ "$(id -u)" = 0 ]]; then
359+
local init_rootdir_info
360+
local our_rootdir_info
361+
init_rootdir_info="$(stat -L --format='%d %i' /proc/1/root)"
362+
our_rootdir_info="$(stat -L --format='%d %i' /)"
363+
[[ "${init_rootdir_info}" != "${our_rootdir_info}" ]] && return 0
364+
fi
365+
366+
return 1
367+
}
368+
342369
mod_compression_ext=
343370
kernel_config="/lib/modules/${KERNEL_VER}/build/.config"
344371
if [[ -f $kernel_config ]]; then
@@ -353,6 +380,12 @@ if [[ -f $kernel_config ]]; then
353380
fi
354381
fi
355382

383+
is_running_in_chroot=false
384+
if running_in_chroot; then
385+
is_running_in_chroot=true
386+
fi
387+
try_sign_modules_file='/etc/dkms/framework.conf.d/try_sign_modules.conf'
388+
356389
# Compute the expected destination module location
357390
os_id="$(sed -n 's/^ID\s*=\s*\(.*\)$/\1/p' /etc/os-release | tr -d '"')"
358391
distro_sign_file_candidates=
@@ -431,6 +464,11 @@ DKMS_VERSION="$(dkms --version)"
431464
echo 'Preparing a clean test environment'
432465
clean_dkms_env
433466

467+
if [[ $is_running_in_chroot = true ]] && (( NO_SIGNING_TOOL == 0 )); then
468+
echo 'Enabling module signing in chroot'
469+
install_framework_conf test/framework/try_sign_modules_true.conf "${try_sign_modules_file}"
470+
fi
471+
434472
echo 'Test that there are no dkms modules installed'
435473
run_with_expected_output dkms status -k "${KERNEL_VER}" << EOF
436474
EOF
@@ -967,6 +1005,55 @@ Before uninstall, this module version was ACTIVE on this kernel.
9671005
Deleting /lib/modules/${KERNEL_VER}/${expected_dest_loc}/dkms_test.ko${mod_compression_ext}
9681006
Running depmod... done.
9691007
1008+
Deleting module dkms_test/1.0 completely from the DKMS tree.
1009+
EOF
1010+
run_status_with_expected_output 'dkms_test' << EOF
1011+
EOF
1012+
1013+
echo 'Adding the test module'
1014+
run_with_expected_output dkms add test/dkms_test-1.0 << EOF
1015+
Creating symlink /var/lib/dkms/dkms_test/1.0/source -> /usr/src/dkms_test-1.0
1016+
EOF
1017+
check_module_source_tree_created /usr/src/dkms_test-1.0
1018+
run_status_with_expected_output 'dkms_test' << EOF
1019+
dkms_test/1.0: added
1020+
EOF
1021+
1022+
echo 'Building the test module with try_sign_modules=false'
1023+
install_framework_conf test/framework/try_sign_modules_false.conf "${try_sign_modules_file}"
1024+
run_with_expected_output dkms build -k "${KERNEL_VER}" -m dkms_test -v 1.0 --force << EOF
1025+
Module signing is disabled by policy, modules won't be signed
1026+
1027+
Building module(s)... done.
1028+
EOF
1029+
1030+
echo 'Building the test module with try_sign_modules=true'
1031+
install_framework_conf test/framework/try_sign_modules_true.conf "${try_sign_modules_file}"
1032+
run_with_expected_output dkms build -k "${KERNEL_VER}" -m dkms_test -v 1.0 --force << EOF
1033+
${SIGNING_PROLOGUE_tmp_key_cert}
1034+
Building module(s)... done.${SIGNING_MESSAGE}
1035+
EOF
1036+
1037+
if [[ $is_running_in_chroot = true ]]; then
1038+
echo 'Building the test module in a chroot with try_sign_modules=not_in_chroot'
1039+
install_framework_conf test/framework/try_sign_modules_not_in_chroot.conf "${try_sign_modules_file}"
1040+
run_with_expected_output dkms build -k "${KERNEL_VER}" -m dkms_test -v 1.0 --force << EOF
1041+
Running in chroot, modules won't be signed
1042+
1043+
Building module(s)... done.
1044+
EOF
1045+
1046+
echo 'Re-enabling module signing in chroot'
1047+
install_framework_conf test/framework/try_sign_modules_true.conf "${try_sign_modules_file}"
1048+
else
1049+
echo 'Removing try_sign_modules configuration'
1050+
rm "${try_sign_modules_file}"
1051+
fi
1052+
1053+
echo 'Removing the test module'
1054+
run_with_expected_output dkms remove -k "${KERNEL_VER}" -m dkms_test -v 1.0 << EOF
1055+
Module dkms_test/1.0 is not installed for kernel ${KERNEL_VER} (${KERNEL_ARCH}). Skipping...
1056+
9701057
Deleting module dkms_test/1.0 completely from the DKMS tree.
9711058
EOF
9721059
run_status_with_expected_output 'dkms_test' << EOF
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
try_sign_modules=false
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
try_sign_modules=not_in_chroot
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
try_sign_modules=true

0 commit comments

Comments
 (0)