Skip to content

Commit

Permalink
Validate spl_hostid, control loading spl.ko
Browse files Browse the repository at this point in the history
- Parse spl_hostid and spl.spl_hostid on the kernel command line.
  Validate that either the base 10 or base 16 value is valid,
  normalize to 8 hex digits

- Manually load spl.ko via insmod, setting the spl_hostid module
  parameter to 0. This way an invalid spl.spl_hostid on the kernel
  command line won't result in a (previously) unrecoverable module load
  error.

- Add in insmod/modinfo/lsmod/depmod as symlink aliases to the
  multi-call kmod binary.

Closes #184
  • Loading branch information
zdykstra committed Jun 26, 2021
1 parent 12f5ce2 commit 31cc1b3
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 17 deletions.
4 changes: 4 additions & 0 deletions 90zfsbootmenu/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ install() {
"chmod"
"od"
"stty"
"insmod"
"modinfo"
"lsmod"
"depmod"
)

for _exec in "${essential_execs[@]}"; do
Expand Down
35 changes: 28 additions & 7 deletions 90zfsbootmenu/zfsbootmenu-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ if ! is_lib_sourced > /dev/null 2>&1 ; then
exec /bin/bash
fi

# Make sure /dev/zfs exists, otherwise drop to a recovery shell
[ -e /dev/zfs ] || emergency_shell "/dev/zfs missing, check that kernel modules are loaded"

if [ -z "${BASE}" ]; then
export BASE="/zfsbootmenu"
fi
Expand All @@ -30,14 +27,38 @@ mkdir -p "${BASE}"

# Write out a default or overridden hostid
if [ -n "${spl_hostid}" ] ; then
zinfo "writing /etc/hostid from command line: ${spl_hostid}"
write_hostid "${spl_hostid}"
if write_hostid "${spl_hostid}" ; then
zinfo "writing /etc/hostid from command line: ${spl_hostid}"
else
# write_hostid logs an error for us, just note the new value
# shellcheck disable=SC2154
write_hostid "${default_hostid}"
zinfo "defaulting hostid to ${default_hostid}"
fi
elif [ ! -e /etc/hostid ]; then
zinfo "no hostid found on kernel command line or /etc/hostid"
zinfo "defaulting hostid to 00bab10c"
write_hostid 00bab10c
# shellcheck disable=SC2154
zinfo "defaulting hostid to ${default_hostid}"
write_hostid "${default_hostid}"
fi

# Capture the filename for spl.ko
_modfilename="$( modinfo -F filename spl )"
zinfo "loading ${_modfilename}"

# Load with a hostid of 0, so that /etc/hostid takes precedence
if ! _modload="$( insmod "${_modfilename}" "spl_hostid=0" 2>&1 )" ; then
zdebug "${_modload}"
emergency_shell "unable to load SPL kernel module"
fi

if ! _modload="$( modprobe zfs 2>&1 )" ; then
zdebug "${_modload}"
emergency_shell "unable to load ZFS kernel modules"
fi

udevadm settle

# Prefer a specific pool when checking for a bootfs value
# shellcheck disable=SC2154
if [ "${root}" = "zfsbootmenu" ]; then
Expand Down
37 changes: 30 additions & 7 deletions 90zfsbootmenu/zfsbootmenu-parse-commandline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,33 @@ fi

# Let the command line override our host id.
# shellcheck disable=SC2034
spl_hostid=$(getarg spl_hostid=)
cli_spl_hostid=$( getarg spl.spl_hostid ) || cli_spl_hostid=$( getarg spl_hostid )
if [ -n "${cli_spl_hostid}" ] ; then
# Start empty so only valid hostids are set for future use
spl_hostid=

# Test for decimal
if (( 10#${cli_spl_hostid} )) >/dev/null 2>&1 ; then
spl_hostid="$( printf "%08x" "${cli_spl_hostid}" )"
# Test for hex. Requires 0x, if present, to be stripped
# The change to cli_spl_hostid isn't saved outside of the test
elif (( 16#${cli_spl_hostid#0x} )) >/dev/null 2>&1 ; then
spl_hostid="${cli_spl_hostid#0x}"
# printf will strip leading 0s if there are more than 8 hex digits
# normalize to a maximum of 8, then run through printf to fill in
# if there are fewer than 8 digits.
spl_hostid="$( printf "%08x" "0x${spl_hostid:0:8}" )"
# base 10 / base 16 tests fail on 0
elif [ "${cli_spl_hostid#0x}" -eq "0" ] >/dev/null 2>&1 ; then
spl_hostid=0
# Not valid hex or dec, log
else
warn "ZFSBootMenu: invalid hostid value ${cli_spl_hostid}, ignoring"
fi
fi

# Use the last defined console= to control menu output
control_term=$( getarg console=)
control_term=$( getarg console )
if [ -n "${control_term}" ]; then
control_term="/dev/${control_term%,*}"
info "ZFSBootMenu: setting controlling terminal to: ${control_term}"
Expand All @@ -35,7 +58,7 @@ fi

# Use loglevel to determine logging to /dev/kmsg
min_logging=4
loglevel=$( getarg loglevel=)
loglevel=$( getarg loglevel )
if [ -n "${loglevel}" ]; then
# minimum log level of 4, so we never lose error or warning messages
[ "${loglevel}" -ge ${min_logging} ] || loglevel=${min_logging}
Expand Down Expand Up @@ -94,7 +117,7 @@ else
fi

zbm_import_delay=$( getarg zbm.import_delay )
if [ "${zbm_import_delay:-0}" -gt 0 ] 2>/dev/null ; then
if [ "${zbm_import_delay:-0}" -gt 0 ] 2>/dev/null ; then
# Again, this validates that zbm_import_delay is numeric in addition to logging
info "ZFSBootMenu: import retry delay is ${zbm_import_delay} seconds"
else
Expand All @@ -103,13 +126,13 @@ fi

# Allow setting of console size; there are no defaults here
# shellcheck disable=SC2034
zbm_lines=$( getarg zbm.lines=)
zbm_lines=$( getarg zbm.lines )
# shellcheck disable=SC2034
zbm_columns=$( getarg zbm.columns=)
zbm_columns=$( getarg zbm.columns )

# Allow sorting based on a key
zbm_sort=
sort_key=$( getarg zbm.sort_key=)
sort_key=$( getarg zbm.sort_key )
if [ -n "${sort_key}" ] ; then
valid_keys=( "name" "creation" "used" )
for key in "${valid_keys[@]}"; do
Expand Down
4 changes: 1 addition & 3 deletions 90zfsbootmenu/zfsbootmenu-preinit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export menu_timeout="${menu_timeout}"
export loglevel="${loglevel}"
export root="${root}"
export zbm_require_bpool="${zbm_require_bpool}"
export default_hostid=00bab10c
export zbm_sort="${zbm_sort}"
export zbm_set_hostid="${zbm_set_hostid}"
export zbm_import_delay="${zbm_import_delay}"
Expand All @@ -41,9 +42,6 @@ getcmdline > "${BASE}/zbm.cmdline"
# Set a non-empty hostname so we show up in zpool history correctly
echo "ZFSBootMenu" > /proc/sys/kernel/hostname

modprobe zfs 2>/dev/null
udevadm settle

# try to set console options for display and interaction
# this is sometimes run as an initqueue hook, but cannot be guaranteed
#shellcheck disable=SC2154
Expand Down

0 comments on commit 31cc1b3

Please sign in to comment.