Skip to content

Commit 8453885

Browse files
authored
feat: Add SEV measurements to ReplicaVersionRecord (#5966)
NODE-1670 - Replace the deprecated `guest_launch_measurement_sha256_hex` field with a new `GuestLaunchMeasurements` message in `ReplicateVersionRecord` and the corresponding proposal. - Add logic in IC-OS build to calculate the SEV measurement. - Add code in ic-admin to read the generated measurement json and populate the measurement in the proposal. - Propagate the SEV measurement to system tests. - Update various tests to be compatible with the changes. Design doc: https://docs.google.com/document/d/1sowOFzE6HtOsc8Vfpo8Sa3GcJNhy_x6EAroYgGAThic/edit?tab=t.3exr0kbb2lvq
1 parent f13aff7 commit 8453885

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+426
-81
lines changed

ic-os/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
2+
13
exports_files([
24
"vuln-scan/vuln-scan.sh",
35
"vuln-scan/vuln-scan.html",
46
"dev-tools/launch-remote-vm.sh",
57
"dev-tools/build-setupos-config-image.sh",
68
])
9+
10+
py_console_script_binary(
11+
name = "sev-snp-measure",
12+
pkg = "@python_deps//sev_snp_measure",
13+
visibility = ["//ic-os:__subpackages__"],
14+
)

ic-os/defs.bzl

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,23 @@ def icos_build(
132132
tags = ["manual"],
133133
)
134134

135+
# Extract initrd and kernel for SEV measurement
136+
tar_extract(
137+
name = "extracted_initrd.img",
138+
src = "rootfs-tree.tar",
139+
path = "boot/initrd.img-*",
140+
wildcards = True,
141+
tags = ["manual"],
142+
)
143+
144+
tar_extract(
145+
name = "extracted_vmlinuz",
146+
src = "rootfs-tree.tar",
147+
path = "boot/vmlinuz-*",
148+
wildcards = True,
149+
tags = ["manual"],
150+
)
151+
135152
# -------------------- Extract root and boot partitions --------------------
136153

137154
# NOTE: e2fsdroid does not support filenames with spaces, fortunately,
@@ -161,6 +178,7 @@ def icos_build(
161178
version_txt = "version" + test_suffix + ".txt"
162179
boot_args = "boot" + test_suffix + "_args"
163180
extra_boot_args = "extra_boot" + test_suffix + "_args"
181+
launch_measurements = "launch-measurements" + test_suffix + ".json"
164182

165183
ext4_image(
166184
name = partition_root_unsigned_tzst,
@@ -260,6 +278,28 @@ def icos_build(
260278
tags = ["manual"],
261279
)
262280

281+
if image_deps.get("generate_launch_measurements", False):
282+
native.genrule(
283+
name = "generate-" + launch_measurements,
284+
outs = [launch_measurements],
285+
srcs = ["//ic-os/components/ovmf:ovmf_sev", boot_args, ":extracted_initrd.img", ":extracted_vmlinuz"],
286+
visibility = visibility,
287+
tools = ["//ic-os:sev-snp-measure"],
288+
cmd = r"""
289+
source $(execpath """ + boot_args + """)
290+
# Create GuestLaunchMeasurements JSON
291+
(for cmdline in "$$BOOT_ARGS_A" "$$BOOT_ARGS_B"; do
292+
hex=$$($(execpath //ic-os:sev-snp-measure) --mode snp --vcpus 64 --ovmf "$(execpath //ic-os/components/ovmf:ovmf_sev)" --vcpu-type=EPYC-v4 --append "$$cmdline" --initrd "$(location extracted_initrd.img)" --kernel "$(location extracted_vmlinuz)")
293+
# Convert hex string to decimal list, e.g. "abcd" -> 171\\n205
294+
measurement=$$(echo -n "$$hex" | fold -w2 | sed "s/^/0x/" | xargs printf "%d\n")
295+
jq -na --arg cmd "$$cmdline" --arg m "$$measurement" '{
296+
measurement: ($$m | split("\n") | map(tonumber)),
297+
metadata: {kernel_cmdline: $$cmd}
298+
}'
299+
done) | jq -sc "{guest_launch_measurements: .}" > $@
300+
""",
301+
)
302+
263303
component_file_references_test(
264304
name = name + "_component_file_references_test",
265305
image = ":partition-root-unsigned.tzst",
@@ -440,11 +480,20 @@ EOF
440480
tags = tags,
441481
)
442482

443-
icos_images = struct(
444-
disk_image = ":disk-img.tar.zst",
445-
update_image = ":update-img.tar.zst",
446-
update_image_test = ":update-img-test.tar.zst",
447-
)
483+
if image_deps.get("generate_launch_measurements", False):
484+
icos_images = struct(
485+
disk_image = ":disk-img.tar.zst",
486+
update_image = ":update-img.tar.zst",
487+
update_image_test = ":update-img-test.tar.zst",
488+
launch_measurements = ":launch-measurements.json",
489+
launch_measurements_test = ":launch-measurements-test.json",
490+
)
491+
else:
492+
icos_images = struct(
493+
disk_image = ":disk-img.tar.zst",
494+
update_image = ":update-img.tar.zst",
495+
update_image_test = ":update-img-test.tar.zst",
496+
)
448497
return icos_images
449498

450499
# end def icos_build
@@ -456,7 +505,8 @@ def _tar_extract_impl(ctx):
456505
ctx.actions.run_shell(
457506
inputs = [in_tar],
458507
outputs = [out],
459-
command = "tar xOf %s --occurrence=1 %s > %s" % (
508+
command = "tar %s -xOf %s --occurrence=1 %s > %s" % (
509+
"--wildcards" if ctx.attr.wildcards else "",
460510
in_tar.path,
461511
ctx.attr.path,
462512
out.path,
@@ -475,5 +525,9 @@ tar_extract = rule(
475525
"path": attr.string(
476526
mandatory = True,
477527
),
528+
"wildcards": attr.bool(
529+
default = False,
530+
doc = "If True, the path is treated as a glob pattern.",
531+
),
478532
},
479533
)

ic-os/guestos/defs.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def image_deps(mode, malicious = False):
7474
"boot_args_template": Label("//ic-os/bootloader:guestos_boot_args.template"),
7575
# GuestOS requires dm-verity root partition signing
7676
"requires_root_signing": True,
77+
"generate_launch_measurements": True,
7778
}
7879

7980
dev_build_args = ["BUILD_TYPE=dev", "ROOT_PASSWORD=root"]

ic-os/guestos/envs/dev/BUILD.bazel

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ file_size_check(
3939
artifact_bundle(
4040
name = "bundle-disk",
4141
testonly = True,
42-
inputs = [icos_images.disk_image],
42+
inputs = [
43+
icos_images.disk_image,
44+
icos_images.launch_measurements,
45+
],
4346
prefix = "guest-os/disk-img-dev",
4447
visibility = ["//visibility:public"],
4548
)

ic-os/guestos/envs/prod/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ artifact_bundle(
4141
inputs = [
4242
icos_images.update_image,
4343
icos_images.update_image_test,
44+
icos_images.launch_measurements,
4445
],
4546
prefix = "guest-os/update-img",
4647
visibility = ["//visibility:public"],

ic-os/guestos/envs/recovery/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ artifact_bundle(
4242
inputs = [
4343
icos_images.update_image,
4444
icos_images.update_image_test,
45+
icos_images.launch_measurements,
46+
icos_images.launch_measurements_test,
4547
],
4648
prefix = "guest-os/update-img-recovery",
4749
tags = [

requirements.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pytest
2525
pytest-cov
2626
PyYAML>=6.0.2
2727
requests>=2.26.0
28+
sev-snp-measure
2829
simple-parsing
2930
tqdm
3031
uuid

requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ cryptography==45.0.4 \
409409
# ansible-core
410410
# paramiko
411411
# pyjwt
412+
# sev-snp-measure
412413
cvss==3.4 \
413414
--hash=sha256:632353244ba3c58b53355466677edc968b9d7143c317b66271f9fd7939951ee8 \
414415
--hash=sha256:d9950613758e60820f7fac37ca5f35158712f8f2ea4f6629858a60c4984fe4ef
@@ -857,6 +858,10 @@ resolvelib==1.0.1 \
857858
--hash=sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309 \
858859
--hash=sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf
859860
# via ansible-core
861+
sev-snp-measure==0.0.11 \
862+
--hash=sha256:1f1953b94cce43b08041aa7b0e804998f6d89a3d648395b40c447ecd470b1d54 \
863+
--hash=sha256:579abfc6e9359b6bff4755a99d0704c3d2e2fd8fec16882d533192c1d5943c35
864+
# via -r requirements.in
860865
simple-parsing==0.1.7 \
861866
--hash=sha256:225e6b35252d68f7894716101fe3bd7e6dd3d30ab7b1c3c023f77a42dbe1336f \
862867
--hash=sha256:5276e6c90c157362dd0173d1eecebe58361a66b457129cc9bba13b78a4e85092

rs/ic_os/dev_test_tools/launch-single-vm/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ fn main() {
167167
None,
168168
None,
169169
None,
170+
None,
170171
Vec::new(),
171172
);
172173
let initialized_ic = ic_config.initialize().unwrap();

rs/nns/integration_tests/src/upgrades_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn test_submit_and_accept_update_elected_replica_versions_proposal() {
6969
.map(|_| vec!["http://release_package.tar.zst".to_string()])
7070
.unwrap_or_default(),
7171
replica_version_to_elect: elect,
72-
guest_launch_measurement_sha256_hex: None,
72+
guest_launch_measurements: None,
7373
replica_versions_to_unelect: unelect.iter().map(|s| s.to_string()).collect(),
7474
};
7575
let bless_version_payload = |version_id: &str| -> ReviseElectedGuestosVersionsPayload {

0 commit comments

Comments
 (0)