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 <[email protected]> 5# Author: Mimi Zohar <[email protected]> 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 "IMA measurement tests require builtin IMA $policy policy (e.g. ima_policy=$policy kernel 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 [ -z "$DIGEST_INDEX" ] && tst_brk TCONF \ 222 "Cannot find digest index (template: '$template')" 223} 224 225get_algorithm_digest() 226{ 227 local line="$1" 228 local delimiter=':' 229 local algorithm digest 230 231 if [ -z "$line" ]; then 232 echo "measurement record not found" 233 return 1 234 fi 235 236 [ -z "$DIGEST_INDEX" ] && set_digest_index 237 digest=$(echo "$line" | cut -d' ' -f $DIGEST_INDEX) 238 if [ -z "$digest" ]; then 239 echo "digest not found (index: $DIGEST_INDEX, line: '$line')" 240 return 1 241 fi 242 243 if [ "${digest#*$delimiter}" != "$digest" ]; then 244 algorithm=$(echo "$digest" | cut -d $delimiter -f 1) 245 digest=$(echo "$digest" | cut -d $delimiter -f 2) 246 else 247 case "${#digest}" in 248 32) algorithm="md5" ;; 249 40) algorithm="sha1" ;; 250 *) 251 echo "algorithm must be either md5 or sha1 (digest: '$digest')" 252 return 1 ;; 253 esac 254 fi 255 if [ -z "$algorithm" ]; then 256 echo "algorithm not found" 257 return 1 258 fi 259 if [ -z "$digest" ]; then 260 echo "digest not found" 261 return 1 262 fi 263 264 echo "$algorithm|$digest" 265} 266 267ima_check() 268{ 269 local test_file="$1" 270 local algorithm digest expected_digest line tmp 271 272 # need to read file to get updated $ASCII_MEASUREMENTS 273 cat $test_file > /dev/null 274 275 line="$(grep $test_file $ASCII_MEASUREMENTS | tail -1)" 276 277 if tmp=$(get_algorithm_digest "$line"); then 278 algorithm=$(echo "$tmp" | cut -d'|' -f1) 279 digest=$(echo "$tmp" | cut -d'|' -f2) 280 else 281 tst_res TBROK "failed to get algorithm/digest for '$test_file': $tmp" 282 fi 283 284 tst_res TINFO "computing digest for $algorithm algorithm" 285 expected_digest="$(compute_digest $algorithm $test_file)" || \ 286 tst_brk TCONF "cannot compute digest for $algorithm algorithm" 287 288 if [ "$digest" = "$expected_digest" ]; then 289 tst_res TPASS "correct digest found" 290 else 291 tst_res TFAIL "digest not found" 292 fi 293} 294 295# check_evmctl REQUIRED_TPM_VERSION 296# return: 0: evmctl is new enough, 1: version older than required (or version < v0.9) 297check_evmctl() 298{ 299 local required="$1" 300 301 local r1="$(echo $required | cut -d. -f1)" 302 local r2="$(echo $required | cut -d. -f2)" 303 local r3="$(echo $required | cut -d. -f3)" 304 [ -z "$r3" ] && r3=0 305 306 tst_is_int "$r1" || tst_brk TBROK "required major version not int ($v1)" 307 tst_is_int "$r2" || tst_brk TBROK "required minor version not int ($v2)" 308 tst_is_int "$r3" || tst_brk TBROK "required patch version not int ($v3)" 309 310 tst_check_cmds evmctl || return 1 311 312 local v="$(evmctl --version | cut -d' ' -f2)" 313 [ -z "$v" ] && return 1 314 tst_res TINFO "evmctl version: $v" 315 316 local v1="$(echo $v | cut -d. -f1)" 317 local v2="$(echo $v | cut -d. -f2)" 318 local v3="$(echo $v | cut -d. -f3)" 319 [ -z "$v3" ] && v3=0 320 321 if [ $v1 -lt $r1 ] || [ $v1 -eq $r1 -a $v2 -lt $r2 ] || \ 322 [ $v1 -eq $r1 -a $v2 -eq $r2 -a $v3 -lt $r3 ]; then 323 return 1 324 fi 325 return 0 326} 327 328# require_evmctl REQUIRED_TPM_VERSION 329require_evmctl() 330{ 331 local required="$1" 332 333 if ! check_evmctl $required; then 334 tst_brk TCONF "evmctl >= $required required" 335 fi 336} 337 338. tst_test.sh 339 340# loop device is needed to use only for tmpfs 341TMPDIR="${TMPDIR:-/tmp}" 342if tst_supported_fs -d $TMPDIR -s "tmpfs"; then 343 unset TST_MOUNT_DEVICE 344fi 345 346. tst_test.sh 347