1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0-or-later 3# Copyright (c) 2009 IBM Corporation 4# Copyright (c) 2018-2020 Petr Vorel <pvorel@suse.cz> 5# Author: Mimi Zohar <zohar@linux.ibm.com> 6 7TST_TESTFUNC="test" 8TST_SETUP_CALLER="$TST_SETUP" 9TST_SETUP="ima_setup" 10TST_CLEANUP_CALLER="$TST_CLEANUP" 11TST_CLEANUP="ima_cleanup" 12TST_NEEDS_ROOT=1 13TST_MOUNT_DEVICE=1 14 15# TST_MOUNT_DEVICE can be unset, therefore specify explicitly 16TST_NEEDS_TMPDIR=1 17 18SYSFS="/sys" 19UMOUNT= 20TST_FS_TYPE="ext3" 21 22# TODO: find support for rmd128 rmd256 rmd320 wp256 wp384 tgr128 tgr160 23compute_digest() 24{ 25 local algorithm="$1" 26 local file="$2" 27 local digest 28 29 digest="$(${algorithm}sum $file 2>/dev/null | cut -f1 -d ' ')" 30 if [ -n "$digest" ]; then 31 echo "$digest" 32 return 0 33 fi 34 35 digest="$(openssl $algorithm $file 2>/dev/null | cut -f2 -d ' ')" 36 if [ -n "$digest" ]; then 37 echo "$digest" 38 return 0 39 fi 40 41 # uncommon ciphers 42 local arg="$algorithm" 43 case "$algorithm" in 44 tgr192) arg="tiger" ;; 45 wp512) arg="whirlpool" ;; 46 esac 47 48 digest="$(rdigest --$arg $file 2>/dev/null | cut -f1 -d ' ')" 49 if [ -n "$digest" ]; then 50 echo "$digest" 51 return 0 52 fi 53 return 1 54} 55 56check_policy_readable() 57{ 58 if [ ! -f $IMA_POLICY ]; then 59 tst_res TINFO "missing $IMA_POLICY (reboot or CONFIG_IMA_WRITE_POLICY=y required)" 60 return 1 61 fi 62 cat $IMA_POLICY > /dev/null 2>/dev/null 63} 64 65require_policy_readable() 66{ 67 if [ ! -f $IMA_POLICY ]; then 68 tst_brk TCONF "missing $IMA_POLICY (reboot or CONFIG_IMA_WRITE_POLICY=y required)" 69 fi 70 if ! check_policy_readable; then 71 tst_brk TCONF "cannot read IMA policy (CONFIG_IMA_READ_POLICY=y required)" 72 fi 73} 74 75require_policy_writable() 76{ 77 local err="IMA policy already loaded and kernel not configured to enable multiple writes to it (need CONFIG_IMA_WRITE_POLICY=y)" 78 79 [ -f $IMA_POLICY ] || tst_brk TCONF "$err" 80 # CONFIG_IMA_READ_POLICY 81 echo "" 2> log > $IMA_POLICY 82 grep -q "Device or resource busy" log && tst_brk TCONF "$err" 83} 84 85check_ima_policy_content() 86{ 87 local pattern="$1" 88 local grep_params="${2--q}" 89 90 check_policy_readable || return 1 91 grep $grep_params "$pattern" $IMA_POLICY 92} 93 94require_ima_policy_content() 95{ 96 local pattern="$1" 97 local grep_params="${2--q}" 98 99 require_policy_readable 100 if ! grep $grep_params "$pattern" $IMA_POLICY; then 101 tst_brk TCONF "IMA policy does not specify '$pattern'" 102 fi 103} 104 105check_ima_policy_cmdline() 106{ 107 local policy="$1" 108 local i 109 110 grep -q "ima_$policy" /proc/cmdline && return 111 for i in $(cat /proc/cmdline); do 112 if echo "$i" | grep -q '^ima_policy='; then 113 echo "$i" | grep -q -e "|[ ]*$policy" -e "$policy[ ]*|" -e "=$policy" && return 0 114 fi 115 done 116 return 1 117} 118 119require_ima_policy_cmdline() 120{ 121 local policy="$1" 122 123 check_ima_policy_cmdline $policy || \ 124 tst_brk TCONF "test requires builtin IMA $policy policy (e.g. ima_policy=$policy kernel command line parameter)" 125} 126 127mount_helper() 128{ 129 local type="$1" 130 local default_dir="$2" 131 local dir 132 133 dir="$(grep ^$type /proc/mounts | cut -d ' ' -f2 | head -1)" 134 [ -n "$dir" ] && { echo "$dir"; return; } 135 136 if ! mkdir -p $default_dir; then 137 tst_brk TBROK "failed to create $default_dir" 138 fi 139 if ! mount -t $type $type $default_dir; then 140 tst_brk TBROK "failed to mount $type" 141 fi 142 UMOUNT="$default_dir $UMOUNT" 143 echo $default_dir 144} 145 146print_ima_config() 147{ 148 local config="${KCONFIG_PATH:-/boot/config-$(uname -r)}" 149 local i 150 151 if [ -r "$config" ]; then 152 tst_res TINFO "IMA kernel config:" 153 for i in $(grep ^CONFIG_IMA $config); do 154 tst_res TINFO "$i" 155 done 156 fi 157 158 tst_res TINFO "/proc/cmdline: $(cat /proc/cmdline)" 159} 160 161ima_setup() 162{ 163 SECURITYFS="$(mount_helper securityfs $SYSFS/kernel/security)" 164 165 IMA_DIR="$SECURITYFS/ima" 166 [ -d "$IMA_DIR" ] || tst_brk TCONF "IMA not enabled in kernel" 167 ASCII_MEASUREMENTS="$IMA_DIR/ascii_runtime_measurements" 168 BINARY_MEASUREMENTS="$IMA_DIR/binary_runtime_measurements" 169 IMA_POLICY="$IMA_DIR/policy" 170 171 # hack to support running tests locally from ima/tests directory 172 if [ ! -d "$TST_DATAROOT" ]; then 173 TST_DATAROOT="$LTPROOT/../datafiles/$TST_ID/" 174 fi 175 176 print_ima_config 177 178 if [ "$TST_MOUNT_DEVICE" = 1 ]; then 179 tst_res TINFO "\$TMPDIR is on tmpfs => run on loop device" 180 cd "$TST_MNTPOINT" 181 fi 182 183 [ -n "$TST_SETUP_CALLER" ] && $TST_SETUP_CALLER 184} 185 186ima_cleanup() 187{ 188 local dir 189 190 [ -n "$TST_CLEANUP_CALLER" ] && $TST_CLEANUP_CALLER 191 192 for dir in $UMOUNT; do 193 umount $dir 194 done 195} 196 197set_digest_index() 198{ 199 DIGEST_INDEX= 200 201 local template="$(tail -1 $ASCII_MEASUREMENTS | cut -d' ' -f 3)" 202 local i word 203 204 # parse digest index 205 # https://www.kernel.org/doc/html/latest/security/IMA-templates.html#use 206 case "$template" in 207 ima|ima-ng|ima-sig) DIGEST_INDEX=4 ;; 208 *) 209 # using ima_template_fmt kernel parameter 210 local IFS="|" 211 i=4 212 for word in $template; do 213 if [ "$word" = 'd' -o "$word" = 'd-ng' ]; then 214 DIGEST_INDEX=$i 215 break 216 fi 217 i=$((i+1)) 218 done 219 esac 220 221 if [ -z "$DIGEST_INDEX" ]; then 222 tst_res TWARN "Cannot find digest index (template: '$template')" 223 return 1 224 fi 225} 226 227get_algorithm_digest() 228{ 229 local line="$1" 230 local delimiter=':' 231 local algorithm digest 232 233 if [ -z "$line" ]; then 234 echo "measurement record not found" 235 return 1 236 fi 237 238 if [ -z "$DIGEST_INDEX" ]; then 239 set_digest_index 240 fi 241 if [ -z "$DIGEST_INDEX" ]; then 242 return 1 243 fi 244 245 digest=$(echo "$line" | cut -d' ' -f $DIGEST_INDEX) 246 if [ -z "$digest" ]; then 247 echo "digest not found (index: $DIGEST_INDEX, line: '$line')" 248 return 1 249 fi 250 251 if [ "${digest#*$delimiter}" != "$digest" ]; then 252 algorithm=$(echo "$digest" | cut -d $delimiter -f 1) 253 digest=$(echo "$digest" | cut -d $delimiter -f 2) 254 else 255 case "${#digest}" in 256 32) algorithm="md5" ;; 257 40) algorithm="sha1" ;; 258 *) 259 echo "algorithm must be either md5 or sha1 (digest: '$digest')" 260 return 1 ;; 261 esac 262 fi 263 if [ -z "$algorithm" ]; then 264 echo "algorithm not found" 265 return 1 266 fi 267 if [ -z "$digest" ]; then 268 echo "digest not found" 269 return 1 270 fi 271 272 echo "$algorithm|$digest" 273} 274 275ima_check() 276{ 277 local test_file="$1" 278 local algorithm digest expected_digest line 279 280 # need to read file to get updated $ASCII_MEASUREMENTS 281 cat $test_file > /dev/null 282 283 line="$(grep $test_file $ASCII_MEASUREMENTS | tail -1)" 284 285 if get_algorithm_digest "$line" > tmp; then 286 algorithm=$(cat tmp | cut -d'|' -f1) 287 digest=$(cat tmp | cut -d'|' -f2) 288 else 289 tst_brk TBROK "failed to get algorithm/digest for '$test_file'" 290 fi 291 292 tst_res TINFO "computing digest for $algorithm algorithm" 293 expected_digest="$(compute_digest $algorithm $test_file)" || \ 294 tst_brk TCONF "cannot compute digest for $algorithm algorithm" 295 296 if [ "$digest" = "$expected_digest" ]; then 297 tst_res TPASS "correct digest found" 298 else 299 tst_res TFAIL "digest not found" 300 fi 301} 302 303# check_evmctl REQUIRED_TPM_VERSION 304# return: 0: evmctl is new enough, 1: version older than required (or version < v0.9) 305check_evmctl() 306{ 307 local required="$1" 308 309 local r1="$(echo $required | cut -d. -f1)" 310 local r2="$(echo $required | cut -d. -f2)" 311 local r3="$(echo $required | cut -d. -f3)" 312 [ -z "$r3" ] && r3=0 313 314 tst_is_int "$r1" || tst_brk TBROK "required major version not int ($v1)" 315 tst_is_int "$r2" || tst_brk TBROK "required minor version not int ($v2)" 316 tst_is_int "$r3" || tst_brk TBROK "required patch version not int ($v3)" 317 318 tst_check_cmds evmctl || return 1 319 320 local v="$(evmctl --version | cut -d' ' -f2)" 321 [ -z "$v" ] && return 1 322 tst_res TINFO "evmctl version: $v" 323 324 local v1="$(echo $v | cut -d. -f1)" 325 local v2="$(echo $v | cut -d. -f2)" 326 local v3="$(echo $v | cut -d. -f3)" 327 [ -z "$v3" ] && v3=0 328 329 if [ $v1 -lt $r1 ] || [ $v1 -eq $r1 -a $v2 -lt $r2 ] || \ 330 [ $v1 -eq $r1 -a $v2 -eq $r2 -a $v3 -lt $r3 ]; then 331 return 1 332 fi 333 return 0 334} 335 336# require_evmctl REQUIRED_TPM_VERSION 337require_evmctl() 338{ 339 local required="$1" 340 341 if ! check_evmctl $required; then 342 tst_brk TCONF "evmctl >= $required required" 343 fi 344} 345 346. tst_test.sh 347 348# loop device is needed to use only for tmpfs 349TMPDIR="${TMPDIR:-/tmp}" 350if tst_supported_fs -d $TMPDIR -s "tmpfs"; then 351 unset TST_MOUNT_DEVICE 352fi 353 354. tst_test.sh 355