ima_measurements.sh 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. #
  7. # Verify that measurements are added to the measurement list based on policy.
  8. TST_NEEDS_CMDS="awk cut"
  9. TST_SETUP="setup"
  10. TST_CNT=3
  11. TST_NEEDS_DEVICE=1
  12. . ima_setup.sh
  13. setup()
  14. {
  15. require_ima_policy_cmdline "tcb"
  16. TEST_FILE="$PWD/test.txt"
  17. POLICY="$IMA_DIR/policy"
  18. [ -f "$POLICY" ] || tst_res TINFO "not using default policy"
  19. DIGEST_INDEX=
  20. local template="$(tail -1 $ASCII_MEASUREMENTS | cut -d' ' -f 3)"
  21. local i
  22. # parse digest index
  23. # https://www.kernel.org/doc/html/latest/security/IMA-templates.html#use
  24. case "$template" in
  25. ima|ima-ng|ima-sig|ima-buf) DIGEST_INDEX=4 ;;
  26. *)
  27. # using ima_template_fmt kernel parameter
  28. local IFS="|"
  29. i=4
  30. for word in $template; do
  31. if [ "$word" = 'd' -o "$word" = 'd-ng' ]; then
  32. DIGEST_INDEX=$i
  33. break
  34. fi
  35. i=$((i+1))
  36. done
  37. esac
  38. [ -z "$DIGEST_INDEX" ] && tst_brk TCONF \
  39. "Cannot find digest index (template: '$template')"
  40. }
  41. ima_check()
  42. {
  43. local delimiter=':'
  44. local algorithm digest expected_digest line
  45. # need to read file to get updated $ASCII_MEASUREMENTS
  46. cat $TEST_FILE > /dev/null
  47. line="$(grep $TEST_FILE $ASCII_MEASUREMENTS | tail -1)"
  48. if [ -z "$line" ]; then
  49. tst_res TFAIL "cannot find measurement record for '$TEST_FILE'"
  50. return
  51. fi
  52. tst_res TINFO "measurement record: '$line'"
  53. digest=$(echo "$line" | cut -d' ' -f $DIGEST_INDEX)
  54. if [ -z "$digest" ]; then
  55. tst_res TFAIL "cannot find digest (index: $DIGEST_INDEX)"
  56. return
  57. fi
  58. if [ "${digest#*$delimiter}" != "$digest" ]; then
  59. algorithm=$(echo "$digest" | cut -d $delimiter -f 1)
  60. digest=$(echo "$digest" | cut -d $delimiter -f 2)
  61. else
  62. case "${#digest}" in
  63. 32) algorithm="md5" ;;
  64. 40) algorithm="sha1" ;;
  65. *)
  66. tst_res TFAIL "algorithm must be either md5 or sha1 (digest: '$digest')"
  67. return ;;
  68. esac
  69. fi
  70. if [ -z "$algorithm" ]; then
  71. tst_res TFAIL "cannot find algorithm"
  72. return
  73. fi
  74. if [ -z "$digest" ]; then
  75. tst_res TFAIL "cannot find digest"
  76. return
  77. fi
  78. tst_res TINFO "computing digest for $algorithm algorithm"
  79. expected_digest="$(compute_digest $algorithm $TEST_FILE)" || \
  80. tst_brk TCONF "cannot compute digest for $algorithm algorithm"
  81. if [ "$digest" = "$expected_digest" ]; then
  82. tst_res TPASS "correct digest found"
  83. else
  84. tst_res TFAIL "digest not found"
  85. fi
  86. }
  87. check_iversion_support()
  88. {
  89. local device mount fs
  90. tst_kvcmp -ge "4.16" && return 0
  91. device="$(df . | sed -e 1d | cut -f1 -d ' ')"
  92. mount="$(grep $device /proc/mounts | head -1)"
  93. fs="$(echo $mount | awk '{print $3'})"
  94. case "$fs" in
  95. ext[2-4])
  96. if ! echo "$mount" | grep -q -w "i_version"; then
  97. tst_res TCONF "device '$device' is not mounted with iversion, please mount it with 'mount $device -o remount,iversion'"
  98. return 1
  99. fi
  100. ;;
  101. xfs)
  102. if dmesg | grep -q "XFS.*Mounting V[1-4] Filesystem"; then
  103. tst_res TCONF "XFS Filesystem >= V5 required for iversion support"
  104. return 1
  105. fi
  106. ;;
  107. '')
  108. tst_res TWARN "could not find mount info for device '$device'"
  109. ;;
  110. esac
  111. return 0
  112. }
  113. test1()
  114. {
  115. tst_res TINFO "verify adding record to the IMA measurement list"
  116. ROD echo "$(date) this is a test file" \> $TEST_FILE
  117. ima_check
  118. }
  119. test2()
  120. {
  121. tst_res TINFO "verify updating record in the IMA measurement list"
  122. check_iversion_support || return
  123. ROD echo "$(date) modified file" \> $TEST_FILE
  124. ima_check
  125. }
  126. test3()
  127. {
  128. local user="nobody"
  129. local dir="$PWD/user"
  130. local file="$dir/test.txt"
  131. # Default policy does not measure user files
  132. tst_res TINFO "verify not measuring user files"
  133. tst_check_cmds sudo || return
  134. if ! id $user >/dev/null 2>/dev/null; then
  135. tst_res TCONF "missing system user $user (wrong installation)"
  136. return
  137. fi
  138. mkdir -m 0700 $dir
  139. chown $user $dir
  140. cd $dir
  141. # need to read file to get updated $ASCII_MEASUREMENTS
  142. sudo -n -u $user sh -c "echo $(date) user file > $file; cat $file > /dev/null"
  143. cd ..
  144. EXPECT_FAIL "grep $file $ASCII_MEASUREMENTS"
  145. }
  146. tst_run