diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock index dbcade0aeab1..a2d70990eaad 100644 --- a/src/agent/Cargo.lock +++ b/src/agent/Cargo.lock @@ -287,6 +287,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + [[package]] name = "bitflags" version = "1.3.2" @@ -602,6 +608,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "codicon" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12170080f3533d6f09a19f81596f836854d0fa4867dc32c8172b8474b4e9de61" + [[package]] name = "combine" version = "4.6.6" @@ -1051,7 +1063,16 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", ] [[package]] @@ -1075,6 +1096,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1979,6 +2012,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "iocuddle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8972d5be69940353d5347a1344cb375d9b457d6809b428b05bb1ca2fb9ce007" + [[package]] name = "iovec" version = "0.1.4" @@ -2100,6 +2139,7 @@ dependencies = [ "devicemapper", "futures", "h2", + "hex", "http", "image-rs", "ipnetwork", @@ -2114,7 +2154,6 @@ dependencies = [ "nix 0.24.3", "oci", "openssl", - "openssl-src", "opentelemetry", "proc-mounts", "procfs 0.12.0", @@ -2130,6 +2169,8 @@ dependencies = [ "serde", "serde_json", "serial_test", + "sev", + "sha2 0.10.6", "simple_asn1", "slog", "slog-scope", @@ -2204,6 +2245,26 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kvm-bindings" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe70e65a5b092161d17f5005b66e5eefe7a94a70c332e755036fc4af78c4e79" +dependencies = [ + "vmm-sys-util", +] + +[[package]] +name = "kvm-ioctls" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bdde2b46ee7b6587ef79f751019c4726c4f2d3e4628df5d69f3f9c5cb6c6bd4" +dependencies = [ + "kvm-bindings", + "libc", + "vmm-sys-util", +] + [[package]] name = "lalrpop" version = "0.19.12" @@ -2249,9 +2310,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -2875,6 +2936,12 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-stream" version = "0.0.1" @@ -4175,6 +4242,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.9" @@ -4264,6 +4340,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "sev" +version = "1.2.1" +source = "git+https://github.com/virtee/sev#b33ecb6320d65418e8cb154cf3fabbb6480a30df" +dependencies = [ + "bincode", + "bitfield", + "bitflags", + "codicon", + "dirs 5.0.1", + "hex", + "iocuddle", + "kvm-ioctls", + "libc", + "serde", + "serde-big-array", + "serde_bytes", + "static_assertions", + "uuid", +] + [[package]] name = "sha-1" version = "0.10.1" @@ -5176,6 +5273,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "serde", +] + [[package]] name = "valuable" version = "0.1.0" @@ -5203,6 +5309,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vmm-sys-util" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46" +dependencies = [ + "bitflags", + "libc", +] + [[package]] name = "vsock" version = "0.2.6" @@ -5664,7 +5780,7 @@ dependencies = [ "async-trait", "byteorder", "derivative", - "dirs", + "dirs 4.0.0", "enumflags2", "event-listener", "futures-core", diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml index 331c3728c0e2..dff6ba477298 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -12,7 +12,7 @@ protocols = { path = "../libs/protocols", features = ["async", "with-serde"] } lazy_static = "1.3.0" ttrpc = { version = "0.7.1", features = ["async"], default-features = false } protobuf = "3.2.0" -libc = "0.2.58" +libc = "0.2.147" nix = "0.24.2" capctl = "0.2.0" serde_json = "1.0.39" @@ -74,17 +74,21 @@ serde = { version = "1.0.129", features = ["derive"] } toml = "0.5.8" clap = { version = "3.0.1", features = ["derive"] } -# "vendored" feature for openssl is required by musl build -openssl = "0.10.54" -openssl-src = "111.26.0" # OPA requests -http = "0.2.8" -reqwest = { version = "0.11.14" } +http = { version = "0.2.8", optional = true } +reqwest = { version = "0.11.14", optional = true } +# "vendored" feature for openssl is required by musl build +openssl = { version = "0.10.54", features = ["vendored"], optional = true } # Image pull/decrypt image-rs = { git = "https://github.com/confidential-containers/image-rs", tag = "v0.6.0", default-features = false, features = ["kata-cc-native-tls"] } +# Policy validation +sha2 = { version = "0.10.6", optional = true } +hex = { version = "0.4.2", optional = true } +sev = { git = "https://github.com/virtee/sev", version = "1.2", default-features = false, features = ["snp"], optional = true } + [patch.crates-io] oci-distribution = { git = "https://github.com/krustlet/oci-distribution.git", rev = "f44124c" } @@ -103,9 +107,10 @@ members = [ lto = true [features] +default = [] seccomp = ["rustjail/seccomp"] standard-oci-runtime = ["rustjail/standard-oci-runtime"] -security-policy = [] +security-policy = ["hex", "http", "openssl", "reqwest", "sev", "sha2"] [[bin]] name = "kata-agent" diff --git a/src/agent/src/policy.rs b/src/agent/src/policy.rs index d2397b72c3c3..70ee48aa6def 100644 --- a/src/agent/src/policy.rs +++ b/src/agent/src/policy.rs @@ -3,9 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 // -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use reqwest::Client; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use tokio::io::AsyncWriteExt; use tokio::time::{sleep, Duration}; @@ -106,6 +107,8 @@ impl AgentPolicy { /// Replace the Policy in OPA. pub async fn set_policy(&mut self, policy: &str) -> Result<()> { + check_policy_hash(policy)?; + // Delete the old rules. self.opa_client .delete(&self.policy_path) @@ -195,3 +198,24 @@ impl AgentPolicy { } } } + +pub fn check_policy_hash(policy: &str) -> Result<()> { + let mut hasher = Sha256::new(); + hasher.update(policy.as_bytes()); + let digest = hasher.finalize(); + debug!(sl!(), "policy: calculated hash ({:?})", digest.as_slice()); + + let mut firmware = sev::firmware::guest::Firmware::open()?; + let report_data: [u8; 64] = [0; 64]; + let report = firmware.get_report(None, Some(report_data), Some(0))?; + + if report.host_data != digest.as_slice() { + bail!( + "Unexpected policy hash ({:?}), expected ({:?})", + digest.as_slice(), + report.host_data + ); + } + + Ok(()) +} diff --git a/src/runtime/virtcontainers/clh.go b/src/runtime/virtcontainers/clh.go index c50970f6da12..7e7e5c00e92c 100644 --- a/src/runtime/virtcontainers/clh.go +++ b/src/runtime/virtcontainers/clh.go @@ -89,7 +89,7 @@ const ( clhAPISocket = "clh-api.sock" virtioFsSocket = "virtiofsd.sock" defaultClhPath = "/usr/local/bin/cloud-hypervisor" - snpHostDataDummy = "0123456789012345678901234567890123456789012345678901234567890123" + snpZeroHostData = "0000000000000000000000000000000000000000000000000000000000000000" ) // Interface that hides the implementation of openAPI client @@ -458,7 +458,11 @@ func (clh *cloudHypervisor) enableProtection() error { } clh.vmconfig.Platform.SetSnp(true) - clh.vmconfig.Payload.SetHostData(snpHostDataDummy) + if len(clh.config.PolicyHash) > 0 { + clh.vmconfig.Payload.SetHostData(clh.config.PolicyHash) + } else { + clh.vmconfig.Payload.SetHostData(snpZeroHostData) + } return nil diff --git a/src/runtime/virtcontainers/hypervisor.go b/src/runtime/virtcontainers/hypervisor.go index 47b6805d8f77..dc39a363d418 100644 --- a/src/runtime/virtcontainers/hypervisor.go +++ b/src/runtime/virtcontainers/hypervisor.go @@ -422,6 +422,7 @@ type HypervisorConfig struct { DisableGuestSeLinux bool LegacySerial bool ColdPlugVFIO hv.PCIePort + PolicyHash string } // vcpu mapping from vcpu number to thread number diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index 1d3b729ff5b1..0b0591f90638 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -10,6 +10,8 @@ import ( "bufio" "bytes" "context" + "crypto/sha256" + "encoding/hex" "fmt" "io" "math" @@ -647,6 +649,8 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor } } + sandboxConfig.HypervisorConfig.PolicyHash = getAgentPolicyHash(sandboxConfig.AgentConfig.Policy) + // store doesn't require hypervisor to be stored immediately if err = s.hypervisor.CreateVM(ctx, s.id, s.network, &sandboxConfig.HypervisorConfig); err != nil { return nil, err @@ -2702,3 +2706,13 @@ func (s *Sandbox) resetVCPUsPinning(ctx context.Context, vCPUThreadsMap VcpuThre func (s *Sandbox) PullImage(ctx context.Context, req *image.PullImageReq) (*image.PullImageResp, error) { return s.agent.PullImage(ctx, req) } + +func getAgentPolicyHash(policy string) string { + if len(policy) == 0 { + return "" + } else { + h := sha256.New() + h.Write([]byte(policy)) + return hex.EncodeToString(h.Sum(nil)) + } +}