init: Activate IMA and EVM in init script as early as possible

Load IMA and EVM keys and activate EVM and load the IMA policy as soon
as the later root filesystem has been mounted. When an IMA policy is
loaded, have the tools (mount, switch_root, etc.) from the later root
filesystem in the PATH before the initrd ones because those ones may be
signed and work with an appraisal policy.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
diff --git a/meta-phosphor/recipes-phosphor/initrdscripts/files/obmc-init.sh b/meta-phosphor/recipes-phosphor/initrdscripts/files/obmc-init.sh
index 3df371f..b7dd0a4 100644
--- a/meta-phosphor/recipes-phosphor/initrdscripts/files/obmc-init.sh
+++ b/meta-phosphor/recipes-phosphor/initrdscripts/files/obmc-init.sh
@@ -126,6 +126,86 @@
 	fi
 }
 
+# If securityfs is available and 'no_ima' is not found in $optfile then
+# - load IMA and EVM keys
+# - activate EVM if an EVM key was loaded
+# - load the IMA policy; in case an appraise policy is used adjust PATH so that
+#   signed executables from $rodir are used rather than the ones from the
+#   initrd
+#
+# This function requires $rodir to be available.
+activate_ima_evm() {
+	if ! grep -w "securityfs" /proc/filesystems >/dev/null ||
+	     grep -w no_ima "${optfile}" >/dev/null
+	then
+		return
+	fi
+
+	mount -t securityfs securityfs /sys/kernel/security
+
+	for kt in ima evm
+	do
+		if test -r "${rodir}/etc/keys/x509_${kt}.der"
+		then
+			LD_LIBRARY_PATH=${rodir}/usr/lib \
+			  ${rodir}/bin/keyctl padd asymmetric '' \
+			    %keyring:.${kt} \
+			    < "${rodir}/etc/keys/x509_${kt}.der" >/dev/null \
+			  && echo "Successfully loaded key onto .${kt} keyring"
+		fi
+	done
+
+	# Activate EVM if .evm keyring exists and is not empty
+	if test -w /sys/kernel/security/evm -a \
+		-n "$(grep ' .evm:' /proc/keys)" -a \
+		-z "$(grep ' .evm: empty' /proc/keys)"
+	then
+		# EVM key loaded, activate it
+		evm_act=2147483650  # $((0x80000002))
+		if echo "${evm_act}" > /sys/kernel/security/evm
+		then
+			printf "Activated EVM: $(cat /sys/kernel/security/evm) [ activated with 0x%x ]\n" $evm_act
+		fi
+	fi
+
+	# Load IMA policy
+	if test -w /sys/kernel/security/ima/policy -a \
+		-r "/${rodir}/etc/ima/ima-policy"
+	then
+		load_ima_policy=0
+
+		# If a signed policy is required ...
+		if grep -q -E "^appraise func=POLICY_CHECK" \
+			"/${rodir}/etc/ima/ima-policy"
+		then
+			# ... check that .ima exists and is not empty
+			if test  -n "$(grep ' .ima:' /proc/keys)" -a \
+				 -z "$(grep ' .ima: empty' /proc/keys)"
+			then
+				load_ima_policy=1
+			fi
+		else
+			# otherwise load it
+			load_ima_policy=1
+		fi
+
+		if test ${load_ima_policy} = 1
+		then
+			echo "/${rodir}/etc/ima/ima-policy" \
+				> /sys/kernel/security/ima/policy
+		fi
+
+		# If an appraise policy is active use executables from ${rodir}
+		if grep -q -E "appraise .*func=(MMAP_CHECK|BPRM_CHECK)" \
+				/sys/kernel/security/ima/policy
+		then
+			export PATH="/${rodir}/sbin:$PATH"
+		fi
+	fi
+
+	umount /sys/kernel/security
+}
+
 debug_takeover() {
 	echo "$@"
 
@@ -375,6 +455,8 @@
 
 mount "$rodev" $rodir -t $rofst -o $roopts
 
+activate_ima_evm
+
 if test -x "$rodir$fsck"
 then
 	for fs in $fslist