diff mbox series

[v3] IMA: Add test for kexec cmdline measurement

Message ID 20200722184739.19460-1-t-josne@linux.microsoft.com (mailing list archive)
State New, archived
Headers show
Series [v3] IMA: Add test for kexec cmdline measurement | expand

Commit Message

Lachlan Sneff July 22, 2020, 6:47 p.m. UTC
IMA policy can be set to measure the command line passed in the kexec system call.
There needs to be a test to validate this kexec command line measurement.

Add a testcase that verifies that the IMA subsystem has correctly
measured the cmdline specified during a kexec.

Note that this test does not actually reboot.

Signed-off-by: Lachlan Sneff <t-josne@linux.microsoft.com>
---
 runtest/ima                                   |   1 +
 .../kernel/security/integrity/ima/README.md   |  11 ++
 .../security/integrity/ima/tests/ima_kexec.sh | 121 ++++++++++++++++++
 3 files changed, 133 insertions(+)
 create mode 100644 testcases/kernel/security/integrity/ima/tests/ima_kexec.sh

Comments

Petr Vorel July 23, 2020, 11:46 a.m. UTC | #1
Hi,

...
> +++ b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
> @@ -0,0 +1,121 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2020 Microsoft Corporation
> +# Author: Lachlan Sneff <t-josne@linux.microsoft.com>
> +#
> +# Verify that kexec cmdline is measured correctly.
> +
> +TST_NEEDS_CMDS="kexec sed xargs printf grep tr"
> +TST_CNT=1
> +TST_NEEDS_DEVICE=1
> +
> +. ima_setup.sh
> +
> +# Since the test is executed inside some sort of
> +# separate shell, *most* environment variables are
> +# not accessible, so there's no way to set it from
> +# the outside.
Do you mean that using this will not work?
IMA_KEXEC_IMAGE="${IMA_KEXEC_IMAGE:-/boot/vmlinuz-$(uname -r)}"
I don't understand that as I'm able to set variables even I run some tests in
dracut.

Also writing same docs doc on 2 places is not good. High level info should go to
README.md, implementation details to shell script.

Please hold on with posting new version. I have several fixes, thus I'd like to
send it after we sort this (trying to save you time).

Kind regards,
Petr
Lachlan Sneff July 23, 2020, 8:52 p.m. UTC | #2
Hi Petr,
Thank you for reviewing

On 7/23/20 7:46 AM, Petr Vorel wrote:
> Hi,
>
> ...
>> +++ b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
>> @@ -0,0 +1,121 @@
>> +#!/bin/sh
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +# Copyright (c) 2020 Microsoft Corporation
>> +# Author: Lachlan Sneff <t-josne@linux.microsoft.com>
>> +#
>> +# Verify that kexec cmdline is measured correctly.
>> +
>> +TST_NEEDS_CMDS="kexec sed xargs printf grep tr"
>> +TST_CNT=1
>> +TST_NEEDS_DEVICE=1
>> +
>> +. ima_setup.sh
>> +
>> +# Since the test is executed inside some sort of
>> +# separate shell, *most* environment variables are
>> +# not accessible, so there's no way to set it from
>> +# the outside.
> Do you mean that using this will not work?
> IMA_KEXEC_IMAGE="${IMA_KEXEC_IMAGE:-/boot/vmlinuz-$(uname -r)}"
> I don't understand that as I'm able to set variables even I run some tests in
> dracut.
I tried doing this in the past, and couldn't get it to work, but I just 
tried it again
and was able to get it working. Essentially, what I tried before was
`SOME_VAR="..." sudo runltp ...`, which doesn't work, but `sudo 
SOME_VAR="..." runltp` does pass the variable
to the test. So, that should be added to this patch.
>
> Also writing same docs doc on 2 places is not good. High level info should go to
> README.md, implementation details to shell script.
This is a good point. I'll reorganize the documentation of this patch.
> Please hold on with posting new version. I have several fixes, thus I'd like to
> send it after we sort this (trying to save you time).
Okay :)
> Kind regards,
> Petr
Thanks,
Lachlan
Petr Vorel July 24, 2020, 6:43 a.m. UTC | #3
> Hi Petr,
> Thank you for reviewing
Thanks for your time as well :).

> On 7/23/20 7:46 AM, Petr Vorel wrote:
> > Hi,

> > ...
> > > +++ b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
> > > @@ -0,0 +1,121 @@
> > > +#!/bin/sh
> > > +# SPDX-License-Identifier: GPL-2.0-or-later
> > > +# Copyright (c) 2020 Microsoft Corporation
> > > +# Author: Lachlan Sneff <t-josne@linux.microsoft.com>
> > > +#
> > > +# Verify that kexec cmdline is measured correctly.
> > > +
> > > +TST_NEEDS_CMDS="kexec sed xargs printf grep tr"
> > > +TST_CNT=1
> > > +TST_NEEDS_DEVICE=1
> > > +
> > > +. ima_setup.sh
> > > +
> > > +# Since the test is executed inside some sort of
> > > +# separate shell, *most* environment variables are
> > > +# not accessible, so there's no way to set it from
> > > +# the outside.
> > Do you mean that using this will not work?
> > IMA_KEXEC_IMAGE="${IMA_KEXEC_IMAGE:-/boot/vmlinuz-$(uname -r)}"
> > I don't understand that as I'm able to set variables even I run some tests in
> > dracut.
> I tried doing this in the past, and couldn't get it to work, but I just
> tried it again
> and was able to get it working. Essentially, what I tried before was
> `SOME_VAR="..." sudo runltp ...`, which doesn't work, but `sudo
> SOME_VAR="..." runltp` does pass the variable
> to the test. So, that should be added to this patch.
OK, so no any dracut / initramfs involved :).
Passing variables really works as expected, you need to export it first:
$ sudo su
# export IMA_KEXEC_IMAGE=/tmp/foo
# PATH="/opt/ltp/testcases/bin:$PATH" runltp ...

or just run the script directly:
$ sudo su
# IMA_KEXEC_IMAGE=/tmp/foo PATH="/opt/ltp/testcases/bin:$PATH" ima_kexec.sh

> > Also writing same docs doc on 2 places is not good. High level info should go to
> > README.md, implementation details to shell script.
> This is a good point. I'll reorganize the documentation of this patch.
> > Please hold on with posting new version. I have several fixes, thus I'd like to
> > send it after we sort this (trying to save you time).
> Okay :)
> > Kind regards,
> > Petr
> Thanks,
> Lachlan

Kind regards,
Petr
diff mbox series

Patch

diff --git a/runtest/ima b/runtest/ima
index 309d47420..5f4b4a7a1 100644
--- a/runtest/ima
+++ b/runtest/ima
@@ -4,4 +4,5 @@  ima_policy ima_policy.sh
 ima_tpm ima_tpm.sh
 ima_violations ima_violations.sh
 ima_keys ima_keys.sh
+ima_kexec ima_kexec.sh
 evm_overlay evm_overlay.sh
diff --git a/testcases/kernel/security/integrity/ima/README.md b/testcases/kernel/security/integrity/ima/README.md
index db8819a99..926eb8478 100644
--- a/testcases/kernel/security/integrity/ima/README.md
+++ b/testcases/kernel/security/integrity/ima/README.md
@@ -30,6 +30,17 @@  measure func=KEY_CHECK keyrings=key_import_test template=ima-buf
 
 The test also requires loaded policy with `func=KEY_CHECK`, see example in `keycheck.policy`.
 
+### IMA kexec test
+
+This test requires that the ima policy contains:
+```
+measure func=KEXEC_CMDLINE
+```
+
+Even though the test does not actually reboot, it does require a valid,
+signed kernel image. By default, the test will look in `/boot/vmlinuz-$(uname r)`,
+but if no image is accessible there, a valid image be must be placed at `/tmp/Image`.
+
 ## EVM tests
 
 `evm_overlay.sh` requires a builtin IMA appraise tcb policy (e.g. `ima_policy=appraise_tcb`
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
new file mode 100644
index 000000000..7e3ecaec8
--- /dev/null
+++ b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
@@ -0,0 +1,121 @@ 
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2020 Microsoft Corporation
+# Author: Lachlan Sneff <t-josne@linux.microsoft.com>
+#
+# Verify that kexec cmdline is measured correctly.
+
+TST_NEEDS_CMDS="kexec sed xargs printf grep tr"
+TST_CNT=1
+TST_NEEDS_DEVICE=1
+
+. ima_setup.sh
+
+# Since the test is executed inside some sort of
+# separate shell, *most* environment variables are
+# not accessible, so there's no way to set it from
+# the outside.
+#
+# `/boot/vmlinuz-$(uname-r)` is where the image is
+# located on many systems, but not all. Therefore,
+# if the image is not located there, require the
+# user to copy it to `/tmp/Image`.
+#
+# Ideally, this test shouldn't even require an image,
+# since it doesn't actually reboot, but the IMA cmdline
+# measurement occurs after the image is parsed and
+# verified, so we must pass a valid kernel image. There
+# is a possiblity of putting together a "faux" kernel
+# image that has the right headers and appears to be
+# signed correctly, but doesn't actually contain any
+# code, but, after investigating that possiblity, it
+# appears to be quite difficult (and would require a
+# new faux kernel for each arch).
+IMAGE="/boot/vmlinuz-$(uname -r)"
+if [ ! -f $IMAGE ]; then
+    IMAGE="/tmp/Image"
+fi
+
+measure() {
+    local found temp_file="file.txt" temp_file2="file2.txt" algorithm \
+        digest expected_digest
+
+    echo -n "$1" > $temp_file
+    grep "kexec-cmdline" $ASCII_MEASUREMENTS > $temp_file2
+
+    while read found
+    do
+        algorithm=$(echo "$found" | cut -d' ' -f4 | cut -d':' -f1)
+        digest=$(echo "$found" | cut -d' ' -f4 | cut -d':' -f2)
+
+        expected_digest=$(compute_digest $algorithm $temp_file)
+
+        if [ "$digest" = "$expected_digest" ]; then
+            return 0
+        fi
+    done < $temp_file2
+
+    return 1
+}
+
+# Test that the kexec cmdline is measured correctly.
+# NOTE: This does *not* actually reboot.
+test1() {
+    # Strip the `BOOT_IMAGE=...` part from the cmdline.
+    local cmdline="$(sed 's/BOOT_IMAGE=[^ ]* //' /proc/cmdline)"
+
+    if ! kexec -sl $IMAGE --reuse-cmdline; then
+        tst_res TCONF "kexec failed: $?"
+
+        local sb_status="$(bootctl status 2>/dev/null | grep 'Secure Boot' \
+            | tr -d ' ' | sed 's/SecureBoot:*//')"
+
+        if [ "$sb_status" = "enabled" ]; then
+            tst_res TINFO "secure boot is enabled, the specified kernel image may not be signed"
+        fi
+
+        return
+    fi
+
+    kexec -su
+
+    if ! measure "$cmdline"; then
+        tst_res TFAIL "unable to find a correct entry in the IMA log"
+
+        if [ ! -r $IMA_POLICY ]; then
+            tst_brk TCONF "cannot read IMA policy (CONFIG_IMA_READ_POLICY=y required) to give contextual information"
+        fi
+
+        if ! grep "measure func=KEXEC_CMDLINE" $IMA_POLICY >/dev/null; then
+            tst_brk TCONF "The IMA policy does not specify 'measure func=KEXEC_CMDLINE', see IMA test README"
+        fi
+
+        return
+    fi
+
+    cmdline="foo"
+    if ! kexec -sl $IMAGE --append=$cmdline; then
+        tst_brk TCONF "kexec failed: $?"
+    fi
+
+    kexec -su
+
+    if ! measure "$cmdline"; then
+        tst_brk TFAIL "unable to find a correct entry in the IMA log"
+    fi
+
+    cmdline="bar"
+    if ! kexec -sl $IMAGE --command-line=$cmdline; then
+        tst_brk TCONF "kexec failed: $?"
+    fi
+
+    kexec -su
+
+    if ! measure "$cmdline"; then
+        tst_brk TFAIL "unable to find a correct entry in the IMA log"
+    fi
+
+    tst_res TPASS "kexec cmdline was measured correctly"
+}
+
+tst_run