Home | History | Annotate | Download | only in tests
      1 #!/bin/sh
      2 # Copyright (c) 2009 IBM Corporation
      3 # Copyright (c) 2018 Petr Vorel <pvorel (at] suse.cz>
      4 #
      5 # This program is free software; you can redistribute it and/or
      6 # modify it under the terms of the GNU General Public License as
      7 # published by the Free Software Foundation; either version 2 of
      8 # the License, or (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it would be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License
     16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
     17 #
     18 # Author: Mimi Zohar, zohar (at] ibm.vnet.ibm.com
     19 #
     20 # Verify that measurements are added to the measurement list based on policy.
     21 
     22 TST_NEEDS_CMDS="awk cut"
     23 TST_SETUP="setup"
     24 TST_CNT=3
     25 TST_NEEDS_DEVICE=1
     26 
     27 . ima_setup.sh
     28 
     29 setup()
     30 {
     31 	TEST_FILE="$PWD/test.txt"
     32 
     33 	POLICY="$IMA_DIR/policy"
     34 	[ -f "$POLICY" ] || tst_res TINFO "not using default policy"
     35 
     36 	DIGEST_INDEX=
     37 
     38 	local template="$(tail -1 $ASCII_MEASUREMENTS | cut -d' ' -f 3)"
     39 	local i
     40 
     41 	# https://www.kernel.org/doc/html/latest/security/IMA-templates.html#use
     42 	case "$template" in
     43 	ima|ima-ng|ima-sig) DIGEST_INDEX=4 ;;
     44 	*)
     45 		# using ima_template_fmt kernel parameter
     46 		local IFS="|"
     47 		i=4
     48 		for word in $template; do
     49 			if [ "$word" = 'd' -o "$word" = 'd-ng' ]; then
     50 				DIGEST_INDEX=$i
     51 				break
     52 			fi
     53 			i=$((i+1))
     54 		done
     55 	esac
     56 
     57 	[ -z "$DIGEST_INDEX" ] && tst_brk TCONF \
     58 		"Cannot find digest index (template: '$template')"
     59 
     60 	tst_res TINFO "IMA measurement tests assume tcb policy to be loaded (ima_policy=tcb)"
     61 }
     62 
     63 # TODO: find support for rmd128 rmd256 rmd320 wp256 wp384 tgr128 tgr160
     64 compute_digest()
     65 {
     66 	local algorithm="$1"
     67 	local file="$2"
     68 	local digest
     69 
     70 	digest="$(${algorithm}sum $file 2>/dev/null | cut -f1 -d ' ')"
     71 	if [ -n "$digest" ]; then
     72 		echo "$digest"
     73 		return 0
     74 	fi
     75 
     76 	digest="$(openssl $algorithm $file 2>/dev/null | cut -f2 -d ' ')"
     77 	if [ -n "$digest" ]; then
     78 		echo "$digest"
     79 		return 0
     80 	fi
     81 
     82 	# uncommon ciphers
     83 	local arg="$algorithm"
     84 	case "$algorithm" in
     85 	tgr192) arg="tiger" ;;
     86 	wp512) arg="whirlpool" ;;
     87 	esac
     88 
     89 	digest="$(rdigest --$arg $file 2>/dev/null | cut -f1 -d ' ')"
     90 	if [ -n "$digest" ]; then
     91 		echo "$digest"
     92 		return 0
     93 	fi
     94 	return 1
     95 }
     96 
     97 ima_check()
     98 {
     99 	local delimiter=':'
    100 	local algorithm digest expected_digest line
    101 
    102 	# need to read file to get updated $ASCII_MEASUREMENTS
    103 	cat $TEST_FILE > /dev/null
    104 
    105 	line="$(grep $TEST_FILE $ASCII_MEASUREMENTS | tail -1)"
    106 	if [ -z "$line" ]; then
    107 		tst_res TFAIL "cannot find measurement record for '$TEST_FILE'"
    108 		return
    109 	fi
    110 	tst_res TINFO "measurement record: '$line'"
    111 
    112 	digest=$(echo "$line" | cut -d' ' -f $DIGEST_INDEX)
    113 	if [ -z "$digest" ]; then
    114 		tst_res TFAIL "cannot find digest (index: $DIGEST_INDEX)"
    115 		return
    116 	fi
    117 
    118 	if [ "${digest#*$delimiter}" != "$digest" ]; then
    119 		algorithm=$(echo "$digest" | cut -d $delimiter -f 1)
    120 		digest=$(echo "$digest" | cut -d $delimiter -f 2)
    121 	else
    122 		case "${#digest}" in
    123 		32) algorithm="md5" ;;
    124 		40) algorithm="sha1" ;;
    125 		*)
    126 			tst_res TFAIL "algorithm must be either md5 or sha1 (digest: '$digest')"
    127 			return ;;
    128 		esac
    129 	fi
    130 	if [ -z "$algorithm" ]; then
    131 		tst_res TFAIL "cannot find algorithm"
    132 		return
    133 	fi
    134 	if [ -z "$digest" ]; then
    135 		tst_res TFAIL "cannot find digest"
    136 		return
    137 	fi
    138 
    139 	tst_res TINFO "computing digest for $algorithm algorithm"
    140 	expected_digest="$(compute_digest $algorithm $TEST_FILE)" || \
    141 		tst_brk TCONF "cannot compute digest for $algorithm algorithm"
    142 
    143 	if [ "$digest" = "$expected_digest" ]; then
    144 		tst_res TPASS "correct digest found"
    145 	else
    146 		tst_res TFAIL "digest not found"
    147 	fi
    148 }
    149 
    150 check_iversion_support()
    151 {
    152 	local device mount fs
    153 
    154 	tst_kvcmp -ge "4.16" && return 0
    155 
    156 	device="$(df . | sed -e 1d | cut -f1 -d ' ')"
    157 	mount="$(grep $device /proc/mounts | head -1)"
    158 	fs="$(echo $mount | awk '{print $3'})"
    159 
    160 	case "$fs" in
    161 	ext[2-4])
    162 		if ! echo "$mount" | grep -q -w "i_version"; then
    163 			tst_res TCONF "device '$device' is not mounted with iversion, please mount it with 'mount $device -o remount,iversion'"
    164 			return 1
    165 		fi
    166 		;;
    167 	xfs)
    168 		if dmesg | grep -q "XFS.*Mounting V[1-4] Filesystem"; then
    169 			tst_res TCONF "XFS Filesystem >= V5 required for iversion support"
    170 			return 1
    171 		fi
    172 		;;
    173 	'')
    174 		tst_res TWARN "could not find mount info for device '$device'"
    175 		;;
    176 	esac
    177 
    178 	return 0
    179 }
    180 
    181 test1()
    182 {
    183 	tst_res TINFO "verify adding record to the IMA measurement list"
    184 	ROD echo "$(date) this is a test file" \> $TEST_FILE
    185 	ima_check
    186 }
    187 
    188 test2()
    189 {
    190 
    191 	tst_res TINFO "verify updating record in the IMA measurement list"
    192 	check_iversion_support || return
    193 	ROD echo "$(date) modified file" \> $TEST_FILE
    194 	ima_check
    195 }
    196 
    197 test3()
    198 {
    199 	local user="nobody"
    200 	local dir="$PWD/user"
    201 	local file="$dir/test.txt"
    202 
    203 	# Default policy does not measure user files
    204 	tst_res TINFO "verify not measuring user files"
    205 	tst_check_cmds sudo
    206 
    207 	if ! id $user >/dev/null 2>/dev/null; then
    208 		tst_res TCONF "missing system user $user (wrong installation)"
    209 		return
    210 	fi
    211 
    212 	mkdir -m 0700 $dir
    213 	chown $user $dir
    214 	cd $dir
    215 	# need to read file to get updated $ASCII_MEASUREMENTS
    216 	sudo -n -u $user sh -c "echo $(date) user file > $file; cat $file > /dev/null"
    217 	cd ..
    218 
    219 	EXPECT_FAIL "grep $file $ASCII_MEASUREMENTS"
    220 }
    221 
    222 tst_run
    223