|
| 1 | +// Copyright 2026 Edgeless Systems GmbH |
| 2 | +// SPDX-License-Identifier: BUSL-1.1 |
| 3 | + |
| 4 | +//go:build e2e |
| 5 | + |
| 6 | +package badamlvuln |
| 7 | + |
| 8 | +import ( |
| 9 | + "context" |
| 10 | + "testing" |
| 11 | + "time" |
| 12 | + |
| 13 | + "github.com/edgelesssys/contrast/e2e/internal/contrasttest" |
| 14 | + "github.com/edgelesssys/contrast/internal/kuberesource" |
| 15 | + "github.com/edgelesssys/contrast/internal/manifest" |
| 16 | + "github.com/edgelesssys/contrast/internal/platforms" |
| 17 | + "github.com/stretchr/testify/require" |
| 18 | +) |
| 19 | + |
| 20 | +// BadAMLTest is the shared logic between the badaml-vuln and badaml-sandbox tests. |
| 21 | +func BadAMLTest(t *testing.T, expectSuccessfulAttack bool) { |
| 22 | + platform, err := platforms.FromString(contrasttest.Flags.PlatformStr) |
| 23 | + require.NoError(t, err) |
| 24 | + |
| 25 | + ct := contrasttest.New(t) |
| 26 | + |
| 27 | + require.True(t, contrasttest.Flags.InsecureEnableDebugShell, "the --insecure-enable-debug-shell-access flag must be set to true to extract the initrd start address") |
| 28 | + |
| 29 | + runtimeHandler, err := manifest.RuntimeHandler(platform) |
| 30 | + require.NoError(t, err) |
| 31 | + resources := kuberesource.CoordinatorBundle() |
| 32 | + resources = kuberesource.PatchRuntimeHandlers(resources, runtimeHandler) |
| 33 | + resources = kuberesource.AddPortForwarders(resources) |
| 34 | + ct.Init(t, resources) |
| 35 | + |
| 36 | + require.True(t, t.Run("generate", ct.Generate), "contrast generate needs to succeed for subsequent tests") |
| 37 | + require.True(t, t.Run("apply", ct.Apply), "Kubernetes resources need to be applied for subsequent tests") |
| 38 | + if platform == platforms.MetalQEMUTDX { |
| 39 | + // TODO(katexochen): Set on TDX currently fails, as we are still measuring the ACPI tables, so |
| 40 | + // the injected BadAML table is detected during remote attestation. For TDX-GPU, we don't measure |
| 41 | + // the table so the attack works. |
| 42 | + require.True(t, t.Run("wait for debugshell", func(t *testing.T) { |
| 43 | + ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(2*time.Minute)) |
| 44 | + defer cancel() |
| 45 | + require.NoError(t, ct.Kubeclient.WaitForContainer(ctx, ct.Namespace, "coordinator-0", "contrast-debug-shell")) |
| 46 | + }), "debugshell start must succeed for subsequent tests") |
| 47 | + } else { |
| 48 | + require.True(t, t.Run("set", ct.Set), "contrast set needs to succeed for subsequent tests") |
| 49 | + } |
| 50 | + |
| 51 | + var content string |
| 52 | + require.True(t, t.Run("get content of /run/deadbeef.bin", func(t *testing.T) { |
| 53 | + ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(1*time.Minute)) |
| 54 | + defer cancel() |
| 55 | + cmd := []string{"debugshell", `hexdump -e '1/1 "%02x"' -n4 /run/deadbeef.bin`} |
| 56 | + stdout, stderr, err := ct.Kubeclient.ExecContainer(ctx, ct.Namespace, "coordinator-0", "contrast-debug-shell", cmd) |
| 57 | + require.NoError(t, err, "running %q:\nstdout:\n%s\nstderr:\n%s", cmd, stdout, stderr) |
| 58 | + content = stdout |
| 59 | + }), "getting content of /run/deadbeef.bin needs to succeed for subsequent tests") |
| 60 | + |
| 61 | + require.True(t, t.Run("get dmesg logs", func(t *testing.T) { |
| 62 | + ctx, cancel := context.WithTimeout(t.Context(), ct.FactorPlatformTimeout(1*time.Minute)) |
| 63 | + defer cancel() |
| 64 | + cmd := []string{"debugshell", "dmesg | grep -i acpi"} |
| 65 | + stdout, stderr, err := ct.Kubeclient.ExecContainer(ctx, ct.Namespace, "coordinator-0", "contrast-debug-shell", cmd) |
| 66 | + require.NoError(t, err, "running %q:\nstdout:\n%s\nstderr:\n%s", cmd, stdout, stderr) |
| 67 | + t.Log(stdout) |
| 68 | + })) |
| 69 | + |
| 70 | + name := "check attack is" |
| 71 | + if !expectSuccessfulAttack { |
| 72 | + name += " not" |
| 73 | + } |
| 74 | + name += " successful" |
| 75 | + require.True(t, t.Run(name, func(t *testing.T) { |
| 76 | + if expectSuccessfulAttack { |
| 77 | + require.Equal(t, "cafebabe", content, "the content of /run/deadbeef.bin should be 'cafebabe' if the attack was successful") |
| 78 | + } else { |
| 79 | + require.Equal(t, "deadbeef", content, "the content of /run/deadbeef.bin should be 'deadbeef' if the attack was not successful") |
| 80 | + } |
| 81 | + })) |
| 82 | +} |
0 commit comments