diff --git a/dracut-98-integrity.conf b/dracut-98-integrity.conf new file mode 100644 index 0000000..0996b9a --- /dev/null +++ b/dracut-98-integrity.conf @@ -0,0 +1 @@ +add_dracutmodules+=" integrity " diff --git a/ima-add-sigs.sh b/ima-add-sigs.sh new file mode 100755 index 0000000..eadd629 --- /dev/null +++ b/ima-add-sigs.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# +# This script add IMA signatures to installed RPM package files +# Usage: add_ima_sigs.sh [[ALL|PACKAGE_NAME] IMA_CERT_PATH] +# +# By default, it will add IMA sigantures to all installed package files. Or you +# can provide a package name to only add IMA signature for files of specicifed +# package. If it detects >=20 packages (or 1 package if you specify a package +# name) missing signatures in the RPM database, it will reinstall the packages +# in order to get the IMA signatures. +# +# With the signing IMA cert path specified, it will also try to verify +# the added IMA signature. + +if [[ -z "$1" || $1 == ALL ]]; then + package="--all" +else + package=$1 +fi + +ima_cert=$2 + +abort() { + echo "$1" + exit 1 +} + +# Add IMA signatures from RPM database +add_from_rpm_db() { + if ! command -v setfattr &>/dev/null; then + abort "Please install attr" + fi + + # use "|" as deliminator since it won't be used in a filename or signature + while IFS="|" read -r path sig; do + # [[ -z "$sig" ]] somehow doesn't work for some files that don't have IMA + # signatures. This may be a issue of rpm + if [[ "$sig" != "0"* ]]; then + continue + fi + + # Skip directory, soft links, non-existent files and vfat fs + if [[ -d "$path" || -L "$path" || ! -f "$path" || "$path" == "/boot/efi/EFI/"* ]]; then + continue + fi + + if ! setfattr -n security.ima "$path" -v "0x$sig"; then + echo "Failed to add IMA sig for $path" + fi + + [[ -e "$ima_cert" ]] || continue + # TODO + # don't verify the modified files like /etc? + if ! evmctl ima_verify -k "$ima_cert" "$path" &>/dev/null; then + echo "Failed to verify $path" + fi + done < <(rpm -q --queryformat "[%{FILENAMES}|%{FILESIGNATURES}\n]" "$package") +} + +# Add IMA signatures by reinstalling all packages +add_by_reinstall() { + [[ $package == "--all" ]] && package='*' + dnf reinstall "$package" -yq >/dev/null +} + +if [[ $package == "--all" ]]; then + reinstall_threshold=20 +else + if ! rpm -q --quiet $package; then + dnf install "$package" -yq >/dev/null + exit 0 + fi + reinstall_threshold=1 +fi + +unsigned_packages_in_rpm_db=$(rpm -q --queryformat "%{SIGPGP:pgpsig}\n" $package | grep "^(none)$" | wc -l) + +if [[ $unsigned_packages_in_rpm_db -ge $reinstall_threshold ]]; then + add_by_reinstall +else + add_from_rpm_db +fi diff --git a/ima-evm-utils.spec b/ima-evm-utils.spec index ffbc713..f9a1951 100644 --- a/ima-evm-utils.spec +++ b/ima-evm-utils.spec @@ -14,6 +14,14 @@ License: GPLv2 Url: http://linux-ima.sourceforge.net/ Source0: https://github.com/mimizohar/ima-evm-utils/releases/download/v%{version}/%{name}-%{version}.tar.gz +# IMA setup tools +Source2: dracut-98-integrity.conf +Source3: ima-add-sigs.sh +Source4: ima-setup.sh +Source100: policy-01-appraise-exectuables-and-lib-signatures +Source101: policy-02-keylime-remote-attestation +Source200: policy_list + %if 0%{bootstrap} # compat source and patches Source10: ima-evm-utils-1.4.tar.gz @@ -29,6 +37,9 @@ BuildRequires: libxslt BuildRequires: make BuildRequires: openssl-devel BuildRequires: tpm2-tss-devel +Requires: rpm-plugin-ima +Requires: keyutils +Requires: attr %description The Trusted Computing Group(TCG) run-time Integrity Measurement Architecture @@ -81,13 +92,32 @@ popd %ldconfig_scriptlets +# IMA setup tools +install -D -m 644 %{SOURCE2} $RPM_BUILD_ROOT%{_datadir}/ima/dracut-98-integrity.conf + +mkdir -p -m 755 $RPM_BUILD_ROOT%{_datadir}/ima/policies +while IFS= read -r policy_file +do + install -m 644 %{_sourcedir}/policy-"$policy_file" $RPM_BUILD_ROOT%{_datadir}/ima/policies/"$policy_file" +done < %{SOURCE200} + +install -D %{SOURCE3} $RPM_BUILD_ROOT%{_bindir}/ima-add-sigs +install -D %{SOURCE4} $RPM_BUILD_ROOT%{_bindir}/ima-setup + %files %license COPYING %doc NEWS README AUTHORS %{_bindir}/evmctl +%{_mandir}/man1/evmctl* + +# IMA setup tools +%{_datadir}/ima/policies +%{_datadir}/ima/dracut-98-integrity.conf +%{_bindir}/ima-add-sigs +%{_bindir}/ima-setup + # if you need to bump the soname version, coordinate with dependent packages %{_libdir}/libimaevm.so.4* -%{_mandir}/man1/evmctl* %if 0%{bootstrap} %{_libdir}/libimaevm.so.%{compat_soversion} %{_libdir}/libimaevm.so.%{compat_soversion}.0.0 diff --git a/ima-setup.sh b/ima-setup.sh new file mode 100755 index 0000000..6816d7d --- /dev/null +++ b/ima-setup.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# +# This script helps set up IMA. +# +IMA_SYSTEMD_POLICY=/etc/ima/ima-policy +IMA_POLICY_SYSFS=/sys/kernel/security/ima/policy + +usage() { + echo "Set up IMA." + cat </dev/null; then + echo "Failed to load IMA key ${i}" + else + _key_loaded=yes + fi + done + + if [[ $_key_loaded != yes ]]; then + echo "No IMA key loaded" + exit 1 + fi +} + +load_ima_policy() { + local ima_policy_path + + ima_policy_path=$1 + + if ! test -f "$ima_policy_path"; then + echo "$ima_policy_path doesn't exist" + return 1 + fi + if ! echo "$ima_policy_path" >"$IMA_POLICY_SYSFS"; then + echo "$ima_policy_path can't be loaded" + return 1 + fi + # Let systemd load the IMA policy which will load LSM rules first so IMA + # policy containing rules like "appraise obj_type=ifconfig_exec_t" can be + # loaded + [[ -e /etc/ima ]] || mkdir -p /etc/ima/ + if ! cp --preserve=xattr "$ima_policy_path" "$IMA_SYSTEMD_POLICY"; then + echo "Failed to copy $ima_policy_path to $IMA_SYSTEMD_POLICY" + return 1 + fi +} + +echo "Loading IMA keys" +load_ima_keys + +# Include the dracut integrity module to load the IMA keys and policy +# automatically when there is a system reboot +if ! lsinitrd --mod | grep -q integrity; then + cp --preserve=xattr /usr/share/ima/dracut-98-integrity.conf /etc/dracut.conf.d/98-integrity.conf + echo "Rebuilding the initramfs of kernel-$(uname -r) to include the dracut integrity module" + dracut -f +fi + +if ! load_ima_policy "$ima_policy_path"; then + echo "Failed to load IMA policy $ima_policy_path!" + exit 1 +fi diff --git a/policy-01-appraise-exectuables-and-lib-signatures b/policy-01-appraise-exectuables-and-lib-signatures new file mode 100644 index 0000000..afc4530 --- /dev/null +++ b/policy-01-appraise-exectuables-and-lib-signatures @@ -0,0 +1,2 @@ +appraise func=MMAP_CHECK mask=MAY_EXEC appraise_type=imasig +appraise func=BPRM_CHECK appraise_type=imasig diff --git a/policy-02-keylime-remote-attestation b/policy-02-keylime-remote-attestation new file mode 100644 index 0000000..5210734 --- /dev/null +++ b/policy-02-keylime-remote-attestation @@ -0,0 +1,37 @@ +# PROC_SUPER_MAGIC +dont_measure fsmagic=0x9fa0 +# SYSFS_MAGIC +dont_measure fsmagic=0x62656572 +# DEBUGFS_MAGIC +dont_measure fsmagic=0x64626720 +# TMPFS_MAGIC +dont_measure fsmagic=0x01021994 +# DEVPTS_SUPER_MAGIC +dont_measure fsmagic=0x1cd1 +# BINFMTFS_MAGIC +dont_measure fsmagic=0x42494e4d +# SECURITYFS_MAGIC +dont_measure fsmagic=0x73636673 +# SELINUX_MAGIC +dont_measure fsmagic=0xf97cff8c +# SMACK_MAGIC +dont_measure fsmagic=0x43415d53 +# CGROUP_SUPER_MAGIC +dont_measure fsmagic=0x27e0eb +# CGROUP2_SUPER_MAGIC +dont_measure fsmagic=0x63677270 +# NSFS_MAGIC +dont_measure fsmagic=0x6e736673 +# EFIVARFS_MAGIC +dont_measure fsmagic=0xde5e81e4 +# OVERLAYFS_MAGIC +# when containers are used we almost always want to ignore them +dont_measure fsmagic=0x794c7630 + + +# Measure and log keys loaded onto the .ima keyring +measure func=KEY_CHECK keyrings=.ima +# Measure and log executables +measure func=BPRM_CHECK +# Measure and log shared libraries +measure func=FILE_MMAP mask=MAY_EXEC diff --git a/policy_list b/policy_list new file mode 100644 index 0000000..23ff71a --- /dev/null +++ b/policy_list @@ -0,0 +1,2 @@ +01-appraise-exectuables-and-lib-signatures +02-keylime-remote-attestation