From: Mimi Zohar <zohar@linux.ibm.com>
To: Vitaly Chikunov <vt@altlinux.org>,
Mimi Zohar <zohar@linux.vnet.ibm.com>,
Dmitry Kasatkin <dmitry.kasatkin@gmail.com>,
linux-integrity@vger.kernel.org
Subject: Re: [PATCH v8 1/2] ima-evm-utils: Add some tests for evmctl
Date: Tue, 31 Mar 2020 10:25:24 -0400 [thread overview]
Message-ID: <1585664724.5188.572.camel@linux.ibm.com> (raw)
In-Reply-To: <20200327042515.22315-2-vt@altlinux.org>
Hi Vitaly,
On Fri, 2020-03-27 at 07:25 +0300, Vitaly Chikunov wrote:
> Run `make check' to execute the tests.
> This commit only adds ima_hash test.
> Signed-off-by: Vitaly Chikunov <vt@altlinux.org>
Thank you for breaking up the patch based on tests. "ima_hash.test"
may be executed by running "make check", but obviously also by
invoking it directly.
A couple of comments/questions inline below.
> diff --git a/tests/functions.sh b/tests/functions.sh
> new file mode 100755
> index 0000000..16c8d89
> --- /dev/null
> +++ b/tests/functions.sh
> @@ -0,0 +1,272 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# ima-evm-utils tests bash functions
> +#
> +# Copyright (C) 2019 Vitaly Chikunov <vt@altlinux.org>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2, or (at your option)
> +# any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +
> +# Tests accounting
> +declare -i testspass=0 testsfail=0 testsskip=0
> +
> +# Exit codes (compatible with automake)
> +declare -r OK=0
> +declare -r FAIL=1
> +declare -r HARDFAIL=99 # hard failure no matter testing mode
> +declare -r SKIP=77
> +
> +# You can set env VERBOSE=1 to see more output from evmctl
> +V=vvvv
> +V=${V:0:$VERBOSE}
> +V=${V:+-$V}
> +
> +# Exit if env FAILEARLY is defined.
> +# Used in expect_{pass,fail}.
> +exit_early() {
> + if [ $FAILEARLY ]; then
Throughout variables are not double quoted, though the tests
themselves turn off globbing (set -f). shellcheck doesn't detect that
globbing has been turned off. It complains about each variable usage
that is not double quoted.
> + exit $1
> + fi
> +}
> +
> +# Require particular executables to be present
> +_require() {
> + ret=
> + for i; do
> + if ! type $i; then
> + echo "$i is required for test"
> + ret=1
> + fi
> + done
> + [ $ret ] && exit $HARDFAIL
> +}
> +
> +# Only allow color output on tty
> +if [ -t 1 ]; then
> + RED=$'\e[1;31m'
> + GREEN=$'\e[1;32m'
> + YELLOW=$'\e[1;33m'
> + BLUE=$'\e[1;34m'
> + CYAN=$'\e[1;36m'
> + NORM=$'\e[m'
> +fi
> +
> +# Test mode determined by TFAIL variable:
> +# undefined: to success testing
> +# defined: failure testing
> +TFAIL=
> +TMODE=+ # mode character to prepend running command in log
> +declare -i TNESTED=0 # just for sanity checking
> +
> +# Run positive test (one that should pass) and account its result
> +expect_pass() {
> + local ret
> +
> + if [ $TNESTED -gt 0 ]; then
> + echo $RED"expect_pass should not be run nested"$NORM
> + testsfail+=1
> + exit $HARDFAIL
> + fi
> + TFAIL=
> + TMODE=+
> + TNESTED+=1
> + [[ "$VERBOSE" -gt 1 ]] && echo "____ START positive test: $@"
Unless VERBOSE is set as an environment variable, it isn't defined.
This isn't an issue when using [[ ... ]], but should it be
initialized: VERBOSE="${VERBOSE:-0}"?
> + "$@"
> + ret=$?
> + [[ "$VERBOSE" -gt 1 ]] && echo "^^^^ STOP ($ret) positive test: $@"
> + TNESTED+=-1
> + case $ret in
> + 0) testspass+=1 ;;
> + 77) testsskip+=1 ;;
> + 99) testsfail+=1; exit_early 1 ;;
> + *) testsfail+=1; exit_early 2 ;;
> + esac
> + return $ret
> +}
> +
> +# Eval negative test (one that should fail) and account its result
> +expect_fail() {
> + local ret
> +
> + if [ $TNESTED -gt 0 ]; then
> + echo $RED"expect_fail should not be run nested"$NORM
> + testsfail+=1
> + exit $HARDFAIL
> + fi
> +
> + TFAIL=yes
> + TMODE=-
> + TNESTED+=1
> + [[ "$VERBOSE" -gt 1 ]] && echo "____ START negative test: $@"
> + "$@"
> + ret=$?
> + [[ "$VERBOSE" -gt 1 ]] && echo "^^^^ STOP ($ret) negative test: $@"
> + TNESTED+=-1
> + case $ret in
> + 0) testsfail+=1; exit_early 3 ;;
> + 77) testsskip+=1 ;;
> + 99) testsfail+=1; exit_early 4 ;;
> + *) testspass+=1 ;;
> + esac
> + # Restore defaults (as in positive tests)
> + # for tests to run without wrappers
> + TFAIL=
> + TMODE=+
> + return $ret
> +}
> +
> +# return true if current test is positive
> +_is_expect_pass() {
> + [ ! $TFAIL ]
> +}
> +
> +# return true if current test is negative
> +_is_expect_fail() {
> + [ $TFAIL ]
> +}
> +
> +# Show blank line and color following text to red
> +# if it's real error (ie we are in expect_pass mode).
> +red_if_failure() {
> + if _is_expect_pass; then
> + echo $@ $RED
> + COLOR_RESTORE=1
> + fi
> +}
> +
> +# For hard errors
> +red_always() {
> + echo $@ $RED
A few functions - "red_always", "red_if_failure", "color_restore" -
use "$@", but none of the function callers pass any parameters. Is
there a reason for the "$@" or just something left over from
debugging?
> + COLOR_RESTORE=1
> +}
> +
> +color_restore() {
> + [ $COLOR_RESTORE ] && echo $@ $NORM
> + COLOR_RESTORE=
> +}
> +
> +ADD_DEL=
> +ADD_TEXT_FOR=
> +# _evmctl_run should be run as `_evmctl_run ... || return'
> +_evmctl_run() {
> + local op=$1 out=$1-$$.out
> + local text_for=${FOR:+for $ADD_TEXT_FOR}
> + # Additional parameters:
> + # ADD_DEL: additional files to rm on failure
> + # ADD_TEXT_FOR: append to text as 'for $ADD_TEXT_FOR'
> +
> + cmd="evmctl $V $EVMCTL_ENGINE $@"
> + echo $YELLOW$TMODE $cmd$NORM
> + $cmd >$out 2>&1
> + ret=$?
> +
> + # Shell special and signal exit codes (except 255)
> + if [ $ret -ge 126 -a $ret -lt 255 ]; then
> + red_always
> + echo "evmctl $op failed hard with ($ret) $text_for"
> + sed 's/^/ /' $out
> + color_restore
> + rm $out $ADD_DEL
> + ADD_DEL=
> + ADD_TEXT_FOR=
> + return $HARDFAIL
> + elif [ $ret -gt 0 ]; then
> + red_if_failure
> + echo "evmctl $op failed" ${TFAIL:+properly} "with ($ret) $text_for"
> + # Show evmctl output only in verbose mode or if real failure.
> + if _is_expect_pass || [ "$VERBOSE" ]; then
> + sed 's/^/ /' $out
> + fi
> + color_restore
> + rm $out $ADD_DEL
> + ADD_DEL=
> + ADD_TEXT_FOR=
> + return $FAIL
> + elif _is_expect_fail; then
> + red_always
> + echo "evmctl $op wrongly succeeded $text_for"
> + sed 's/^/ /' $out
> + color_restore
> + else
> + [ "$VERBOSE" ] && sed 's/^/ /' $out
> + fi
> + rm $out
> + ADD_DEL=
> + ADD_TEXT_FOR=
> + return $OK
> +}
> +
> +# Extract xattr $attr from $file into $out file skipping $pref'ix
> +_extract_xattr() {
> + local file=$1 attr=$2 out=$3 pref=$4
> +
> + getfattr -n $attr -e hex $file \
> + | grep "^$attr=" \
> + | sed "s/^$attr=$pref//" \
> + | xxd -r -p > $out
> +}
> +
> +# Test if xattr $attr in $file matches $pref'ix
> +# Show error and fail otherwise.
> +_test_xattr() {
> + local file=$1 attr=$2 pref=$3
> + local text_for=${ADD_TEXT_FOR:+ for $ADD_TEXT_FOR}
> +
> + if ! getfattr -n $attr -e hex $file | egrep -qx "$attr=$pref"; then
> + red_if_failure
> + echo "Did not find expected hash$text_for:"
> + echo " $attr=$pref"
> + echo ""
> + echo "Actual output below:"
> + getfattr -n $attr -e hex $file | sed 's/^/ /'
> + color_restore
> + rm $file
> + ADD_TEXT_FOR=
> + return $FAIL
> + fi
> + ADD_TEXT_FOR=
> +}
> +
> +# Try to enable gost-engine if needed.
> +_enable_gost_engine() {
> + # Do not enable if it's already working (enabled by user)
> + if ! openssl md_gost12_256 /dev/null >/dev/null 2>&1 \
Interesting /dev/null usage here as a filename.
> + && openssl engine gost >/dev/null 2>&1; then
> + EVMCTL_ENGINE="--engine gost"
> + OPENSSL_ENGINE="-engine gost"
> + fi
> +}
> +
> +# Show test stats and exit into automake test system
> +# with proper exit code (same as ours).
> +_report_exit() {
> + if [ $testsfail -gt 0 ]; then
> + echo "================================="
> + echo " Run with FAILEARLY=1 $0 $@"
> + echo " To stop after first failure"
> + echo "================================="
> + fi
> + [ $testspass -gt 0 ] && echo -n $GREEN || echo -n $NORM
> + echo -n "PASS: $testspass"
> + [ $testsskip -gt 0 ] && echo -n $YELLOW || echo -n $NORM
> + echo -n " SKIP: $testsskip"
> + [ $testsfail -gt 0 ] && echo -n $RED || echo -n $NORM
> + echo " FAIL: $testsfail"
> + echo $NORM
> + if [ $testsfail -gt 0 ]; then
> + exit $FAIL
> + elif [ $testspass -gt 0 ]; then
> + exit $OK
> + else
> + exit $SKIP
> + fi
> +}
> +
> diff --git a/tests/ima_hash.test b/tests/ima_hash.test
> new file mode 100755
> index 0000000..30aec19
> --- /dev/null
> +++ b/tests/ima_hash.test
> @@ -0,0 +1,80 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# evmctl ima_hash tests
> +#
> +# Copyright (C) 2019 Vitaly Chikunov <vt@altlinux.org>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2, or (at your option)
> +# any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +
> +cd $(dirname $0)
> +PATH=../src:$PATH
> +source ./functions.sh
> +_require evmctl openssl getfattr
> +
> +trap _report_exit EXIT
> +set -f # disable globbing
> +
> +check() {
> + local alg=$1 pref=$2 chash=$3 hash
> + local file=$alg-hash.txt
> +
> + rm -f $file
> + touch $file
> + # Generate hash with openssl, if it's failed skip test,
> + # unless it's negative test, then pass to evmctl
> + cmd="openssl dgst $OPENSSL_ENGINE -$alg $file"
> + echo - $cmd
> + hash=$(set -o pipefail; $cmd 2>/dev/null | cut -d' ' -f2)
> + if [ $? -ne 0 ] && _is_expect_pass; then
> + echo $CYAN"$alg test is skipped"$NORM
> + rm $file
> + return $SKIP
> + fi
> + if [ "$chash" ] && [ "$chash" != "$hash" ]; then
> + red_always
Only when "ima_hash.test" is invoked directly, the output is colored
red. Really confusing.
> + echo "Invalid hash for $alg from openssl"
> + echo "Expected: $chash"
> + echo "Returned: $hash"
> + color_restore
> + rm $file
> + return $HARDFAIL
> + fi
> +
> + ADD_TEXT_FOR=$alg ADD_DEL=$file \
> + _evmctl_run ima_hash --hashalgo $alg --xattr-user $file || return
> + ADD_TEXT_FOR=$alg \
> + _test_xattr $file user.ima $pref$hash || return
> + rm $file
> + return $OK
> +}
> +
> +# check args: algo hdr-prefix canonic-hash
> +expect_pass check md4 0x01 31d6cfe0d16ae931b73c59d7e0c089c0
> +expect_pass check md5 0x01 d41d8cd98f00b204e9800998ecf8427e
> +expect_pass check sha1 0x01 da39a3ee5e6b4b0d3255bfef95601890afd80709
> +expect_fail check SHA1 0x01 # uppercase
> +expect_fail check sha512-224 0x01 # valid for pkcs1
> +expect_fail check sha512-256 0x01 # valid for pkcs1
> +expect_fail check unknown 0x01 # nonexistent
> +expect_pass check sha224 0x0407 d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f
> +expect_pass check sha256 0x0404 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
> +expect_pass check sha384 0x0405 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
> +expect_pass check sha512 0x0406 cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
> +expect_pass check rmd160 0x0403 9c1185a5c5e9fc54612808977ee8f548b2258d31
> +expect_fail check sm3 0x01
> +expect_fail check sm3-256 0x01
> +_enable_gost_engine
> +expect_pass check md_gost12_256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
> +expect_pass check streebog256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
> +expect_pass check md_gost12_512 0x0413 8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a
> +expect_pass check streebog512 0x0413 8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a
> +
Nice! The code is very concisely written.
Reviewing this patch would be a lot easier, if it was broken up into
smaller pieces. For example, and this is only an example, the initial
patch could define the base ima_hash.test, a subsequent patch could
add coloring for the base ima_hash.test, another patch could introduce
"make check" and add its coloring. There's all sorts of ways to break
up this patch to simplify review.
Mimi
next prev parent reply other threads:[~2020-03-31 14:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-27 4:25 [PATCH v8 0/2] ima-evm-utils: Add some tests for evmctl Vitaly Chikunov
2020-03-27 4:25 ` [PATCH v8 1/2] " Vitaly Chikunov
[not found] ` <f9b36972-df5d-db9a-d840-52e9ff76d271@linux.microsoft.com>
2020-03-30 16:29 ` Lakshmi Ramasubramanian
2020-03-30 17:11 ` Vitaly Chikunov
2020-03-31 14:25 ` Mimi Zohar [this message]
2020-03-31 15:14 ` Vitaly Chikunov
2020-03-31 16:04 ` Mimi Zohar
2020-03-27 4:25 ` [PATCH v8 2/2] ima-evm-utils: Add sign/verify " Vitaly Chikunov
[not found] ` <98cfccc0-2191-6072-aebe-296e6e150e0c@linux.microsoft.com>
2020-03-30 16:29 ` Lakshmi Ramasubramanian
2020-03-30 17:16 ` Vitaly Chikunov
2020-04-01 18:00 ` Mimi Zohar
2020-04-02 7:19 ` Vitaly Chikunov
2020-04-02 11:14 ` Mimi Zohar
[not found] ` <d39b433e-4504-d0a4-116f-dd33ca238f7f@linux.microsoft.com>
2020-03-30 16:28 ` [PATCH v8 0/2] ima-evm-utils: Add some " Lakshmi Ramasubramanian
2020-03-30 17:47 ` James Bottomley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1585664724.5188.572.camel@linux.ibm.com \
--to=zohar@linux.ibm.com \
--cc=dmitry.kasatkin@gmail.com \
--cc=linux-integrity@vger.kernel.org \
--cc=vt@altlinux.org \
--cc=zohar@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).