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 13 14# TST_NEEDS_DEVICE can be unset, therefore specify explicitly 15TST_NEEDS_TMPDIR=1 16 17. tst_test.sh 18 19SYSFS="/sys" 20UMOUNT= 21TST_FS_TYPE="ext3" 22 23# TODO: find support for rmd128 rmd256 rmd320 wp256 wp384 tgr128 tgr160 24compute_digest() 25{ 26 local algorithm="$1" 27 local file="$2" 28 local digest 29 30 digest="$(${algorithm}sum $file 2>/dev/null | cut -f1 -d ' ')" 31 if [ -n "$digest" ]; then 32 echo "$digest" 33 return 0 34 fi 35 36 digest="$(openssl $algorithm $file 2>/dev/null | cut -f2 -d ' ')" 37 if [ -n "$digest" ]; then 38 echo "$digest" 39 return 0 40 fi 41 42 # uncommon ciphers 43 local arg="$algorithm" 44 case "$algorithm" in 45 tgr192) arg="tiger" ;; 46 wp512) arg="whirlpool" ;; 47 esac 48 49 digest="$(rdigest --$arg $file 2>/dev/null | cut -f1 -d ' ')" 50 if [ -n "$digest" ]; then 51 echo "$digest" 52 return 0 53 fi 54 return 1 55} 56 57check_policy_readable() 58{ 59 if [ ! -f $IMA_POLICY ]; then 60 tst_res TINFO "missing $IMA_POLICY (reboot or CONFIG_IMA_WRITE_POLICY=y required)" 61 return 1 62 fi 63 cat $IMA_POLICY > /dev/null 2>/dev/null 64} 65 66require_policy_readable() 67{ 68 if [ ! -f $IMA_POLICY ]; then 69 tst_brk TCONF "missing $IMA_POLICY (reboot or CONFIG_IMA_WRITE_POLICY=y required)" 70 fi 71 if ! check_policy_readable; then 72 tst_brk TCONF "cannot read IMA policy (CONFIG_IMA_READ_POLICY=y required)" 73 fi 74} 75 76check_ima_policy_content() 77{ 78 local pattern="$1" 79 local grep_params="${2--q}" 80 81 check_policy_readable || return 1 82 grep $grep_params "$pattern" $IMA_POLICY 83} 84 85require_ima_policy_content() 86{ 87 local pattern="$1" 88 local grep_params="${2--q}" 89 90 require_policy_readable 91 if ! grep $grep_params "$pattern" $IMA_POLICY; then 92 tst_brk TCONF "IMA policy does not specify '$pattern'" 93 fi 94} 95 96check_ima_policy_cmdline() 97{ 98 local policy="$1" 99 local i 100 101 grep -q "ima_$policy" /proc/cmdline && return 102 for i in $(cat /proc/cmdline); do 103 if echo "$i" | grep -q '^ima_policy='; then 104 echo "$i" | grep -q -e "|[ ]*$policy" -e "$policy[ ]*|" -e "=$policy" && return 0 105 fi 106 done 107 return 1 108} 109 110require_ima_policy_cmdline() 111{ 112 local policy="$1" 113 114 check_ima_policy_cmdline $policy || \ 115 tst_brk TCONF "IMA measurement tests require builtin IMA $policy policy (e.g. ima_policy=$policy kernel parameter)" 116} 117 118mount_helper() 119{ 120 local type="$1" 121 local default_dir="$2" 122 local dir 123 124 dir="$(grep ^$type /proc/mounts | cut -d ' ' -f2 | head -1)" 125 [ -n "$dir" ] && { echo "$dir"; return; } 126 127 if ! mkdir -p $default_dir; then 128 tst_brk TBROK "failed to create $default_dir" 129 fi 130 if ! mount -t $type $type $default_dir; then 131 tst_brk TBROK "failed to mount $type" 132 fi 133 UMOUNT="$default_dir $UMOUNT" 134 echo $default_dir 135} 136 137mount_loop_device() 138{ 139 local ret 140 141 tst_mkfs 142 tst_mount 143 cd $TST_MNTPOINT 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_NEEDS_DEVICE" = 1 ]; then 179 tst_res TINFO "\$TMPDIR is on tmpfs => run on loop device" 180 mount_loop_device 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 if [ "$TST_NEEDS_DEVICE" = 1 ]; then 197 cd $TST_TMPDIR 198 tst_umount 199 fi 200} 201 202set_digest_index() 203{ 204 DIGEST_INDEX= 205 206 local template="$(tail -1 $ASCII_MEASUREMENTS | cut -d' ' -f 3)" 207 local i word 208 209 # parse digest index 210 # https://www.kernel.org/doc/html/latest/security/IMA-templates.html#use 211 case "$template" in 212 ima|ima-ng|ima-sig) DIGEST_INDEX=4 ;; 213 *) 214 # using ima_template_fmt kernel parameter 215 local IFS="|" 216 i=4 217 for word in $template; do 218 if [ "$word" = 'd' -o "$word" = 'd-ng' ]; then 219 DIGEST_INDEX=$i 220 break 221 fi 222 i=$((i+1)) 223 done 224 esac 225 226 [ -z "$DIGEST_INDEX" ] && tst_brk TCONF \ 227 "Cannot find digest index (template: '$template')" 228} 229 230get_algorithm_digest() 231{ 232 local line="$1" 233 local delimiter=':' 234 local algorithm digest 235 236 if [ -z "$line" ]; then 237 echo "measurement record not found" 238 return 1 239 fi 240 241 [ -z "$DIGEST_INDEX" ] && set_digest_index 242 digest=$(echo "$line" | cut -d' ' -f $DIGEST_INDEX) 243 if [ -z "$digest" ]; then 244 echo "digest not found (index: $DIGEST_INDEX, line: '$line')" 245 return 1 246 fi 247 248 if [ "${digest#*$delimiter}" != "$digest" ]; then 249 algorithm=$(echo "$digest" | cut -d $delimiter -f 1) 250 digest=$(echo "$digest" | cut -d $delimiter -f 2) 251 else 252 case "${#digest}" in 253 32) algorithm="md5" ;; 254 40) algorithm="sha1" ;; 255 *) 256 echo "algorithm must be either md5 or sha1 (digest: '$digest')" 257 return 1 ;; 258 esac 259 fi 260 if [ -z "$algorithm" ]; then 261 echo "algorithm not found" 262 return 1 263 fi 264 if [ -z "$digest" ]; then 265 echo "digest not found" 266 return 1 267 fi 268 269 echo "$algorithm|$digest" 270} 271 272# check_evmctl REQUIRED_TPM_VERSION 273# return: 0: evmctl is new enough, 1: version older than required (or version < v0.9) 274check_evmctl() 275{ 276 local required="$1" 277 278 local r1="$(echo $required | cut -d. -f1)" 279 local r2="$(echo $required | cut -d. -f2)" 280 local r3="$(echo $required | cut -d. -f3)" 281 [ -z "$r3" ] && r3=0 282 283 tst_is_int "$r1" || tst_brk TBROK "required major version not int ($v1)" 284 tst_is_int "$r2" || tst_brk TBROK "required minor version not int ($v2)" 285 tst_is_int "$r3" || tst_brk TBROK "required patch version not int ($v3)" 286 287 tst_check_cmds evmctl || return 1 288 289 local v="$(evmctl --version | cut -d' ' -f2)" 290 [ -z "$v" ] && return 1 291 tst_res TINFO "evmctl version: $v" 292 293 local v1="$(echo $v | cut -d. -f1)" 294 local v2="$(echo $v | cut -d. -f2)" 295 local v3="$(echo $v | cut -d. -f3)" 296 [ -z "$v3" ] && v3=0 297 298 if [ $v1 -lt $r1 ] || [ $v1 -eq $r1 -a $v2 -lt $r2 ] || \ 299 [ $v1 -eq $r1 -a $v2 -eq $r2 -a $v3 -lt $r3 ]; then 300 return 1 301 fi 302 return 0 303} 304 305# require_evmctl REQUIRED_TPM_VERSION 306require_evmctl() 307{ 308 local required="$1" 309 310 if ! check_evmctl $required; then 311 tst_brk TCONF "evmctl >= $required required" 312 fi 313} 314 315# loop device is needed to use only for tmpfs 316TMPDIR="${TMPDIR:-/tmp}" 317if [ "$(df -T $TMPDIR | tail -1 | awk '{print $2}')" != "tmpfs" -a -n "$TST_NEEDS_DEVICE" ]; then 318 unset TST_NEEDS_DEVICE 319fi 320