#! /bin/sh # Oracle VM VirtualBox # Linux kernel module init script # # Copyright (C) 2006-2023 Oracle and/or its affiliates. # # This file is part of VirtualBox base platform packages, as # available from https://www.virtualbox.org. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, in version 3 of the # License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # SPDX-License-Identifier: GPL-3.0-only # # chkconfig: 345 20 80 # description: VirtualBox Linux kernel module # ### BEGIN INIT INFO # Provides: vboxdrv # Required-Start: $syslog # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: VirtualBox Linux kernel module ### END INIT INFO ## @todo This file duplicates a lot of script with vboxadd.sh. When making # changes please try to reduce differences between the two wherever possible. ## @todo Remove the stop_vms target so that this script is only relevant to # kernel modules. Nice but not urgent. PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH DEVICE=/dev/vboxdrv MODPROBE=/sbin/modprobe SCRIPTNAME=vboxdrv.sh # The below is GNU-specific. See VBox.sh for the longer Solaris/OS X version. TARGET=`readlink -e -- "${0}"` || exit 1 SCRIPT_DIR="${TARGET%/[!/]*}" if $MODPROBE -c | grep -q '^allow_unsupported_modules *0'; then MODPROBE="$MODPROBE --allow-unsupported-modules" fi setup_log() { test -n "${LOG}" && return 0 # Rotate log files LOG="/var/log/vbox-setup.log" mv "${LOG}.3" "${LOG}.4" 2>/dev/null mv "${LOG}.2" "${LOG}.3" 2>/dev/null mv "${LOG}.1" "${LOG}.2" 2>/dev/null mv "${LOG}" "${LOG}.1" 2>/dev/null } [ -f /etc/vbox/vbox.cfg ] && . /etc/vbox/vbox.cfg export VBOX_KBUILD_TYPE export USERNAME export USER=$USERNAME if test -n "${INSTALL_DIR}" && test -x "${INSTALL_DIR}/VirtualBox"; then MODULE_SRC="${INSTALL_DIR}/src/vboxhost" elif test -x /usr/lib/virtualbox/VirtualBox; then INSTALL_DIR=/usr/lib/virtualbox MODULE_SRC="/usr/share/virtualbox/src/vboxhost" elif test -x "${SCRIPT_DIR}/VirtualBox"; then # Executing from the build directory INSTALL_DIR="${SCRIPT_DIR}" MODULE_SRC="${INSTALL_DIR}/src" else # Silently exit if the package was uninstalled but not purged. # Applies to Debian packages only (but shouldn't hurt elsewhere) exit 0 fi VBOXMANAGE="${INSTALL_DIR}/VBoxManage" BUILDINTMP="${MODULE_SRC}/build_in_tmp" # If the VirtualBoxVM file has the set-uid bit set or if it doesn't exist, setup vboxdrv # in hardened mode. Otherwise, do the developer mode using vboxusers for access control. if test -u "${INSTALL_DIR}/VirtualBoxVM" || test '!' -e "${INSTALL_DIR}/VirtualBoxVM"; then GROUP=root DEVICE_MODE=0600 else GROUP=vboxusers DEVICE_MODE=0660 fi KERN_VER=`uname -r` # Prepend PATH for building UEK7 on OL8 distribution. case "$KERN_VER" in 5.15.0-*.el8uek*) PATH="/opt/rh/gcc-toolset-11/root/usr/bin:$PATH";; esac if test -e "${MODULE_SRC}/vboxpci"; then MODULE_LIST="vboxdrv vboxnetflt vboxnetadp vboxpci" else MODULE_LIST="vboxdrv vboxnetflt vboxnetadp" fi # Secure boot state. case "`mokutil --sb-state 2>/dev/null`" in *"disabled in shim"*) unset HAVE_SEC_BOOT;; *"SecureBoot enabled"*) HAVE_SEC_BOOT=true;; *) unset HAVE_SEC_BOOT;; esac # So far we can only sign modules on Ubuntu and on Debian 10 and later. DEB_PUB_KEY=/var/lib/shim-signed/mok/MOK.der DEB_PRIV_KEY=/var/lib/shim-signed/mok/MOK.priv unset HAVE_DEB_KEY case "`mokutil --test-key "$DEB_PUB_KEY" 2>/dev/null`" in *"is already"*) DEB_KEY_ENROLLED=true;; *) unset DEB_KEY_ENROLLED;; esac # Try to find a tool for modules signing. SIGN_TOOL=$(which kmodsign 2>/dev/null) # Attempt to use in-kernel signing tool if kmodsign not found. if test -z "$SIGN_TOOL"; then if test -x "/lib/modules/$KERN_VER/build/scripts/sign-file"; then SIGN_TOOL="/lib/modules/$KERN_VER/build/scripts/sign-file" fi fi # Check if update-secureboot-policy tool supports required commandline options. update_secureboot_policy_supports() { opt_name="$1" [ -n "$opt_name" ] || return [ -z "$(update-secureboot-policy --help 2>&1 | grep "$opt_name")" ] && return echo "1" } HAVE_UPDATE_SECUREBOOT_POLICY_TOOL= if type update-secureboot-policy >/dev/null 2>&1; then [ "$(update_secureboot_policy_supports new-key)" = "1" -a "$(update_secureboot_policy_supports enroll-key)" = "1" ] && \ HAVE_UPDATE_SECUREBOOT_POLICY_TOOL=true fi [ -r /etc/default/virtualbox ] && . /etc/default/virtualbox # Preamble for Gentoo if [ "`which $0`" = "/sbin/rc" ]; then shift fi begin_msg() { test -n "${2}" && echo "${SCRIPTNAME}: ${1}." logger -t "${SCRIPTNAME}" "${1}." } succ_msg() { logger -t "${SCRIPTNAME}" "${1}." } fail_msg() { echo "${SCRIPTNAME}: failed: ${1}." >&2 logger -t "${SCRIPTNAME}" "failed: ${1}." } failure() { fail_msg "$1" exit 1 } running() { lsmod | grep -q "$1[^_-]" } log() { setup_log echo "${1}" >> "${LOG}" } module_build_log() { setup_log echo "${1}" | egrep -v \ "^test -e include/generated/autoconf.h|^echo >&2|^/bin/false\)$" \ >> "${LOG}" } # Detect VirtualBox version info or report error. VBOX_VERSION="`"$VBOXMANAGE" -v | cut -d r -f1`" [ -n "$VBOX_VERSION" ] || failure 'Cannot detect VirtualBox version number' VBOX_REVISION="r`"$VBOXMANAGE" -v | cut -d r -f2`" [ "$VBOX_REVISION" != "r" ] || failure 'Cannot detect VirtualBox revision number' ## Output the vboxdrv part of our udev rule. This is redirected to the right file. udev_write_vboxdrv() { VBOXDRV_GRP="$1" VBOXDRV_MODE="$2" echo "KERNEL==\"vboxdrv\", OWNER=\"root\", GROUP=\"$VBOXDRV_GRP\", MODE=\"$VBOXDRV_MODE\"" echo "KERNEL==\"vboxdrvu\", OWNER=\"root\", GROUP=\"root\", MODE=\"0666\"" echo "KERNEL==\"vboxnetctl\", OWNER=\"root\", GROUP=\"$VBOXDRV_GRP\", MODE=\"$VBOXDRV_MODE\"" } ## Output the USB part of our udev rule. This is redirected to the right file. udev_write_usb() { INSTALLATION_DIR="$1" USB_GROUP="$2" echo "SUBSYSTEM==\"usb_device\", ACTION==\"add\", RUN+=\"$INSTALLATION_DIR/VBoxCreateUSBNode.sh \$major \$minor \$attr{bDeviceClass}${USB_GROUP}\"" echo "SUBSYSTEM==\"usb\", ACTION==\"add\", ENV{DEVTYPE}==\"usb_device\", RUN+=\"$INSTALLATION_DIR/VBoxCreateUSBNode.sh \$major \$minor \$attr{bDeviceClass}${USB_GROUP}\"" echo "SUBSYSTEM==\"usb_device\", ACTION==\"remove\", RUN+=\"$INSTALLATION_DIR/VBoxCreateUSBNode.sh --remove \$major \$minor\"" echo "SUBSYSTEM==\"usb\", ACTION==\"remove\", ENV{DEVTYPE}==\"usb_device\", RUN+=\"$INSTALLATION_DIR/VBoxCreateUSBNode.sh --remove \$major \$minor\"" } ## Generate our udev rule file. This takes a change in udev rule syntax in ## version 55 into account. It only creates rules for USB for udev versions ## recent enough to support USB device nodes. generate_udev_rule() { VBOXDRV_GRP="$1" # The group owning the vboxdrv device VBOXDRV_MODE="$2" # The access mode for the vboxdrv device INSTALLATION_DIR="$3" # The directory VirtualBox is installed in USB_GROUP="$4" # The group that has permission to access USB devices NO_INSTALL="$5" # Set this to "1" to remove but not re-install rules # Extra space! case "$USB_GROUP" in ?*) USB_GROUP=" $USB_GROUP" ;; esac case "$NO_INSTALL" in "1") return ;; esac udev_write_vboxdrv "$VBOXDRV_GRP" "$VBOXDRV_MODE" udev_write_usb "$INSTALLATION_DIR" "$USB_GROUP" } ## Install udev rule (disable with INSTALL_NO_UDEV=1 in ## /etc/default/virtualbox). install_udev() { VBOXDRV_GRP="$1" # The group owning the vboxdrv device VBOXDRV_MODE="$2" # The access mode for the vboxdrv device INSTALLATION_DIR="$3" # The directory VirtualBox is installed in USB_GROUP="$4" # The group that has permission to access USB devices NO_INSTALL="$5" # Set this to "1" to remove but not re-install rules if test -d /etc/udev/rules.d; then generate_udev_rule "$VBOXDRV_GRP" "$VBOXDRV_MODE" "$INSTALLATION_DIR" \ "$USB_GROUP" "$NO_INSTALL" fi # Remove old udev description file rm -f /etc/udev/rules.d/10-vboxdrv.rules 2> /dev/null } ## Create a usb device node for a given sysfs path to a USB device. install_create_usb_node_for_sysfs() { path="$1" # sysfs path for the device usb_createnode="$2" # Path to the USB device node creation script usb_group="$3" # The group to give ownership of the node to if test -r "${path}/dev"; then dev="`cat "${path}/dev" 2> /dev/null`" major="`expr "$dev" : '\(.*\):' 2> /dev/null`" minor="`expr "$dev" : '.*:\(.*\)' 2> /dev/null`" class="`cat ${path}/bDeviceClass 2> /dev/null`" sh "${usb_createnode}" "$major" "$minor" "$class" \ "${usb_group}" 2>/dev/null fi } udev_rule_file=/etc/udev/rules.d/60-vboxdrv.rules sysfs_usb_devices="/sys/bus/usb/devices/*" ## Install udev rules and create device nodes for usb access setup_usb() { VBOXDRV_GRP="$1" # The group that should own /dev/vboxdrv VBOXDRV_MODE="$2" # The mode to be used for /dev/vboxdrv INSTALLATION_DIR="$3" # The directory VirtualBox is installed in USB_GROUP="$4" # The group that should own the /dev/vboxusb device # nodes unless INSTALL_NO_GROUP=1 in # /etc/default/virtualbox. Optional. usb_createnode="$INSTALLATION_DIR/VBoxCreateUSBNode.sh" # install udev rule (disable with INSTALL_NO_UDEV=1 in # /etc/default/virtualbox) if [ "$INSTALL_NO_GROUP" != "1" ]; then usb_group=$USB_GROUP vboxdrv_group=$VBOXDRV_GRP else usb_group=root vboxdrv_group=root fi install_udev "${vboxdrv_group}" "$VBOXDRV_MODE" \ "$INSTALLATION_DIR" "${usb_group}" \ "$INSTALL_NO_UDEV" > ${udev_rule_file} # Build our device tree for i in ${sysfs_usb_devices}; do # This line intentionally without quotes. install_create_usb_node_for_sysfs "$i" "${usb_createnode}" \ "${usb_group}" done } cleanup_usb() { # Remove udev description file rm -f /etc/udev/rules.d/60-vboxdrv.rules rm -f /etc/udev/rules.d/10-vboxdrv.rules # Remove our USB device tree rm -rf /dev/vboxusb } # Returns path to module file as seen by modinfo(8) or empty string. module_path() { mod="$1" [ -n "$mod" ] || return modinfo "$mod" 2>/dev/null | grep -e "^filename:" | tr -s ' ' | cut -d " " -f2 } # Returns module version if module is available or empty string. module_version() { mod="$1" [ -n "$mod" ] || return modinfo "$mod" 2>/dev/null | grep -e "^version:" | tr -s ' ' | cut -d " " -f2 } # Returns module revision if module is available in the system or empty string. module_revision() { mod="$1" [ -n "$mod" ] || return modinfo "$mod" 2>/dev/null | grep -e "^version:" | tr -s ' ' | cut -d " " -f3 } # Reads kernel configuration option. kernel_get_config_opt() { opt_name="$1" [ -n "$opt_name" ] || return # Check if there is a kernel tool which can extract config option. if test -x /lib/modules/"$KERN_VER"/build/scripts/config; then /lib/modules/"$KERN_VER"/build/scripts/config \ --file /lib/modules/"$KERN_VER"/build/.config \ --state "$opt_name" 2>/dev/null elif test -f /lib/modules/"$KERN_VER"/build/.config; then # Extract config option manually. grep "$opt_name=" /lib/modules/"$KERN_VER"/build/.config | sed -e "s/^$opt_name=//" -e "s/\"//g" fi } # Reads CONFIG_MODULE_SIG_HASH from kernel config. kernel_module_sig_hash() { kernel_get_config_opt "CONFIG_MODULE_SIG_HASH" } # Returns "1" if kernel module signature hash algorithm # is supported by us. Or empty string otherwise. module_sig_hash_supported() { sig_hashalgo="$1" [ -n "$sig_hashalgo" ] || return # Go through supported list. [ "$sig_hashalgo" = "sha1" \ -o "$sig_hashalgo" = "sha224" \ -o "$sig_hashalgo" = "sha256" \ -o "$sig_hashalgo" = "sha384" \ -o "$sig_hashalgo" = "sha512" ] || return echo "1" } # Check if kernel configuration requires modules signature. kernel_requires_module_signature() { vbox_sys_lockdown_path="/sys/kernel/security/lockdown" requires="" # We consider that if kernel is running in the following configurations, # it will require modules to be signed. if [ "$(kernel_get_config_opt "CONFIG_MODULE_SIG")" = "y" ]; then # Modules signature verification is hardcoded in kernel config. [ "$(kernel_get_config_opt "CONFIG_MODULE_SIG_FORCE")" = "y" ] && requires="1" # Unsigned modules loading is restricted by "lockdown" feature in runtime. if [ "$(kernel_get_config_opt "CONFIG_LOCK_DOWN_KERNEL")" = "y" \ -o "$(kernel_get_config_opt "CONFIG_SECURITY_LOCKDOWN_LSM")" = "y" \ -o "$(kernel_get_config_opt "CONFIG_SECURITY_LOCKDOWN_LSM_EARLY")" = "y" ]; then # Once lockdown level is set to something different than "none" (e.g., "integrity" # or "confidentiality"), kernel will reject unsigned modules loading. if [ -r "$vbox_sys_lockdown_path" ]; then [ -n "$(cat "$vbox_sys_lockdown_path" | grep "\[integrity\]")" ] && requires="1" [ -n "$(cat "$vbox_sys_lockdown_path" | grep "\[confidentiality\]")" ] && requires="1" fi # This configuration is used by a number of modern Linux distributions and restricts # unsigned modules loading when Secure Boot mode is enabled. [ "$(kernel_get_config_opt "CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT")" = "y" -a -n "$HAVE_SEC_BOOT" ] && requires="1" fi fi [ -n "$requires" ] && echo "1" } # Returns "1" if module is signed and signature can be verified # with public key provided in DEB_PUB_KEY. Or empty string otherwise. module_signed() { mod="$1" [ -n "$mod" ] || return # Be nice with distributions which do not provide tools which we # use in order to verify module signature. This variable needs to # be explicitly set by administrator. This script will look for it # in /etc/vbox/vbox.cfg. Make sure that you know what you do! if [ "$VBOX_BYPASS_MODULES_SIGNATURE_CHECK" = "1" ]; then echo "1" return fi extraction_tool=/lib/modules/"$(uname -r)"/build/scripts/extract-module-sig.pl mod_path=$(module_path "$mod" 2>/dev/null) openssl_tool=$(which openssl 2>/dev/null) # Do not use built-in printf! printf_tool=$(which printf 2>/dev/null) # Make sure all the tools required for signature validation are available. [ -x "$extraction_tool" ] || return [ -n "$mod_path" ] || return [ -n "$openssl_tool" ] || return [ -n "$printf_tool" ] || return # Make sure openssl can handle hash algorithm. sig_hashalgo=$(modinfo -F sig_hashalgo "$mod" 2>/dev/null) [ "$(module_sig_hash_supported $sig_hashalgo)" = "1" ] || return # Generate file names for temporary stuff. mod_pub_key=$(mktemp -u) mod_signature=$(mktemp -u) mod_unsigned=$(mktemp -u) # Convert public key in DER format into X509 certificate form. "$openssl_tool" x509 -pubkey -inform DER -in "$DEB_PUB_KEY" -out "$mod_pub_key" 2>/dev/null # Extract raw module signature and convert it into binary format. "$printf_tool" \\x$(modinfo -F signature "$mod" | sed -z 's/[ \t\n]//g' | sed -e "s/:/\\\x/g") 2>/dev/null > "$mod_signature" # Extract unsigned module for further digest calculation. "$extraction_tool" -0 "$mod_path" 2>/dev/null > "$mod_unsigned" # Verify signature. rc="" "$openssl_tool" dgst "-$sig_hashalgo" -binary -verify "$mod_pub_key" -signature "$mod_signature" "$mod_unsigned" 2>&1 >/dev/null && rc="1" # Clean up. rm -f $mod_pub_key $mod_signature $mod_unsigned # Check result. [ "$rc" = "1" ] || return echo "1" } # Returns "1" if externally built module is available in the system and its # version and revision number do match to current VirtualBox installation. # Or empty string otherwise. module_available() { mod="$1" [ -n "$mod" ] || return [ "$VBOX_VERSION" = "$(module_version "$mod")" ] || return [ "$VBOX_REVISION" = "$(module_revision "$mod")" ] || return # Check if module belongs to VirtualBox installation. # # We have a convention that only modules from /lib/modules/*/misc # belong to us. Modules from other locations are treated as # externally built. mod_path="$(module_path "$mod")" # If module path points to a symbolic link, resolve actual file location. [ -L "$mod_path" ] && mod_path="$(readlink -e -- "$mod_path")" # File exists? [ -f "$mod_path" ] || return # Extract last component of module path and check whether it is located # outside of /lib/modules/*/misc. mod_dir="$(dirname "$mod_path" | sed 's;^.*/;;')" [ "$mod_dir" = "misc" ] || return # In case if kernel configuration requires module signature, check if module is signed. if test "$(kernel_requires_module_signature)" = "1"; then [ "$(module_signed "$mod")" = "1" ] || return fi echo "1" } # Check if required modules are installed in the system and versions match. setup_complete() { [ "$(module_available vboxdrv)" = "1" ] || return [ "$(module_available vboxnetflt)" = "1" ] || return [ "$(module_available vboxnetadp)" = "1" ] || return # All modules are in place. echo "1" } start() { begin_msg "Starting VirtualBox services" console if [ -d /proc/xen ]; then failure "Running VirtualBox in a Xen environment is not supported" fi if test "$(kernel_requires_module_signature)" = "1" && test -z "$DEB_KEY_ENROLLED"; then if test -n "$HAVE_DEB_KEY"; then begin_msg "You must re-start your system to finish Debian secure boot set-up." console else begin_msg "You must sign these kernel modules before using VirtualBox: $MODULE_LIST See the documentation for your Linux distribution." console fi fi if ! running vboxdrv; then # Check if system already has matching modules installed. [ "$(setup_complete)" = "1" ] || setup if ! rm -f $DEVICE; then failure "Cannot remove $DEVICE" fi if ! $MODPROBE vboxdrv > /dev/null 2>&1; then failure "modprobe vboxdrv failed. Please use 'dmesg' to find out why" fi sleep .2 fi # ensure the character special exists if [ ! -c $DEVICE ]; then MAJOR=`sed -n 's;\([0-9]\+\) vboxdrv$;\1;p' /proc/devices` if [ ! -z "$MAJOR" ]; then MINOR=0 else MINOR=`sed -n 's;\([0-9]\+\) vboxdrv$;\1;p' /proc/misc` if [ ! -z "$MINOR" ]; then MAJOR=10 fi fi if [ -z "$MAJOR" ]; then rmmod vboxdrv 2>/dev/null failure "Cannot locate the VirtualBox device" fi if ! mknod -m 0660 $DEVICE c $MAJOR $MINOR 2>/dev/null; then rmmod vboxdrv 2>/dev/null failure "Cannot create device $DEVICE with major $MAJOR and minor $MINOR" fi fi # ensure permissions if ! chown :"${GROUP}" $DEVICE 2>/dev/null; then rmmod vboxpci 2>/dev/null rmmod vboxnetadp 2>/dev/null rmmod vboxnetflt 2>/dev/null rmmod vboxdrv 2>/dev/null failure "Cannot change group ${GROUP} for device $DEVICE" fi if ! $MODPROBE vboxnetflt > /dev/null 2>&1; then failure "modprobe vboxnetflt failed. Please use 'dmesg' to find out why" fi if ! $MODPROBE vboxnetadp > /dev/null 2>&1; then failure "modprobe vboxnetadp failed. Please use 'dmesg' to find out why" fi if test -e "${MODULE_SRC}/vboxpci" && ! $MODPROBE vboxpci > /dev/null 2>&1; then failure "modprobe vboxpci failed. Please use 'dmesg' to find out why" fi # Create the /dev/vboxusb directory if the host supports that method # of USB access. The USB code checks for the existence of that path. if grep -q usb_device /proc/devices; then mkdir -p -m 0750 /dev/vboxusb 2>/dev/null chown root:vboxusers /dev/vboxusb 2>/dev/null fi # Remove any kernel modules left over from previously installed kernels. cleanup only_old succ_msg "VirtualBox services started" } stop() { begin_msg "Stopping VirtualBox services" console if running vboxpci; then if ! rmmod vboxpci 2>/dev/null; then failure "Cannot unload module vboxpci" fi fi if running vboxnetadp; then if ! rmmod vboxnetadp 2>/dev/null; then failure "Cannot unload module vboxnetadp" fi fi if running vboxdrv; then if running vboxnetflt; then if ! rmmod vboxnetflt 2>/dev/null; then failure "Cannot unload module vboxnetflt" fi fi if ! rmmod vboxdrv 2>/dev/null; then failure "Cannot unload module vboxdrv" fi if ! rm -f $DEVICE; then failure "Cannot unlink $DEVICE" fi fi succ_msg "VirtualBox services stopped" } # enter the following variables in /etc/default/virtualbox: # SHUTDOWN_USERS="foo bar" # check for running VMs of user foo and user bar # SHUTDOWN=poweroff # SHUTDOWN=acpibutton # SHUTDOWN=savestate # select one of these shutdown methods for running VMs stop_vms() { wait=0 for i in $SHUTDOWN_USERS; do # don't create the ipcd directory with wrong permissions! if [ -d /tmp/.vbox-$i-ipc ]; then export VBOX_IPC_SOCKETID="$i" VMS=`$VBOXMANAGE --nologo list runningvms | sed -e 's/^".*".*{\(.*\)}/\1/' 2>/dev/null` if [ -n "$VMS" ]; then if [ "$SHUTDOWN" = "poweroff" ]; then begin_msg "Powering off remaining VMs" for v in $VMS; do $VBOXMANAGE --nologo controlvm $v poweroff done succ_msg "Remaining VMs powered off" elif [ "$SHUTDOWN" = "acpibutton" ]; then begin_msg "Sending ACPI power button event to remaining VMs" for v in $VMS; do $VBOXMANAGE --nologo controlvm $v acpipowerbutton wait=30 done succ_msg "ACPI power button event sent to remaining VMs" elif [ "$SHUTDOWN" = "savestate" ]; then begin_msg "Saving state of remaining VMs" for v in $VMS; do $VBOXMANAGE --nologo controlvm $v savestate done succ_msg "State of remaining VMs saved" fi fi fi done # wait for some seconds when doing ACPI shutdown if [ "$wait" -ne 0 ]; then begin_msg "Waiting for $wait seconds for VM shutdown" sleep $wait succ_msg "Waited for $wait seconds for VM shutdown" fi } cleanup() { # If this is set, only remove kernel modules for no longer installed # kernels. Note that only generated kernel modules should be placed # in /lib/modules/*/misc. Anything that we should not remove automatically # should go elsewhere. only_old="${1}" for i in /lib/modules/*; do # Check whether we are only cleaning up for uninstalled kernels. test -n "${only_old}" && test -e "${i}/kernel/drivers" && continue unset do_update for j in $MODULE_LIST; do for mod_ext in ko ko.gz ko.xz ko.zst; do test -f "${i}/misc/${j}.${mod_ext}" && do_update=1 && rm -f "${i}/misc/${j}.${mod_ext}" done done # Trigger depmod(8) only in case if directory content was modified # and save a bit of run time. test -n "$do_update" && depmod -a "$(basename "$i")" && sync # Remove the kernel version folder if it was empty except for us. test "`echo ${i}/misc/* ${i}/misc/.?* ${i}/* ${i}/.?*`" \ = "${i}/misc/* ${i}/misc/.. ${i}/misc ${i}/.." && rmdir "${i}/misc" "${i}" # We used to leave empty folders. done } # setup_script setup() { begin_msg "Building VirtualBox kernel modules" console log "Building the main VirtualBox module." # Detect if kernel was built with clang. unset LLVM vbox_cc_is_clang=$(kernel_get_config_opt "CONFIG_CC_IS_CLANG") if test "${vbox_cc_is_clang}" = "y"; then log "Using clang compiler." export LLVM=1 fi if ! myerr=`$BUILDINTMP \ --save-module-symvers /tmp/vboxdrv-Module.symvers \ --module-source "$MODULE_SRC/vboxdrv" \ --no-print-directory install 2>&1`; then "${INSTALL_DIR}/check_module_dependencies.sh" || exit 1 log "Error building the module:" module_build_log "$myerr" failure "Look at $LOG to find out what went wrong" fi log "Building the net filter module." if ! myerr=`$BUILDINTMP \ --use-module-symvers /tmp/vboxdrv-Module.symvers \ --module-source "$MODULE_SRC/vboxnetflt" \ --no-print-directory install 2>&1`; then log "Error building the module:" module_build_log "$myerr" failure "Look at $LOG to find out what went wrong" fi log "Building the net adapter module." if ! myerr=`$BUILDINTMP \ --use-module-symvers /tmp/vboxdrv-Module.symvers \ --module-source "$MODULE_SRC/vboxnetadp" \ --no-print-directory install 2>&1`; then log "Error building the module:" module_build_log "$myerr" failure "Look at $LOG to find out what went wrong" fi if test -e "$MODULE_SRC/vboxpci"; then log "Building the PCI pass-through module." if ! myerr=`$BUILDINTMP \ --use-module-symvers /tmp/vboxdrv-Module.symvers \ --module-source "$MODULE_SRC/vboxpci" \ --no-print-directory install 2>&1`; then log "Error building the module:" module_build_log "$myerr" failure "Look at $LOG to find out what went wrong" fi fi rm -f /etc/vbox/module_not_compiled depmod -a sync succ_msg "VirtualBox kernel modules built" # Sign kernel modules if kernel configuration requires it. if test "$(kernel_requires_module_signature)" = "1"; then begin_msg "Signing VirtualBox kernel modules" console # Generate new signing key if needed. [ -n "$HAVE_UPDATE_SECUREBOOT_POLICY_TOOL" ] && SHIM_NOTRIGGER=y update-secureboot-policy --new-key # Check if signing keys are in place. if test ! -f "$DEB_PUB_KEY" || ! test -f "$DEB_PRIV_KEY"; then # update-secureboot-policy tool present in the system, but keys were not generated. [ -n "$HAVE_UPDATE_SECUREBOOT_POLICY_TOOL" ] && fail_msg " update-secureboot-policy tool does not generate signing keys in your distribution, see below on how to generate them manually " # update-secureboot-policy not present in the system, recommend generate keys manually. failure " System is running in Secure Boot mode, however your distribution does not provide tools for automatic generation of keys needed for modules signing. Please consider to generate and enroll them manually: sudo mkdir -p /var/lib/shim-signed/mok sudo openssl req -nodes -new -x509 -newkey rsa:2048 -outform DER -addext \"extendedKeyUsage=codeSigning\" -keyout $DEB_PRIV_KEY -out $DEB_PUB_KEY sudo mokutil --import $DEB_PUB_KEY sudo reboot Restart \"rcvboxdrv setup\" after system is rebooted " fi # Check if signing tool is available. [ -n "$SIGN_TOOL" ] || failure "Unable to find signing tool" # Get kernel signature hash algorithm from kernel config and validate it. sig_hashalgo=$(kernel_module_sig_hash) [ "$(module_sig_hash_supported $sig_hashalgo)" = "1" ] \ || failure "Unsupported kernel signature hash algorithm $sig_hashalgo" # Sign modules. for i in $MODULE_LIST; do "$SIGN_TOOL" "$sig_hashalgo" "$DEB_PRIV_KEY" "$DEB_PUB_KEY" \ /lib/modules/"$KERN_VER"/misc/"$i".ko 2>/dev/null || failure "Unable to sign $i.ko" done # Enroll signing key if needed. if test -n "$HAVE_UPDATE_SECUREBOOT_POLICY_TOOL"; then # update-secureboot-policy "expects" DKMS modules. # Work around this and talk to the authors as soon # as possible to fix it. mkdir -p /var/lib/dkms/vbox-temp update-secureboot-policy --enroll-key 2>/dev/null || begin_msg "Failed to enroll secure boot key." console rmdir -p /var/lib/dkms/vbox-temp 2>/dev/null # Indicate that key has been enrolled and reboot is needed. HAVE_DEB_KEY=true fi succ_msg "Signing completed" fi } dmnstatus() { if running vboxdrv; then str="vboxdrv" if running vboxnetflt; then str="$str, vboxnetflt" if running vboxnetadp; then str="$str, vboxnetadp" fi fi if running vboxpci; then str="$str, vboxpci" fi echo "VirtualBox kernel modules ($str) are loaded." for i in $SHUTDOWN_USERS; do # don't create the ipcd directory with wrong permissions! if [ -d /tmp/.vbox-$i-ipc ]; then export VBOX_IPC_SOCKETID="$i" VMS=`$VBOXMANAGE --nologo list runningvms | sed -e 's/^".*".*{\(.*\)}/\1/' 2>/dev/null` if [ -n "$VMS" ]; then echo "The following VMs are currently running:" for v in $VMS; do echo " $v" done fi fi done else echo "VirtualBox kernel module is not loaded." fi } case "$1" in start) start ;; stop) stop_vms stop ;; stop_vms) stop_vms ;; restart) stop && start ;; setup) test -n "${2}" && export KERN_VER="${2}" # Create udev rule and USB device nodes. ## todo Wouldn't it make more sense to install the rule to /lib/udev? This ## is not a user-created configuration file after all. ## todo Do we need a udev rule to create /dev/vboxdrv[u] at all? We have ## working fall-back code here anyway, and the "right" code is more complex ## than the fall-back. Unnecessary duplication? stop && cleanup setup_usb "$GROUP" "$DEVICE_MODE" "$INSTALL_DIR" start ;; cleanup) stop && cleanup cleanup_usb ;; force-reload) stop start ;; status) dmnstatus ;; *) echo "Usage: $0 {start|stop|stop_vms|restart|setup|cleanup|force-reload|status}" exit 1 esac exit 0