1#!/bin/sh 2# Copyright (c) 2009 IBM Corporation 3# Copyright (c) 2018 Petr Vorel <pvorel@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@ibm.vnet.ibm.com 19# 20# Verify that measurements are added to the measurement list based on policy. 21 22TST_NEEDS_CMDS="awk cut" 23TST_SETUP="setup" 24TST_CNT=3 25TST_NEEDS_DEVICE=1 26 27. ima_setup.sh 28 29setup() 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 64compute_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 97ima_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 150check_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 181test1() 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 188test2() 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 197test3() 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 222tst_run 223