1# No default! Either this or IMA_EVM_PRIVKEY/IMA_EVM_X509 have to be 2# set explicitly in a local.conf before activating ima-evm-rootfs. 3# To use the insecure (because public) example keys, use 4# IMA_EVM_KEY_DIR = "${INTEGRITY_BASE}/data/debug-keys" 5IMA_EVM_KEY_DIR ?= "IMA_EVM_KEY_DIR_NOT_SET" 6 7# Private key for IMA signing. The default is okay when 8# using the example key directory. 9IMA_EVM_PRIVKEY ?= "${IMA_EVM_KEY_DIR}/privkey_ima.pem" 10 11# Additional option when signing. Allows to for example provide 12# --keyid <id> or --keyid-from-cert <filename>. 13IMA_EVM_PRIVKEY_KEYID_OPT ?= "" 14 15# Password for the private key 16IMA_EVM_EVMCTL_KEY_PASSWORD ?= "" 17 18# Public part of certificates (used for both IMA and EVM). 19# The default is okay when using the example key directory. 20IMA_EVM_X509 ?= "${IMA_EVM_KEY_DIR}/x509_ima.der" 21 22# Root CA to be compiled into the kernel, none by default. 23# Must be the absolute path to a der-encoded x509 CA certificate 24# with a .x509 suffix. See linux-%.bbappend for details. 25# 26# ima-local-ca.x509 is what ima-gen-local-ca.sh creates. 27IMA_EVM_ROOT_CA ?= "${IMA_EVM_KEY_DIR}/ima-local-ca.pem" 28 29# Mount these file systems (identified via their mount point) with 30# the iversion flags (needed by IMA when allowing writing). 31IMA_EVM_ROOTFS_IVERSION ?= "" 32 33# Avoid re-generating fstab when ima is enabled. 34WIC_CREATE_EXTRA_ARGS:append = "${@bb.utils.contains('DISTRO_FEATURES', 'ima', ' --no-fstab-update', '', d)}" 35 36# Add necessary tools (e.g., keyctl) to image 37IMAGE_INSTALL:append = "${@bb.utils.contains('DISTRO_FEATURES', 'ima', ' ima-evm-utils', '', d)}" 38 39ima_evm_sign_rootfs () { 40 cd ${IMAGE_ROOTFS} 41 42 # Beware that all operations below must also work when 43 # ima_evm_sign_rootfs was already called earlier for the same 44 # rootfs. That's because do_image might again run for various 45 # reasons (including a change of the signing keys) without also 46 # re-running do_rootfs. 47 48 # Fix /etc/fstab: it must include the "i_version" mount option for 49 # those file systems where writing files is allowed, otherwise 50 # these changes will not get detected at runtime. 51 # 52 # Note that "i_version" is documented in "man mount" only for ext4, 53 # whereas "iversion" is said to be filesystem-independent. In practice, 54 # there is only one MS_I_VERSION flag in the syscall and ext2/ext3/ext4 55 # all support it. 56 # 57 # coreutils translates "iversion" into MS_I_VERSION. busybox rejects 58 # "iversion" and only understands "i_version". systemd only understands 59 # "iversion". We pick "iversion" here for systemd, whereas rootflags 60 # for initramfs must use "i_version" for busybox. 61 # 62 # Deduplicates iversion in case that this gets called more than once. 63 if [ -f etc/fstab ]; then 64 perl -pi -e 's;(\S+)(\s+)(${@"|".join((d.getVar("IMA_EVM_ROOTFS_IVERSION", True) or "no-such-mount-point").split())})(\s+)(\S+)(\s+)(\S+);\1\2\3\4\5\6\7,iversion;; s/(,iversion)+/,iversion/;' etc/fstab 65 fi 66 67 # Detect 32bit target to pass --m32 to evmctl by looking at libc 68 tmp="$(file "${IMAGE_ROOTFS}/lib/libc.so.6" | grep -o 'ELF .*-bit')" 69 if [ "${tmp}" = "ELF 32-bit" ]; then 70 evmctl_param="--m32" 71 elif [ "${tmp}" = "ELF 64-bit" ]; then 72 evmctl_param="" 73 else 74 bberror "Unknown target architecture bitness: '${tmp}'" >&2 75 exit 1 76 fi 77 78 export EVMCTL_KEY_PASSWORD=${IMA_EVM_EVMCTL_KEY_PASSWORD} 79 80 bbnote "IMA/EVM: Signing root filesystem at ${IMAGE_ROOTFS} with key ${IMA_EVM_PRIVKEY}" 81 evmctl sign --imasig ${evmctl_param} --portable -a sha256 \ 82 --key "${IMA_EVM_PRIVKEY}" ${IMA_EVM_PRIVKEY_KEYID_OPT} -r "${IMAGE_ROOTFS}" 83 84 # check signing key and signature verification key 85 evmctl ima_verify ${evmctl_param} --key "${IMA_EVM_X509}" "${IMAGE_ROOTFS}/lib/libc.so.6" || exit 1 86 evmctl verify ${evmctl_param} --key "${IMA_EVM_X509}" "${IMAGE_ROOTFS}/lib/libc.so.6" || exit 1 87 88 # Optionally install custom policy for loading by systemd. 89 if [ "${IMA_EVM_POLICY}" ]; then 90 install -d ./${sysconfdir}/ima 91 rm -f ./${sysconfdir}/ima/ima-policy 92 install "${IMA_EVM_POLICY}" ./${sysconfdir}/ima/ima-policy 93 94 bbnote "IMA/EVM: Signing IMA policy with key ${IMA_EVM_PRIVKEY}" 95 evmctl sign --imasig ${evmctl_param} --portable -a sha256 \ 96 --key "${IMA_EVM_PRIVKEY}" ${IMA_EVM_PRIVKEY_KEYID_OPT} "${IMAGE_ROOTFS}/etc/ima/ima-policy" 97 fi 98 99 # Optionally write the file names and ima and evm signatures into files 100 if [ "${IMA_FILE_SIGNATURES_FILE}" ]; then 101 getfattr -R -m security.ima --e hex --dump ./ 2>/dev/null | \ 102 sed -n -e 's|# file: |/|p' -e 's|security.ima=|ima:|p' | \ 103 sed '$!N;s/\n/ /' > ./${IMA_FILE_SIGNATURES_FILE} 104 fi 105 if [ "${EVM_FILE_SIGNATURES_FILE}" ]; then 106 getfattr -R -m security.evm --e hex --dump ./ 2>/dev/null | \ 107 sed -n -e 's|# file: |/|p' -e 's|security.evm=|evm:|p' | \ 108 sed '$!N;s/\n/ /' > ./${EVM_FILE_SIGNATURES_FILE} 109 fi 110} 111 112# Signing must run as late as possible in the do_rootfs task. 113# To guarantee that, we append it to IMAGE_PREPROCESS_COMMAND in 114# RecipePreFinalise event handler, this ensures it's the last 115# function in IMAGE_PREPROCESS_COMMAND. 116python ima_evm_sign_handler () { 117 if not e.data or 'ima' not in e.data.getVar('DISTRO_FEATURES').split(): 118 return 119 120 e.data.appendVar('IMAGE_PREPROCESS_COMMAND', ' ima_evm_sign_rootfs; ') 121 e.data.appendVar('IMAGE_INSTALL', ' ima-evm-keys') 122 e.data.appendVarFlag('do_rootfs', 'depends', ' ima-evm-utils-native:do_populate_sysroot') 123} 124addhandler ima_evm_sign_handler 125ima_evm_sign_handler[eventmask] = "bb.event.RecipePreFinalise" 126