Difference between revisions of "Signed kernel module support"

From Funtoo
Jump to navigation Jump to search
(adding general warning about the production readiness of Funtoo kernel module signing)
 
(21 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Since the Linux kernel version 3.7.x, support for the signed kernel modules has been useful. When enabled, the Linux kernel kernel will be fixed. This allows the system to be "hardened", not using the unsigned kernel, or kernel modules to be loaded with a wrong key, to be loaded. Malicious kernel modules are a common system for rootkits to enter a Linux system.
{{warning|Signed Linux Kernel Modules is currently an experimental feature for Funtoo Linux as part of [[Funtoo:Security|the active Security Project]], which hardens and locks down kernel module loading. It is not a production ready feature yet.
 
All of the required automated tooling is still in development to help support seamless signing of genkernel initramfs modules and signing of any out-of-tree kernel modules available in Funtoo Linux as a package. Proceed with cautious and open mindset, plus the understanding that running full boot time kernel level enforcement of signed modules will require additional manual upkeep until the proper tooling is developed and publicly available}}
 
Since the Linux kernel version 3.7.x, support for the signed kernel modules has been useful. When enabled, the Linux kernel will be fixed. This allows the system to be "hardened", not using the unsigned kernel, or kernel modules to be loaded with a wrong key, to be loaded. Malicious kernel modules are a common system for rootkits to enter a Linux system.


When the Linux kernel is building with module signature verification support enabled, then you can use your own keys. We recommend the debian-sources kernel, just enabling the useflag "sign-modules".
When the Linux kernel is building with module signature verification support enabled, then you can use your own keys. We recommend the debian-sources kernel, just enabling the useflag "sign-modules".
Line 5: Line 9:
{{console|body=
{{console|body=
###i## echo "sys-kernel/debian-sources sign-modules" >> /etc/portage/package.use
###i## echo "sys-kernel/debian-sources sign-modules" >> /etc/portage/package.use
}}
We will manually generate the private/public key files using the x509.genkey key generation configuration file and the openssl command. Here is an example to generate the public/private key files:
{{console|body=
###i## mkdir -p /etc/kernel/certs/linux
###i## mkdir -p /etc/kernel/certs/linux
###i## openssl req -new -nodes -sha256 -x509 -newkey rsa:2048 -days 36500 -addext extendedKeyUsage=1.3.6.1.5.5.7.3.3 -subj '/CN=Funtoo Secure Boot/' -out /etc/kernel/certs/linux/signing_key.cert -keyout /etc/kernel/certs/linux/signing_key.asc
###i## cat /etc/kernel/certs/linux/signing_key.asc /etc/kernel/certs/linux/signing_key.cert > /etc/kernel/certs/linux/signing_key.pem
###i## openssl x509 -outform der -in /etc/kernel/certs/linux/signing_key.pem -out /etc/kernel/certs/linux/signing_key.x509
}}
Create DER file to sign grub and SHIM (secure boot):
{{console|body=
###i## openssl x509 -in /etc/kernel/certs/linux/signing_key.cert -outform der -out /etc/kernel/certs/linux/signing_key.der
}}
Fix permissions:
{{console|body=
###i## chmod -R 644 /etc/kernel/certs/linux/signing_key.pem
}}
Now, build debian-sources with your own keys:
{{console|body=
###i## emerge sys-kernel/debian-sources
}}
== Manually signing modules ==
If you ever need to manually sign a kernel module, you can use the scripts/sign-file script available in the Linux kernel source tree. It requires four arguments:
# The hash algorithm to use, such as sha512.
# The private key location.
# The certificate (which includes the public key) location.
# The kernel module to sign.
{{console|body=
###i## /usr/src/linux/scripts/sign-file sha512 /etc/kernel/certs/linux/signing_key.pem /etc/kernel/certs/linux/signing_key.x509 ${MODULE_KO}
}}
}}


=== Advanced Module Signing and Verification Scripts ===


If we want to use our own keys, you can use openssl to create a key pair (private key and public key). First, create a new file '''x509.genkey''' on directory '''/etc/kernel/certs/linux''' :
{{warning|Only run these scripts once booted into a debian-sources kernel that was emerged with the '''sign-modules''' USE flag}}
{{file|name=/etc/kernel/certs/linux/x509.genkey|body=
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts


[ req_distinguished_name ]
==== Module Signing ====
#O = Funtoo Corporation Inc
CN = Funtoo Linux
#emailAddress = drobbins@funtoo.org


[ myexts ]
Here is an experimental but well tested script that locally automates the signing of arbitrary kernel modules (both in-tree and out-of-tree) with your kernel module signing certificate and key:
basicConstraints=critical,CA:FALSE
 
keyUsage=digitalSignature
{{file|name=sign_out_of_tree_modules.sh|lang=Shell|desc=Kernel module signing script|body=
subjectKeyIdentifier=hash
#!/bin/bash
authorityKeyIdentifier=keyid
 
SIGNING_HASH_ALGO="sha512"
SIGNING_PRIVATE_KEY="/etc/kernel/certs/linux/signing_key.pem"
SIGNING_PUBLIC_KEY="/etc/kernel/certs/linux/signing_key.x509"
SIGNING_SCRIPT_DIR="/usr/src/linux"
SIGNING_SCRIPT="./scripts/sign-file"
 
KERNEL_VERSION="6.1.4_p1-debian-sources"
KERNEL_MODULES=(
  "/lib/modules/${KERNEL_VERSION}/misc/vboxdrv.ko"
  "/lib/modules/${KERNEL_VERSION}/misc/vboxnetadp.ko"
  "/lib/modules/${KERNEL_VERSION}/misc/vboxnetflt.ko"
  "/lib64/modules/${KERNEL_VERSION}/misc/vboxdrv.ko"
  "/lib64/modules/${KERNEL_VERSION}/misc/vboxnetadp.ko"
  "/lib64/modules/${KERNEL_VERSION}/misc/vboxnetflt.ko"
  "/lib/modules/${KERNEL_VERSION}/extra/v4l2loopback.ko"
)
 
for mod in "${KERNEL_MODULES[@]}"; do
  echo "signing tainted kernel module $mod"
  (
    cd $SIGNING_SCRIPT_DIR
    $SIGNING_SCRIPT $SIGNING_HASH_ALGO $SIGNING_PRIVATE_KEY $SIGNING_PUBLIC_KEY $mod
  )
done
}}
}}


Adjust the values of these Bash variables for to match your locally configured Funtoo system: '''SIGNING_HASH_ALGO, KERNEL_VERSION, KERNEL_MODULES'''
==== Module Verification ====
This is an experimental but well tested script that verifies the signatures of all signed kernel modules are correct.


We will manually generate the private/public key files using the x509.genkey key generation configuration file and the openssl command. Here is an example to generate the public/private key files:
It verifies the signature of each kernel module to ensure it matches what is configured in your kernel.
{{console|body=
 
###i## openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config /etc/kernel/certs/linux/x509.genkey -outform PEM -out /etc/kernel/certs/linux/signing_key.pem -keyout /etc/kernel/certs/linux/signing_key.pem
{{file|name=verify_signed_modules.sh|lang=Shell|desc=Kernel module signature verification script|body=
###i## openssl x509 -outform der -in /etc/kernel/certs/linux/signing_key.pem -out /etc/kernel/certs/linux/signing_key.x509
#!/bin/bash
 
# Colors
RED=$'\033[31;01m'
GREEN=$'\033[32;01m'
OFF=$'\033[0m'
 
SIGNING_HASH_ALGO="sha512"
SIGNING_SIGNER="Funtoo Secure Boot"
KERNEL_VERSION="6.1.4_p1-debian-sources"
MODULE_LIB_DIR="/lib/modules/${KERNEL_VERSION}/"
MODULE_LIB64_DIR="/lib64/modules/${KERNEL_VERSION}/"
 
for dir in $MODULE_LIB_DIR $MODULE_LIB64_DIR; do
for mod in $(find $dir -name *.ko {{!}} xargs); do
        if (modinfo $mod {{!}} egrep "${SIGNING_SIGNER}{{!}}${SIGNING_HASH_ALGO}" &> /dev/null); then
                echo "${GREEN}PASS${OFF}: kernel module $mod signed. signer:$SIGNING_SIGNER sig_hashalgo:$SIGNING_HASH_ALGO"
        else
                echo "${RED}FAIL${OFF}: kernel module $mod is NOT properly signed"
        fi
done
done
}}
}}


Adjust the values of these Bash variables to match your locally configured Funtoo system: '''SIGNING_HASH_ALGO, SIGNING_SIGNER, KERNEL_VERSION'''
To filter successfully signed kernel modules out and only show failed signatures, execute the above script locally on your Funtoo system with the below syntax:


Fix permissions:
{{console|body=
{{console|body=
###i## chmod -R 755 /etc/kernel
###i## ./verify_signed_modules.sh  | grep -v PASS
}}
}}


If you want to do an ad-hoc verification of a single kernel module's signature you can simply use the '''modinfo''' tool:


Now, build debian-sources with your own keys:
{{console|body=
{{console|body=
###i## emerge sys-kernel/debian-sources
###i## modinfo MODNAME {{!}} grep sig
}}
}}


Where {{c|MODNAME}} is the name of the kernel module


'''Optional:''' Enable ''' module.sig_enforce=1'''
== Non-valid signatures and unsigned modules==
{{note|If module.sig_enforce is enabled supplied on the kernel command line, the kernel will only load validly signed modules for which it has a public key. Otherwise, it will also load modules that are unsigned. Any module for which the kernel has a key, but which proves to have a signature mismatch will not be permitted to load.}}
{{note|If module.sig_enforce is disabled (default) it will also load modules that are unsigned.}}


If module.sig_enforce=1 is enabled is supplied on the kernel command line, the kernel will only load validly signed modules for which it has a public key. Otherwise, it will also load modules that are unsigned. Any module for which the kernel has a key, but which proves to have a signature mismatch will not be permitted to load.
Any module that has an unparseable signature will be rejected.
When you have confirmed that the modules are being signed and that the kernel works as it should, you can enable the following kernel parameter on your '''/etc/boot.conf''' to require that the kernel only permits verified modules to be loaded:
If you need recreate initramfs (optional):
{{console|body=
###i## genkernel --clean --luks --lvm --disklabel --ramdisk-modules --fullname=debian-sources-x86_64-6.1.4_p1 initramfs
}}
You need sign all modules into initramfs first:
{{console|body=
###i## mount /boot
###i## mkdir /tmp/initram; cd /tmp/initram
###i## cp /boot/initramfs-debian-sources-x86_64-6.1.4_p1 .
###i## cat initramfs-debian-sources-x86_64-6.1.4_p1 {{!}} xz -d {{!}} cpio -id
###i## find /tmp/initram/lib/modules/ -name "*ko" -exec /usr/src/linux/scripts/sign-file sha256 /etc/kernel/certs/linux/signing_key.pem /etc/kernel/certs/linux/signing_key.x509 '{}' \;
###i## mv /boot/initramfs-debian-sources-x86_64-6.1.4_p1 /boot/initramfs-debian-sources-x86_64-6.1.4_p1.old
###i## find . {{!}} cpio -H newc -o {{!}} xz --check=crc32 --x86 --lzma2 >/boot/initramfs-debian-sources-x86_64-6.1.4_p1
}}


Include this parameter on your kernel line into '''/etc/boot.conf''':


== Manually signing modules ==
{{console|body=
If you ever need to manually sign a kernel module, you can use the scripts/sign-file script available in the Linux kernel source tree. It requires four arguments:
module.sig_enforce=1
}}


# The hash algorithm to use, such as sha512.
Example /etc/boot.conf enabling kernel module signature verification:
# The private key location.
# The certificate (which includes the public key) location.
# The kernel module to sign.


{{file|name=/etc/boot.conf|desc=module.sig_enforce boot.conf|body=
"Funtoo Linux genkernel signing enforced" {
kernel kernel[-v]
initrd initramfs[-v]
params += real_root=auto rootfstype=auto module.sig_enforce=1
}
}}


Update configuration file that GRUB will use for booting:
{{console|body=
{{console|body=
###i## /usr/src/linux/scripts/sign-file sha512 /etc/kernel/certs/linux/signing_key.pem /etc/kernel/certs/linux/signing_key.x509 ${MODULE_KO}
###i## ego boot update
}}
}}
==Key Security==
{{important|Always keep your private kernel signing keys secret and safe.}}
The private key used to sign kernel modules should be consider secret and always kept safe. It is only needed to be available and readable at the {{c|/etc/kernel/certs/linux}} file path when emerging {{c|sys-kernel/debian-sources}} or {{c|sys-kernel/debian-sources-lts}} using the {{c|sign-modules}} USE flag or when manually signing an out-of-tree kernel module.
This means that these keys can and should be kept securely on encrypted external drives or in other cryptographically secure places like a password manager software, especially if they are being reused across multiple kernel module signings.
As noted by the upstream Linux Kernel Development Team:
'''''Since the private key is used to sign modules, viruses and malware could use the private key to sign modules and compromise the operating system. The private key must be either destroyed or moved to a secure location and not kept in the root node of the kernel source tree.'''''
==Ready to Shim==
Now that our system has a signed kernel and modules, we can load them up for secure boot using the fedora shim.
*[[Package:Shim]]
==References==
Some external documentation for signed kernel modules:
* [https://www.kernel.org/doc/html/v6.1/admin-guide/module-signing.html Official Linux 6.1 Kernel Development Team Doc on Kernel Module Signing Facilities]
* [https://www.rodsbooks.com/efi-bootloaders/sb-modules.html Managing EFI Boot Loaders for Linux: Signing Kernel Modules for Secure Boot]

Latest revision as of 07:07, January 18, 2023

   Warning

Signed Linux Kernel Modules is currently an experimental feature for Funtoo Linux as part of the active Security Project, which hardens and locks down kernel module loading. It is not a production ready feature yet.

All of the required automated tooling is still in development to help support seamless signing of genkernel initramfs modules and signing of any out-of-tree kernel modules available in Funtoo Linux as a package. Proceed with cautious and open mindset, plus the understanding that running full boot time kernel level enforcement of signed modules will require additional manual upkeep until the proper tooling is developed and publicly available

Since the Linux kernel version 3.7.x, support for the signed kernel modules has been useful. When enabled, the Linux kernel will be fixed. This allows the system to be "hardened", not using the unsigned kernel, or kernel modules to be loaded with a wrong key, to be loaded. Malicious kernel modules are a common system for rootkits to enter a Linux system.

When the Linux kernel is building with module signature verification support enabled, then you can use your own keys. We recommend the debian-sources kernel, just enabling the useflag "sign-modules".

root # echo "sys-kernel/debian-sources sign-modules" >> /etc/portage/package.use

We will manually generate the private/public key files using the x509.genkey key generation configuration file and the openssl command. Here is an example to generate the public/private key files:

root # mkdir -p /etc/kernel/certs/linux
root # openssl req -new -nodes -sha256 -x509 -newkey rsa:2048 -days 36500 -addext extendedKeyUsage=1.3.6.1.5.5.7.3.3 -subj '/CN=Funtoo Secure Boot/' -out /etc/kernel/certs/linux/signing_key.cert -keyout /etc/kernel/certs/linux/signing_key.asc
root # cat /etc/kernel/certs/linux/signing_key.asc /etc/kernel/certs/linux/signing_key.cert > /etc/kernel/certs/linux/signing_key.pem
root # openssl x509 -outform der -in /etc/kernel/certs/linux/signing_key.pem -out /etc/kernel/certs/linux/signing_key.x509

Create DER file to sign grub and SHIM (secure boot):

root # openssl x509 -in /etc/kernel/certs/linux/signing_key.cert -outform der -out /etc/kernel/certs/linux/signing_key.der

Fix permissions:

root # chmod -R 644 /etc/kernel/certs/linux/signing_key.pem

Now, build debian-sources with your own keys:

root # emerge sys-kernel/debian-sources

Manually signing modules

If you ever need to manually sign a kernel module, you can use the scripts/sign-file script available in the Linux kernel source tree. It requires four arguments:

  1. The hash algorithm to use, such as sha512.
  2. The private key location.
  3. The certificate (which includes the public key) location.
  4. The kernel module to sign.
root # /usr/src/linux/scripts/sign-file sha512 /etc/kernel/certs/linux/signing_key.pem /etc/kernel/certs/linux/signing_key.x509 ${MODULE_KO}

Advanced Module Signing and Verification Scripts

   Warning

Only run these scripts once booted into a debian-sources kernel that was emerged with the sign-modules USE flag

Module Signing

Here is an experimental but well tested script that locally automates the signing of arbitrary kernel modules (both in-tree and out-of-tree) with your kernel module signing certificate and key:

   sign_out_of_tree_modules.sh (Shell source code) - Kernel module signing script
#!/bin/bash

SIGNING_HASH_ALGO="sha512"
SIGNING_PRIVATE_KEY="/etc/kernel/certs/linux/signing_key.pem"
SIGNING_PUBLIC_KEY="/etc/kernel/certs/linux/signing_key.x509"
SIGNING_SCRIPT_DIR="/usr/src/linux"
SIGNING_SCRIPT="./scripts/sign-file"

KERNEL_VERSION="6.1.4_p1-debian-sources"
KERNEL_MODULES=(
  "/lib/modules/${KERNEL_VERSION}/misc/vboxdrv.ko"
  "/lib/modules/${KERNEL_VERSION}/misc/vboxnetadp.ko"
  "/lib/modules/${KERNEL_VERSION}/misc/vboxnetflt.ko"
  "/lib64/modules/${KERNEL_VERSION}/misc/vboxdrv.ko"
  "/lib64/modules/${KERNEL_VERSION}/misc/vboxnetadp.ko"
  "/lib64/modules/${KERNEL_VERSION}/misc/vboxnetflt.ko"
  "/lib/modules/${KERNEL_VERSION}/extra/v4l2loopback.ko"
)

for mod in "${KERNEL_MODULES[@]}"; do
  echo "signing tainted kernel module $mod"
  (
    cd $SIGNING_SCRIPT_DIR
    $SIGNING_SCRIPT $SIGNING_HASH_ALGO $SIGNING_PRIVATE_KEY $SIGNING_PUBLIC_KEY $mod
  )
done

Adjust the values of these Bash variables for to match your locally configured Funtoo system: SIGNING_HASH_ALGO, KERNEL_VERSION, KERNEL_MODULES

Module Verification

This is an experimental but well tested script that verifies the signatures of all signed kernel modules are correct.

It verifies the signature of each kernel module to ensure it matches what is configured in your kernel.

   verify_signed_modules.sh (Shell source code) - Kernel module signature verification script
#!/bin/bash

# Colors
RED=$'\033[31;01m'
GREEN=$'\033[32;01m'
OFF=$'\033[0m'

SIGNING_HASH_ALGO="sha512"
SIGNING_SIGNER="Funtoo Secure Boot"
KERNEL_VERSION="6.1.4_p1-debian-sources"
MODULE_LIB_DIR="/lib/modules/${KERNEL_VERSION}/"
MODULE_LIB64_DIR="/lib64/modules/${KERNEL_VERSION}/"

for dir in $MODULE_LIB_DIR $MODULE_LIB64_DIR; do
	for mod in $(find $dir -name *.ko | xargs); do
	        if (modinfo $mod | egrep "${SIGNING_SIGNER}|${SIGNING_HASH_ALGO}" &> /dev/null); then
		                echo "${GREEN}PASS${OFF}: kernel module $mod signed. signer:$SIGNING_SIGNER sig_hashalgo:$SIGNING_HASH_ALGO"
	        else
		                echo "${RED}FAIL${OFF}: kernel module $mod is NOT properly signed"
	        fi
	done
done

Adjust the values of these Bash variables to match your locally configured Funtoo system: SIGNING_HASH_ALGO, SIGNING_SIGNER, KERNEL_VERSION

To filter successfully signed kernel modules out and only show failed signatures, execute the above script locally on your Funtoo system with the below syntax:

root # ./verify_signed_modules.sh

If you want to do an ad-hoc verification of a single kernel module's signature you can simply use the modinfo tool:

root # modinfo MODNAME | grep sig

Where MODNAME is the name of the kernel module

Non-valid signatures and unsigned modules

   Note

If module.sig_enforce is disabled (default) it will also load modules that are unsigned.

If module.sig_enforce=1 is enabled is supplied on the kernel command line, the kernel will only load validly signed modules for which it has a public key. Otherwise, it will also load modules that are unsigned. Any module for which the kernel has a key, but which proves to have a signature mismatch will not be permitted to load. Any module that has an unparseable signature will be rejected. When you have confirmed that the modules are being signed and that the kernel works as it should, you can enable the following kernel parameter on your /etc/boot.conf to require that the kernel only permits verified modules to be loaded:

If you need recreate initramfs (optional):

root # genkernel --clean --luks --lvm --disklabel --ramdisk-modules --fullname=debian-sources-x86_64-6.1.4_p1 initramfs

You need sign all modules into initramfs first:

root # mount /boot
root # mkdir /tmp/initram; cd /tmp/initram
root # cp /boot/initramfs-debian-sources-x86_64-6.1.4_p1 .
root # cat initramfs-debian-sources-x86_64-6.1.4_p1 | xz -d | cpio -id
root # find /tmp/initram/lib/modules/ -name "*ko" -exec /usr/src/linux/scripts/sign-file sha256 /etc/kernel/certs/linux/signing_key.pem /etc/kernel/certs/linux/signing_key.x509 '{}' \;
root # mv /boot/initramfs-debian-sources-x86_64-6.1.4_p1 /boot/initramfs-debian-sources-x86_64-6.1.4_p1.old
root # find . | cpio -H newc -o | xz --check=crc32 --x86 --lzma2 >/boot/initramfs-debian-sources-x86_64-6.1.4_p1

Include this parameter on your kernel line into /etc/boot.conf:

module.sig_enforce=1

Example /etc/boot.conf enabling kernel module signature verification:

   /etc/boot.conf - module.sig_enforce boot.conf
"Funtoo Linux genkernel signing enforced" {
	kernel kernel[-v]
	initrd initramfs[-v]
	params += real_root=auto rootfstype=auto module.sig_enforce=1
}

Update configuration file that GRUB will use for booting:

root # ego boot update

Key Security

   Important

Always keep your private kernel signing keys secret and safe.

The private key used to sign kernel modules should be consider secret and always kept safe. It is only needed to be available and readable at the /etc/kernel/certs/linux file path when emerging sys-kernel/debian-sources or sys-kernel/debian-sources-lts using the sign-modules USE flag or when manually signing an out-of-tree kernel module.

This means that these keys can and should be kept securely on encrypted external drives or in other cryptographically secure places like a password manager software, especially if they are being reused across multiple kernel module signings.

As noted by the upstream Linux Kernel Development Team:

Since the private key is used to sign modules, viruses and malware could use the private key to sign modules and compromise the operating system. The private key must be either destroyed or moved to a secure location and not kept in the root node of the kernel source tree.

Ready to Shim

Now that our system has a signed kernel and modules, we can load them up for secure boot using the fedora shim.

References

Some external documentation for signed kernel modules: