From 257353538c4314e2389d7a3a04e1cae3ac75f474 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Tue, 6 Jan 2026 06:05:19 +0530 Subject: [PATCH] Add protos for sandbox options and helpers In this commit, we are adding the proto definition used for passing along the parameters for sandbox to the shim. In addition to the proto, we are also adding few helper methods which take the runtime options along with the annotations and create the sandbox specs. We also have a method to convert the sandbox specs into appropriate UVM specs to be passed along to HCS. Signed-off-by: Harsh Rawat --- .../sandboxspec/doc.go | 1 + .../sandboxspec/sandbox.pb.go | 2228 +++++++++++++++++ .../sandboxspec/sandbox.proto | 439 ++++ .../sandboxspec/sandbox_specs.go | 689 +++++ .../sandboxspec/sandbox_specs_test.go | 836 +++++++ .../sandboxspec/uvm_specs.go | 627 +++++ .../sandboxspec/uvm_specs_test.go | 752 ++++++ .../service_internal.go | 2 +- internal/oci/annotations.go | 47 +- internal/oci/annotations_test.go | 11 +- internal/oci/uvm.go | 48 +- 11 files changed, 5636 insertions(+), 44 deletions(-) create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/doc.go create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.pb.go create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.proto create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs.go create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs_test.go create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs.go create mode 100644 cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs_test.go diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/doc.go b/cmd/containerd-shim-runhcs-v1/sandboxspec/doc.go new file mode 100644 index 0000000000..030287cd80 --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/doc.go @@ -0,0 +1 @@ +package sandboxspec diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.pb.go b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.pb.go new file mode 100644 index 0000000000..f164027d9b --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.pb.go @@ -0,0 +1,2228 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.7 +// protoc v5.26.0 +// source: github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.proto + +package sandboxspec + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type RegistryHive int32 + +const ( + RegistryHive_REGISTRY_HIVE_SYSTEM RegistryHive = 0 + RegistryHive_REGISTRY_HIVE_SOFTWARE RegistryHive = 1 + RegistryHive_REGISTRY_HIVE_SECURITY RegistryHive = 2 + RegistryHive_REGISTRY_HIVE_SAM RegistryHive = 3 +) + +// Enum value maps for RegistryHive. +var ( + RegistryHive_name = map[int32]string{ + 0: "REGISTRY_HIVE_SYSTEM", + 1: "REGISTRY_HIVE_SOFTWARE", + 2: "REGISTRY_HIVE_SECURITY", + 3: "REGISTRY_HIVE_SAM", + } + RegistryHive_value = map[string]int32{ + "REGISTRY_HIVE_SYSTEM": 0, + "REGISTRY_HIVE_SOFTWARE": 1, + "REGISTRY_HIVE_SECURITY": 2, + "REGISTRY_HIVE_SAM": 3, + } +) + +func (x RegistryHive) Enum() *RegistryHive { + p := new(RegistryHive) + *p = x + return p +} + +func (x RegistryHive) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RegistryHive) Descriptor() protoreflect.EnumDescriptor { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes[0].Descriptor() +} + +func (RegistryHive) Type() protoreflect.EnumType { + return &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes[0] +} + +func (x RegistryHive) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RegistryHive.Descriptor instead. +func (RegistryHive) EnumDescriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{0} +} + +type RegistryValueType int32 + +const ( + RegistryValueType_REGISTRY_VALUE_TYPE_NONE RegistryValueType = 0 + RegistryValueType_REGISTRY_VALUE_TYPE_STRING RegistryValueType = 1 + RegistryValueType_REGISTRY_VALUE_TYPE_EXPANDED_STRING RegistryValueType = 2 + RegistryValueType_REGISTRY_VALUE_TYPE_MULTI_STRING RegistryValueType = 3 + RegistryValueType_REGISTRY_VALUE_TYPE_BINARY RegistryValueType = 4 + RegistryValueType_REGISTRY_VALUE_TYPE_D_WORD RegistryValueType = 5 + RegistryValueType_REGISTRY_VALUE_TYPE_Q_WORD RegistryValueType = 6 + RegistryValueType_REGISTRY_VALUE_TYPE_CUSTOM_TYPE RegistryValueType = 7 +) + +// Enum value maps for RegistryValueType. +var ( + RegistryValueType_name = map[int32]string{ + 0: "REGISTRY_VALUE_TYPE_NONE", + 1: "REGISTRY_VALUE_TYPE_STRING", + 2: "REGISTRY_VALUE_TYPE_EXPANDED_STRING", + 3: "REGISTRY_VALUE_TYPE_MULTI_STRING", + 4: "REGISTRY_VALUE_TYPE_BINARY", + 5: "REGISTRY_VALUE_TYPE_D_WORD", + 6: "REGISTRY_VALUE_TYPE_Q_WORD", + 7: "REGISTRY_VALUE_TYPE_CUSTOM_TYPE", + } + RegistryValueType_value = map[string]int32{ + "REGISTRY_VALUE_TYPE_NONE": 0, + "REGISTRY_VALUE_TYPE_STRING": 1, + "REGISTRY_VALUE_TYPE_EXPANDED_STRING": 2, + "REGISTRY_VALUE_TYPE_MULTI_STRING": 3, + "REGISTRY_VALUE_TYPE_BINARY": 4, + "REGISTRY_VALUE_TYPE_D_WORD": 5, + "REGISTRY_VALUE_TYPE_Q_WORD": 6, + "REGISTRY_VALUE_TYPE_CUSTOM_TYPE": 7, + } +) + +func (x RegistryValueType) Enum() *RegistryValueType { + p := new(RegistryValueType) + *p = x + return p +} + +func (x RegistryValueType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RegistryValueType) Descriptor() protoreflect.EnumDescriptor { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes[1].Descriptor() +} + +func (RegistryValueType) Type() protoreflect.EnumType { + return &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes[1] +} + +func (x RegistryValueType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RegistryValueType.Descriptor instead. +func (RegistryValueType) EnumDescriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{1} +} + +type PreferredRootFSType int32 + +const ( + PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_INITRD PreferredRootFSType = 0 + PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_VHD PreferredRootFSType = 1 +) + +// Enum value maps for PreferredRootFSType. +var ( + PreferredRootFSType_name = map[int32]string{ + 0: "PREFERRED_ROOT_FS_TYPE_INITRD", + 1: "PREFERRED_ROOT_FS_TYPE_VHD", + } + PreferredRootFSType_value = map[string]int32{ + "PREFERRED_ROOT_FS_TYPE_INITRD": 0, + "PREFERRED_ROOT_FS_TYPE_VHD": 1, + } +) + +func (x PreferredRootFSType) Enum() *PreferredRootFSType { + p := new(PreferredRootFSType) + *p = x + return p +} + +func (x PreferredRootFSType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PreferredRootFSType) Descriptor() protoreflect.EnumDescriptor { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes[2].Descriptor() +} + +func (PreferredRootFSType) Type() protoreflect.EnumType { + return &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes[2] +} + +func (x PreferredRootFSType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PreferredRootFSType.Descriptor instead. +func (PreferredRootFSType) EnumDescriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{2} +} + +type Specs struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sandbox isolation mode. + // + // Types that are valid to be assigned to IsolationLevel: + // + // *Specs_Process + // *Specs_Hypervisor + IsolationLevel isSpecs_IsolationLevel `protobuf_oneof:"isolation_level"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Specs) Reset() { + *x = Specs{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Specs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Specs) ProtoMessage() {} + +func (x *Specs) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Specs.ProtoReflect.Descriptor instead. +func (*Specs) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{0} +} + +func (x *Specs) GetIsolationLevel() isSpecs_IsolationLevel { + if x != nil { + return x.IsolationLevel + } + return nil +} + +func (x *Specs) GetProcess() *ProcessIsolated { + if x != nil { + if x, ok := x.IsolationLevel.(*Specs_Process); ok { + return x.Process + } + } + return nil +} + +func (x *Specs) GetHypervisor() *HypervisorIsolated { + if x != nil { + if x, ok := x.IsolationLevel.(*Specs_Hypervisor); ok { + return x.Hypervisor + } + } + return nil +} + +type isSpecs_IsolationLevel interface { + isSpecs_IsolationLevel() +} + +type Specs_Process struct { + // Process-isolated sandbox (no UVM). + Process *ProcessIsolated `protobuf:"bytes,1,opt,name=process,proto3,oneof"` +} + +type Specs_Hypervisor struct { + // Hypervisor-isolated sandbox (UVM-backed). + Hypervisor *HypervisorIsolated `protobuf:"bytes,2,opt,name=hypervisor,proto3,oneof"` +} + +func (*Specs_Process) isSpecs_IsolationLevel() {} + +func (*Specs_Hypervisor) isSpecs_IsolationLevel() {} + +type ProcessIsolated struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProcessIsolated) Reset() { + *x = ProcessIsolated{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProcessIsolated) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessIsolated) ProtoMessage() {} + +func (x *ProcessIsolated) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProcessIsolated.ProtoReflect.Descriptor instead. +func (*ProcessIsolated) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{1} +} + +type HypervisorIsolated struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Platform-specific UVM options. + // + // Types that are valid to be assigned to Platform: + // + // *HypervisorIsolated_Lcow + // *HypervisorIsolated_Wcow + Platform isHypervisorIsolated_Platform `protobuf_oneof:"platform"` + // UVM CPU topology. + CpuConfig *CPUConfig `protobuf:"bytes,3,opt,name=cpuConfig,proto3" json:"cpuConfig,omitempty"` + // UVM memory sizing and commit policy; MMIO aperture tuning. + MemoryConfig *MemoryConfig `protobuf:"bytes,4,opt,name=memoryConfig,proto3" json:"memoryConfig,omitempty"` + // UVM storage QoS caps and file-share hardening. + StorageConfig *StorageConfig `protobuf:"bytes,5,opt,name=storageConfig,proto3" json:"storageConfig,omitempty"` + // UVM vNUMA hints (implicit/explicit topology). + NumaConfig *NUMAConfig `protobuf:"bytes,6,opt,name=numaConfig,proto3" json:"numaConfig,omitempty"` + // Misc sandbox controls: networking proxy, dump paths, HvSocket services, console pipe. + AdditionalConfig *AdditionalConfig `protobuf:"bytes,7,opt,name=additionalConfig,proto3" json:"additionalConfig,omitempty"` + // Assign the UVM to a CPU group. Mutually exclusive with resource_partition_id. + CpuGroupID *string `protobuf:"bytes,8,opt,name=cpu_group_id,json=cpuGroupId,proto3,oneof" json:"cpu_group_id,omitempty"` + // Resource partition GUID to associate the UVM with (has its own CPU group). + // Mutually exclusive with cpu_group_id. + ResourcePartitionID *string `protobuf:"bytes,9,opt,name=resource_partition_id,json=resourcePartitionId,proto3,oneof" json:"resource_partition_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HypervisorIsolated) Reset() { + *x = HypervisorIsolated{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HypervisorIsolated) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HypervisorIsolated) ProtoMessage() {} + +func (x *HypervisorIsolated) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HypervisorIsolated.ProtoReflect.Descriptor instead. +func (*HypervisorIsolated) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{2} +} + +func (x *HypervisorIsolated) GetPlatform() isHypervisorIsolated_Platform { + if x != nil { + return x.Platform + } + return nil +} + +func (x *HypervisorIsolated) GetLcow() *LinuxHyperVOptions { + if x != nil { + if x, ok := x.Platform.(*HypervisorIsolated_Lcow); ok { + return x.Lcow + } + } + return nil +} + +func (x *HypervisorIsolated) GetWcow() *WindowsHyperVOptions { + if x != nil { + if x, ok := x.Platform.(*HypervisorIsolated_Wcow); ok { + return x.Wcow + } + } + return nil +} + +func (x *HypervisorIsolated) GetCpuConfig() *CPUConfig { + if x != nil { + return x.CpuConfig + } + return nil +} + +func (x *HypervisorIsolated) GetMemoryConfig() *MemoryConfig { + if x != nil { + return x.MemoryConfig + } + return nil +} + +func (x *HypervisorIsolated) GetStorageConfig() *StorageConfig { + if x != nil { + return x.StorageConfig + } + return nil +} + +func (x *HypervisorIsolated) GetNumaConfig() *NUMAConfig { + if x != nil { + return x.NumaConfig + } + return nil +} + +func (x *HypervisorIsolated) GetAdditionalConfig() *AdditionalConfig { + if x != nil { + return x.AdditionalConfig + } + return nil +} + +func (x *HypervisorIsolated) GetCpuGroupID() string { + if x != nil && x.CpuGroupID != nil { + return *x.CpuGroupID + } + return "" +} + +func (x *HypervisorIsolated) GetResourcePartitionID() string { + if x != nil && x.ResourcePartitionID != nil { + return *x.ResourcePartitionID + } + return "" +} + +type isHypervisorIsolated_Platform interface { + isHypervisorIsolated_Platform() +} + +type HypervisorIsolated_Lcow struct { + // Linux UVM options. + Lcow *LinuxHyperVOptions `protobuf:"bytes,1,opt,name=lcow,proto3,oneof"` +} + +type HypervisorIsolated_Wcow struct { + // Windows UVM options. + Wcow *WindowsHyperVOptions `protobuf:"bytes,2,opt,name=wcow,proto3,oneof"` +} + +func (*HypervisorIsolated_Lcow) isHypervisorIsolated_Platform() {} + +func (*HypervisorIsolated_Wcow) isHypervisorIsolated_Platform() {} + +type CPUConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // vCPU count override for the UVM. On UVM, count/limit/weight may be combined. + ProcessorCount *int32 `protobuf:"varint,1,opt,name=processor_count,json=processorCount,proto3,oneof" json:"processor_count,omitempty"` + // vCPU percentage cap: 1..100000 (100000 = 100%). Omitted => platform default. + ProcessorLimit *int32 `protobuf:"varint,2,opt,name=processor_limit,json=processorLimit,proto3,oneof" json:"processor_limit,omitempty"` + // vCPU scheduling weight: 0..10000 (100 default). Omitted => default. + ProcessorWeight *int32 `protobuf:"varint,3,opt,name=processor_weight,json=processorWeight,proto3,oneof" json:"processor_weight,omitempty"` + // architecture represents the architecture of the platform. + Architecture *string `protobuf:"bytes,4,opt,name=architecture,proto3,oneof" json:"architecture,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CPUConfig) Reset() { + *x = CPUConfig{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CPUConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CPUConfig) ProtoMessage() {} + +func (x *CPUConfig) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CPUConfig.ProtoReflect.Descriptor instead. +func (*CPUConfig) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{3} +} + +func (x *CPUConfig) GetProcessorCount() int32 { + if x != nil && x.ProcessorCount != nil { + return *x.ProcessorCount + } + return 0 +} + +func (x *CPUConfig) GetProcessorLimit() int32 { + if x != nil && x.ProcessorLimit != nil { + return *x.ProcessorLimit + } + return 0 +} + +func (x *CPUConfig) GetProcessorWeight() int32 { + if x != nil && x.ProcessorWeight != nil { + return *x.ProcessorWeight + } + return 0 +} + +func (x *CPUConfig) GetArchitecture() string { + if x != nil && x.Architecture != nil { + return *x.Architecture + } + return "" +} + +type MemoryConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Total UVM memory size in MB (MB units; OCI uses bytes). + MemorySizeInMb *uint64 `protobuf:"varint,1,opt,name=memory_size_in_mb,json=memorySizeInMb,proto3,oneof" json:"memory_size_in_mb,omitempty"` + // MMIO aperture tuning (low gap/base/high gap in MB). + LowMmioGapInMb *uint64 `protobuf:"varint,2,opt,name=low_mmio_gap_in_mb,json=lowMmioGapInMb,proto3,oneof" json:"low_mmio_gap_in_mb,omitempty"` + HighMmioBaseInMb *uint64 `protobuf:"varint,3,opt,name=high_mmio_base_in_mb,json=highMmioBaseInMb,proto3,oneof" json:"high_mmio_base_in_mb,omitempty"` + HighMmioGapInMb *uint64 `protobuf:"varint,4,opt,name=high_mmio_gap_in_mb,json=highMmioGapInMb,proto3,oneof" json:"high_mmio_gap_in_mb,omitempty"` + // Allow virtual memory overcommit (true by default). Set false for fully physical backing. + AllowOvercommit *bool `protobuf:"varint,5,opt,name=allow_overcommit,json=allowOvercommit,proto3,oneof" json:"allow_overcommit,omitempty"` + // Enforce fully physically backed memory, including future device additions. + FullyPhysicallyBacked *bool `protobuf:"varint,6,opt,name=fully_physically_backed,json=fullyPhysicallyBacked,proto3,oneof" json:"fully_physically_backed,omitempty"` + // Enable deferred commit for virtual memory (defaults to false). + EnableDeferredCommit *bool `protobuf:"varint,7,opt,name=enable_deferred_commit,json=enableDeferredCommit,proto3,oneof" json:"enable_deferred_commit,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MemoryConfig) Reset() { + *x = MemoryConfig{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MemoryConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MemoryConfig) ProtoMessage() {} + +func (x *MemoryConfig) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MemoryConfig.ProtoReflect.Descriptor instead. +func (*MemoryConfig) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{4} +} + +func (x *MemoryConfig) GetMemorySizeInMb() uint64 { + if x != nil && x.MemorySizeInMb != nil { + return *x.MemorySizeInMb + } + return 0 +} + +func (x *MemoryConfig) GetLowMmioGapInMb() uint64 { + if x != nil && x.LowMmioGapInMb != nil { + return *x.LowMmioGapInMb + } + return 0 +} + +func (x *MemoryConfig) GetHighMmioBaseInMb() uint64 { + if x != nil && x.HighMmioBaseInMb != nil { + return *x.HighMmioBaseInMb + } + return 0 +} + +func (x *MemoryConfig) GetHighMmioGapInMb() uint64 { + if x != nil && x.HighMmioGapInMb != nil { + return *x.HighMmioGapInMb + } + return 0 +} + +func (x *MemoryConfig) GetAllowOvercommit() bool { + if x != nil && x.AllowOvercommit != nil { + return *x.AllowOvercommit + } + return false +} + +func (x *MemoryConfig) GetFullyPhysicallyBacked() bool { + if x != nil && x.FullyPhysicallyBacked != nil { + return *x.FullyPhysicallyBacked + } + return false +} + +func (x *MemoryConfig) GetEnableDeferredCommit() bool { + if x != nil && x.EnableDeferredCommit != nil { + return *x.EnableDeferredCommit + } + return false +} + +type StorageConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Max storage IOPS; 0/omitted => platform default. + StorageQosIopsMaximum *int32 `protobuf:"varint,1,opt,name=storage_qos_iops_maximum,json=storageQosIopsMaximum,proto3,oneof" json:"storage_qos_iops_maximum,omitempty"` + // Max storage bandwidth in bytes/sec; 0/omitted => platform default. + StorageQosBandwidthMaximum *int32 `protobuf:"varint,2,opt,name=storage_qos_bandwidth_maximum,json=storageQosBandwidthMaximum,proto3,oneof" json:"storage_qos_bandwidth_maximum,omitempty"` + // Disallow any writable file shares (e.g., VSMB/Plan9) to the UVM. + NoWritableFileShares *bool `protobuf:"varint,3,opt,name=no_writable_file_shares,json=noWritableFileShares,proto3,oneof" json:"no_writable_file_shares,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StorageConfig) Reset() { + *x = StorageConfig{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StorageConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageConfig) ProtoMessage() {} + +func (x *StorageConfig) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageConfig.ProtoReflect.Descriptor instead. +func (*StorageConfig) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{5} +} + +func (x *StorageConfig) GetStorageQosIopsMaximum() int32 { + if x != nil && x.StorageQosIopsMaximum != nil { + return *x.StorageQosIopsMaximum + } + return 0 +} + +func (x *StorageConfig) GetStorageQosBandwidthMaximum() int32 { + if x != nil && x.StorageQosBandwidthMaximum != nil { + return *x.StorageQosBandwidthMaximum + } + return 0 +} + +func (x *StorageConfig) GetNoWritableFileShares() bool { + if x != nil && x.NoWritableFileShares != nil { + return *x.NoWritableFileShares + } + return false +} + +type NUMAConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Implicit vNUMA: max memory per node (MB). + MaxMemorySizePerNumaNode *uint64 `protobuf:"varint,1,opt,name=max_memory_size_per_numa_node,json=maxMemorySizePerNumaNode,proto3,oneof" json:"max_memory_size_per_numa_node,omitempty"` + // Implicit vNUMA: max processors per node. + MaxProcessorsPerNumaNode *uint32 `protobuf:"varint,2,opt,name=max_processors_per_numa_node,json=maxProcessorsPerNumaNode,proto3,oneof" json:"max_processors_per_numa_node,omitempty"` + // Implicit vNUMA: preferred physical NUMA nodes. + PreferredPhysicalNumaNodes []uint32 `protobuf:"varint,3,rep,packed,name=preferred_physical_numa_nodes,json=preferredPhysicalNumaNodes,proto3" json:"preferred_physical_numa_nodes,omitempty"` + // Explicit vNUMA: pNUMA -> vNUMA mapping by index. + NumaMappedPhysicalNodes []uint32 `protobuf:"varint,4,rep,packed,name=numa_mapped_physical_nodes,json=numaMappedPhysicalNodes,proto3" json:"numa_mapped_physical_nodes,omitempty"` + // Explicit vNUMA: processor counts per vNUMA index. + NumaProcessorCounts []uint32 `protobuf:"varint,5,rep,packed,name=numa_processor_counts,json=numaProcessorCounts,proto3" json:"numa_processor_counts,omitempty"` + // Explicit vNUMA: memory block counts per vNUMA index. + NumaMemoryBlocksCounts []uint64 `protobuf:"varint,6,rep,packed,name=numa_memory_blocks_counts,json=numaMemoryBlocksCounts,proto3" json:"numa_memory_blocks_counts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NUMAConfig) Reset() { + *x = NUMAConfig{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NUMAConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NUMAConfig) ProtoMessage() {} + +func (x *NUMAConfig) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NUMAConfig.ProtoReflect.Descriptor instead. +func (*NUMAConfig) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{6} +} + +func (x *NUMAConfig) GetMaxMemorySizePerNumaNode() uint64 { + if x != nil && x.MaxMemorySizePerNumaNode != nil { + return *x.MaxMemorySizePerNumaNode + } + return 0 +} + +func (x *NUMAConfig) GetMaxProcessorsPerNumaNode() uint32 { + if x != nil && x.MaxProcessorsPerNumaNode != nil { + return *x.MaxProcessorsPerNumaNode + } + return 0 +} + +func (x *NUMAConfig) GetPreferredPhysicalNumaNodes() []uint32 { + if x != nil { + return x.PreferredPhysicalNumaNodes + } + return nil +} + +func (x *NUMAConfig) GetNumaMappedPhysicalNodes() []uint32 { + if x != nil { + return x.NumaMappedPhysicalNodes + } + return nil +} + +func (x *NUMAConfig) GetNumaProcessorCounts() []uint32 { + if x != nil { + return x.NumaProcessorCounts + } + return nil +} + +func (x *NUMAConfig) GetNumaMemoryBlocksCounts() []uint64 { + if x != nil { + return x.NumaMemoryBlocksCounts + } + return nil +} + +type AdditionalConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // ncproxy service address for network setup; when set, use ncproxy. + NetworkConfigProxy *string `protobuf:"bytes,1,opt,name=network_config_proxy,json=networkConfigProxy,proto3,oneof" json:"network_config_proxy,omitempty"` + // In-guest path for container process dumps; prefer a mounted volume over scratch. + ProcessDumpLocation *string `protobuf:"bytes,2,opt,name=process_dump_location,json=processDumpLocation,proto3,oneof" json:"process_dump_location,omitempty"` + // Host directory to collect UVM crash dumps. + DumpDirectoryPath *string `protobuf:"bytes,3,opt,name=dump_directory_path,json=dumpDirectoryPath,proto3,oneof" json:"dump_directory_path,omitempty"` + // HvSocket per-service configuration (bind/connect SDDL, wildcard, disabled). + AdditionalHypervConfig map[string]*HvSocketServiceConfig `protobuf:"bytes,4,rep,name=additional_hyperv_config,json=additionalHypervConfig,proto3" json:"additional_hyperv_config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Serial console named pipe (e.g., \\.\pipe\) for the UVM console. + ConsolePipe *string `protobuf:"bytes,5,opt,name=console_pipe,json=consolePipe,proto3,oneof" json:"console_pipe,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdditionalConfig) Reset() { + *x = AdditionalConfig{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdditionalConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdditionalConfig) ProtoMessage() {} + +func (x *AdditionalConfig) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdditionalConfig.ProtoReflect.Descriptor instead. +func (*AdditionalConfig) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{7} +} + +func (x *AdditionalConfig) GetNetworkConfigProxy() string { + if x != nil && x.NetworkConfigProxy != nil { + return *x.NetworkConfigProxy + } + return "" +} + +func (x *AdditionalConfig) GetProcessDumpLocation() string { + if x != nil && x.ProcessDumpLocation != nil { + return *x.ProcessDumpLocation + } + return "" +} + +func (x *AdditionalConfig) GetDumpDirectoryPath() string { + if x != nil && x.DumpDirectoryPath != nil { + return *x.DumpDirectoryPath + } + return "" +} + +func (x *AdditionalConfig) GetAdditionalHypervConfig() map[string]*HvSocketServiceConfig { + if x != nil { + return x.AdditionalHypervConfig + } + return nil +} + +func (x *AdditionalConfig) GetConsolePipe() string { + if x != nil && x.ConsolePipe != nil { + return *x.ConsolePipe + } + return "" +} + +type HvSocketServiceConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Host bind permission SDDL. + BindSecurityDescriptor *string `protobuf:"bytes,1,opt,name=bind_security_descriptor,json=bindSecurityDescriptor,proto3,oneof" json:"bind_security_descriptor,omitempty"` + // Host connect permission SDDL. + ConnectSecurityDescriptor *string `protobuf:"bytes,2,opt,name=connect_security_descriptor,json=connectSecurityDescriptor,proto3,oneof" json:"connect_security_descriptor,omitempty"` + // Allow wildcard binds per policy. + AllowWildcardBinds *bool `protobuf:"varint,3,opt,name=allow_wildcard_binds,json=allowWildcardBinds,proto3,oneof" json:"allow_wildcard_binds,omitempty"` + // Disable service (refuse new, cancel existing connections). + Disabled *bool `protobuf:"varint,4,opt,name=disabled,proto3,oneof" json:"disabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HvSocketServiceConfig) Reset() { + *x = HvSocketServiceConfig{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HvSocketServiceConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HvSocketServiceConfig) ProtoMessage() {} + +func (x *HvSocketServiceConfig) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HvSocketServiceConfig.ProtoReflect.Descriptor instead. +func (*HvSocketServiceConfig) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{8} +} + +func (x *HvSocketServiceConfig) GetBindSecurityDescriptor() string { + if x != nil && x.BindSecurityDescriptor != nil { + return *x.BindSecurityDescriptor + } + return "" +} + +func (x *HvSocketServiceConfig) GetConnectSecurityDescriptor() string { + if x != nil && x.ConnectSecurityDescriptor != nil { + return *x.ConnectSecurityDescriptor + } + return "" +} + +func (x *HvSocketServiceConfig) GetAllowWildcardBinds() bool { + if x != nil && x.AllowWildcardBinds != nil { + return *x.AllowWildcardBinds + } + return false +} + +func (x *HvSocketServiceConfig) GetDisabled() bool { + if x != nil && x.Disabled != nil { + return *x.Disabled + } + return false +} + +type WindowsHyperVOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Boot configuration for WCOW UVM. + WindowsBootOptions *WindowsBootOptions `protobuf:"bytes,1,opt,name=windowsBootOptions,proto3" json:"windowsBootOptions,omitempty"` + // Guest configuration for WCOW UVM. + WindowsGuestOptions *WindowsGuestOptions `protobuf:"bytes,2,opt,name=windowsGuestOptions,proto3" json:"windowsGuestOptions,omitempty"` + // Confidential computing options for WCOW. + ConfidentialOptions *WCOWConfidentialOptions `protobuf:"bytes,3,opt,name=confidentialOptions,proto3" json:"confidentialOptions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WindowsHyperVOptions) Reset() { + *x = WindowsHyperVOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WindowsHyperVOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WindowsHyperVOptions) ProtoMessage() {} + +func (x *WindowsHyperVOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WindowsHyperVOptions.ProtoReflect.Descriptor instead. +func (*WindowsHyperVOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{9} +} + +func (x *WindowsHyperVOptions) GetWindowsBootOptions() *WindowsBootOptions { + if x != nil { + return x.WindowsBootOptions + } + return nil +} + +func (x *WindowsHyperVOptions) GetWindowsGuestOptions() *WindowsGuestOptions { + if x != nil { + return x.WindowsGuestOptions + } + return nil +} + +func (x *WindowsHyperVOptions) GetConfidentialOptions() *WCOWConfidentialOptions { + if x != nil { + return x.ConfidentialOptions + } + return nil +} + +type WindowsBootOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Disable network compartment namespacing in the WCOW UVM. + DisableCompartmentNamespace *bool `protobuf:"varint,1,opt,name=disable_compartment_namespace,json=disableCompartmentNamespace,proto3,oneof" json:"disable_compartment_namespace,omitempty"` + // Disable direct mapping for VSMB shares in the WCOW UVM. + NoDirectMap *bool `protobuf:"varint,2,opt,name=no_direct_map,json=noDirectMap,proto3,oneof" json:"no_direct_map,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WindowsBootOptions) Reset() { + *x = WindowsBootOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WindowsBootOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WindowsBootOptions) ProtoMessage() {} + +func (x *WindowsBootOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WindowsBootOptions.ProtoReflect.Descriptor instead. +func (*WindowsBootOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{10} +} + +func (x *WindowsBootOptions) GetDisableCompartmentNamespace() bool { + if x != nil && x.DisableCompartmentNamespace != nil { + return *x.DisableCompartmentNamespace + } + return false +} + +func (x *WindowsBootOptions) GetNoDirectMap() bool { + if x != nil && x.NoDirectMap != nil { + return *x.NoDirectMap + } + return false +} + +type WindowsGuestOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Do not inherit host timezone; default WCOW UVM time is UTC. + NoInheritHostTimezone *bool `protobuf:"varint,1,opt,name=no_inherit_host_timezone,json=noInheritHostTimezone,proto3,oneof" json:"no_inherit_host_timezone,omitempty"` + // Additional registry entries to apply in the guest. + AdditionalRegistryKeys []*RegistryValue `protobuf:"bytes,2,rep,name=additional_registry_keys,json=additionalRegistryKeys,proto3" json:"additional_registry_keys,omitempty"` + // Specifies whether to forward logs to the host or not. + ForwardLogs *bool `protobuf:"varint,3,opt,name=forward_logs,json=forwardLogs,proto3,oneof" json:"forward_logs,omitempty"` + // Specifies the log sources to be forwarded to the host. + LogSources *string `protobuf:"bytes,4,opt,name=log_sources,json=logSources,proto3,oneof" json:"log_sources,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WindowsGuestOptions) Reset() { + *x = WindowsGuestOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WindowsGuestOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WindowsGuestOptions) ProtoMessage() {} + +func (x *WindowsGuestOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WindowsGuestOptions.ProtoReflect.Descriptor instead. +func (*WindowsGuestOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{11} +} + +func (x *WindowsGuestOptions) GetNoInheritHostTimezone() bool { + if x != nil && x.NoInheritHostTimezone != nil { + return *x.NoInheritHostTimezone + } + return false +} + +func (x *WindowsGuestOptions) GetAdditionalRegistryKeys() []*RegistryValue { + if x != nil { + return x.AdditionalRegistryKeys + } + return nil +} + +func (x *WindowsGuestOptions) GetForwardLogs() bool { + if x != nil && x.ForwardLogs != nil { + return *x.ForwardLogs + } + return false +} + +func (x *WindowsGuestOptions) GetLogSources() string { + if x != nil && x.LogSources != nil { + return *x.LogSources + } + return "" +} + +type RegistryKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Target hive. + Hive RegistryHive `protobuf:"varint,1,opt,name=hive,proto3,enum=containerd.runhcs.sandbox.v1.RegistryHive" json:"hive,omitempty"` + // Key path. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Volatile key flag. + Volatile bool `protobuf:"varint,3,opt,name=volatile,proto3" json:"volatile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegistryKey) Reset() { + *x = RegistryKey{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegistryKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegistryKey) ProtoMessage() {} + +func (x *RegistryKey) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegistryKey.ProtoReflect.Descriptor instead. +func (*RegistryKey) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{12} +} + +func (x *RegistryKey) GetHive() RegistryHive { + if x != nil { + return x.Hive + } + return RegistryHive_REGISTRY_HIVE_SYSTEM +} + +func (x *RegistryKey) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RegistryKey) GetVolatile() bool { + if x != nil { + return x.Volatile + } + return false +} + +type RegistryValue struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Value location (hive + key path). + Key *RegistryKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // Value name. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Value type. + Type RegistryValueType `protobuf:"varint,3,opt,name=type,proto3,enum=containerd.runhcs.sandbox.v1.RegistryValueType" json:"type,omitempty"` + // Typed payloads (one populated per type). + StringValue string `protobuf:"bytes,4,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"` + BinaryValue string `protobuf:"bytes,5,opt,name=binary_value,json=binaryValue,proto3" json:"binary_value,omitempty"` + DwordValue int32 `protobuf:"varint,6,opt,name=dword_value,json=dwordValue,proto3" json:"dword_value,omitempty"` + QwordValue int32 `protobuf:"varint,7,opt,name=qword_value,json=qwordValue,proto3" json:"qword_value,omitempty"` + CustomType int32 `protobuf:"varint,8,opt,name=custom_type,json=customType,proto3" json:"custom_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegistryValue) Reset() { + *x = RegistryValue{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegistryValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegistryValue) ProtoMessage() {} + +func (x *RegistryValue) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegistryValue.ProtoReflect.Descriptor instead. +func (*RegistryValue) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{13} +} + +func (x *RegistryValue) GetKey() *RegistryKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *RegistryValue) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RegistryValue) GetType() RegistryValueType { + if x != nil { + return x.Type + } + return RegistryValueType_REGISTRY_VALUE_TYPE_NONE +} + +func (x *RegistryValue) GetStringValue() string { + if x != nil { + return x.StringValue + } + return "" +} + +func (x *RegistryValue) GetBinaryValue() string { + if x != nil { + return x.BinaryValue + } + return "" +} + +func (x *RegistryValue) GetDwordValue() int32 { + if x != nil { + return x.DwordValue + } + return 0 +} + +func (x *RegistryValue) GetQwordValue() int32 { + if x != nil { + return x.QwordValue + } + return 0 +} + +func (x *RegistryValue) GetCustomType() int32 { + if x != nil { + return x.CustomType + } + return 0 +} + +type LinuxHyperVOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Boot configuration for LCOW UVM. + LinuxBootOptions *LinuxBootOptions `protobuf:"bytes,1,opt,name=linuxBootOptions,proto3" json:"linuxBootOptions,omitempty"` + // Guest configuration for LCOW UVM. + LinuxGuestOptions *LinuxGuestOptions `protobuf:"bytes,2,opt,name=linuxGuestOptions,proto3" json:"linuxGuestOptions,omitempty"` + // Device configuration for LCOW UVM. + LinuxDeviceOptions *LinuxDeviceOptions `protobuf:"bytes,3,opt,name=linuxDeviceOptions,proto3" json:"linuxDeviceOptions,omitempty"` + // Confidential computing options for LCOW. + ConfidentialOptions *LCOWConfidentialOptions `protobuf:"bytes,4,opt,name=confidentialOptions,proto3" json:"confidentialOptions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LinuxHyperVOptions) Reset() { + *x = LinuxHyperVOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LinuxHyperVOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LinuxHyperVOptions) ProtoMessage() {} + +func (x *LinuxHyperVOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LinuxHyperVOptions.ProtoReflect.Descriptor instead. +func (*LinuxHyperVOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{14} +} + +func (x *LinuxHyperVOptions) GetLinuxBootOptions() *LinuxBootOptions { + if x != nil { + return x.LinuxBootOptions + } + return nil +} + +func (x *LinuxHyperVOptions) GetLinuxGuestOptions() *LinuxGuestOptions { + if x != nil { + return x.LinuxGuestOptions + } + return nil +} + +func (x *LinuxHyperVOptions) GetLinuxDeviceOptions() *LinuxDeviceOptions { + if x != nil { + return x.LinuxDeviceOptions + } + return nil +} + +func (x *LinuxHyperVOptions) GetConfidentialOptions() *LCOWConfidentialOptions { + if x != nil { + return x.ConfidentialOptions + } + return nil +} + +type LinuxBootOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Root path for LCOW boot files. + BootFilesPath *string `protobuf:"bytes,1,opt,name=boot_files_path,json=bootFilesPath,proto3,oneof" json:"boot_files_path,omitempty"` + // Boot directly to kernel (skip UEFI). + KernelDirect *bool `protobuf:"varint,2,opt,name=kernel_direct,json=kernelDirect,proto3,oneof" json:"kernel_direct,omitempty"` + // Extra kernel cmdline options. + KernelBootOptions *string `protobuf:"bytes,3,opt,name=kernel_boot_options,json=kernelBootOptions,proto3,oneof" json:"kernel_boot_options,omitempty"` + // Preferred rootfs type selection (INITRD/VHD). + PreferredRootFsType *PreferredRootFSType `protobuf:"varint,4,opt,name=preferred_root_fs_type,json=preferredRootFsType,proto3,enum=containerd.runhcs.sandbox.v1.PreferredRootFSType,oneof" json:"preferred_root_fs_type,omitempty"` + // Enable cold discard hint for trimming non‑zeroed pages. + EnableColdDiscardHint *bool `protobuf:"varint,5,opt,name=enable_cold_discard_hint,json=enableColdDiscardHint,proto3,oneof" json:"enable_cold_discard_hint,omitempty"` + // Host Compatibility Layer toggle (presence-aware). + HclEnabled *bool `protobuf:"varint,6,opt,name=hcl_enabled,json=hclEnabled,proto3,oneof" json:"hcl_enabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LinuxBootOptions) Reset() { + *x = LinuxBootOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LinuxBootOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LinuxBootOptions) ProtoMessage() {} + +func (x *LinuxBootOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LinuxBootOptions.ProtoReflect.Descriptor instead. +func (*LinuxBootOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{15} +} + +func (x *LinuxBootOptions) GetBootFilesPath() string { + if x != nil && x.BootFilesPath != nil { + return *x.BootFilesPath + } + return "" +} + +func (x *LinuxBootOptions) GetKernelDirect() bool { + if x != nil && x.KernelDirect != nil { + return *x.KernelDirect + } + return false +} + +func (x *LinuxBootOptions) GetKernelBootOptions() string { + if x != nil && x.KernelBootOptions != nil { + return *x.KernelBootOptions + } + return "" +} + +func (x *LinuxBootOptions) GetPreferredRootFsType() PreferredRootFSType { + if x != nil && x.PreferredRootFsType != nil { + return *x.PreferredRootFsType + } + return PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_INITRD +} + +func (x *LinuxBootOptions) GetEnableColdDiscardHint() bool { + if x != nil && x.EnableColdDiscardHint != nil { + return *x.EnableColdDiscardHint + } + return false +} + +func (x *LinuxBootOptions) GetHclEnabled() bool { + if x != nil && x.HclEnabled != nil { + return *x.HclEnabled + } + return false +} + +type LinuxGuestOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Disable LCOW time-sync service. + DisableTimeSyncService *bool `protobuf:"varint,1,opt,name=disable_time_sync_service,json=disableTimeSyncService,proto3,oneof" json:"disable_time_sync_service,omitempty"` + // Extra vsock ports to expose. + ExtraVsockPorts []uint32 `protobuf:"varint,2,rep,packed,name=extra_vsock_ports,json=extraVsockPorts,proto3" json:"extra_vsock_ports,omitempty"` + // Enable policy-based routing in guest. + PolicyBasedRouting *bool `protobuf:"varint,3,opt,name=policy_based_routing,json=policyBasedRouting,proto3,oneof" json:"policy_based_routing,omitempty"` + // Allow writable overlays for /var and /etc. + WritableOverlayDirs *bool `protobuf:"varint,4,opt,name=writable_overlay_dirs,json=writableOverlayDirs,proto3,oneof" json:"writable_overlay_dirs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LinuxGuestOptions) Reset() { + *x = LinuxGuestOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LinuxGuestOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LinuxGuestOptions) ProtoMessage() {} + +func (x *LinuxGuestOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LinuxGuestOptions.ProtoReflect.Descriptor instead. +func (*LinuxGuestOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{16} +} + +func (x *LinuxGuestOptions) GetDisableTimeSyncService() bool { + if x != nil && x.DisableTimeSyncService != nil { + return *x.DisableTimeSyncService + } + return false +} + +func (x *LinuxGuestOptions) GetExtraVsockPorts() []uint32 { + if x != nil { + return x.ExtraVsockPorts + } + return nil +} + +func (x *LinuxGuestOptions) GetPolicyBasedRouting() bool { + if x != nil && x.PolicyBasedRouting != nil { + return *x.PolicyBasedRouting + } + return false +} + +func (x *LinuxGuestOptions) GetWritableOverlayDirs() bool { + if x != nil && x.WritableOverlayDirs != nil { + return *x.WritableOverlayDirs + } + return false +} + +type LinuxDeviceOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Max vPMem device count. + VpMemDeviceCount *uint32 `protobuf:"varint,1,opt,name=vp_mem_device_count,json=vpMemDeviceCount,proto3,oneof" json:"vp_mem_device_count,omitempty"` + // vPMem device size (bytes). + VpMemSizeBytes *uint64 `protobuf:"varint,2,opt,name=vp_mem_size_bytes,json=vpMemSizeBytes,proto3,oneof" json:"vp_mem_size_bytes,omitempty"` + // Disable LCOW vPMem layer multi-mapping. + VpMemNoMultiMapping *bool `protobuf:"varint,3,opt,name=vp_mem_no_multi_mapping,json=vpMemNoMultiMapping,proto3,oneof" json:"vp_mem_no_multi_mapping,omitempty"` + // Enable PCI support in LCOW kernel. + VpciEnabled *bool `protobuf:"varint,4,opt,name=vpci_enabled,json=vpciEnabled,proto3,oneof" json:"vpci_enabled,omitempty"` + // Assigned devices (e.g., SR-IOV). + AssignedDevices []*Device `protobuf:"bytes,5,rep,name=assigned_devices,json=assignedDevices,proto3" json:"assigned_devices,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LinuxDeviceOptions) Reset() { + *x = LinuxDeviceOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LinuxDeviceOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LinuxDeviceOptions) ProtoMessage() {} + +func (x *LinuxDeviceOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LinuxDeviceOptions.ProtoReflect.Descriptor instead. +func (*LinuxDeviceOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{17} +} + +func (x *LinuxDeviceOptions) GetVpMemDeviceCount() uint32 { + if x != nil && x.VpMemDeviceCount != nil { + return *x.VpMemDeviceCount + } + return 0 +} + +func (x *LinuxDeviceOptions) GetVpMemSizeBytes() uint64 { + if x != nil && x.VpMemSizeBytes != nil { + return *x.VpMemSizeBytes + } + return 0 +} + +func (x *LinuxDeviceOptions) GetVpMemNoMultiMapping() bool { + if x != nil && x.VpMemNoMultiMapping != nil { + return *x.VpMemNoMultiMapping + } + return false +} + +func (x *LinuxDeviceOptions) GetVpciEnabled() bool { + if x != nil && x.VpciEnabled != nil { + return *x.VpciEnabled + } + return false +} + +func (x *LinuxDeviceOptions) GetAssignedDevices() []*Device { + if x != nil { + return x.AssignedDevices + } + return nil +} + +type Device struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Device identifier: interface class GUID, etc. + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Device identifier type: "class", etc. + IdType string `protobuf:"bytes,2,opt,name=id_type,json=idType,proto3" json:"id_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Device) Reset() { + *x = Device{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Device) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Device) ProtoMessage() {} + +func (x *Device) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Device.ProtoReflect.Descriptor instead. +func (*Device) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{18} +} + +func (x *Device) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *Device) GetIdType() string { + if x != nil { + return x.IdType + } + return "" +} + +type ConfidentialOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Guest state file (VMGS) path used by confidential UVM modes. + GuestStateFile *string `protobuf:"bytes,1,opt,name=guest_state_file,json=guestStateFile,proto3,oneof" json:"guest_state_file,omitempty"` + // Security policy to enforce inside the guest. + SecurityPolicy *string `protobuf:"bytes,2,opt,name=security_policy,json=securityPolicy,proto3,oneof" json:"security_policy,omitempty"` + // Security policy enforcer selection ("open-door", "standard", "rego"). + SecurityPolicyEnforcer *string `protobuf:"bytes,3,opt,name=security_policy_enforcer,json=securityPolicyEnforcer,proto3,oneof" json:"security_policy_enforcer,omitempty"` + // Signed UVM reference info file passed to guest. + UvmReferenceInfoFile *string `protobuf:"bytes,4,opt,name=uvm_reference_info_file,json=uvmReferenceInfoFile,proto3,oneof" json:"uvm_reference_info_file,omitempty"` + // no_security_hardware allows to do testing and development without requiring SNP hardware. + NoSecurityHardware *bool `protobuf:"varint,5,opt,name=no_security_hardware,json=noSecurityHardware,proto3,oneof" json:"no_security_hardware,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConfidentialOptions) Reset() { + *x = ConfidentialOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfidentialOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfidentialOptions) ProtoMessage() {} + +func (x *ConfidentialOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConfidentialOptions.ProtoReflect.Descriptor instead. +func (*ConfidentialOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{19} +} + +func (x *ConfidentialOptions) GetGuestStateFile() string { + if x != nil && x.GuestStateFile != nil { + return *x.GuestStateFile + } + return "" +} + +func (x *ConfidentialOptions) GetSecurityPolicy() string { + if x != nil && x.SecurityPolicy != nil { + return *x.SecurityPolicy + } + return "" +} + +func (x *ConfidentialOptions) GetSecurityPolicyEnforcer() string { + if x != nil && x.SecurityPolicyEnforcer != nil { + return *x.SecurityPolicyEnforcer + } + return "" +} + +func (x *ConfidentialOptions) GetUvmReferenceInfoFile() string { + if x != nil && x.UvmReferenceInfoFile != nil { + return *x.UvmReferenceInfoFile + } + return "" +} + +func (x *ConfidentialOptions) GetNoSecurityHardware() bool { + if x != nil && x.NoSecurityHardware != nil { + return *x.NoSecurityHardware + } + return false +} + +type LCOWConfidentialOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // LCOW common confidential options. + Options *ConfidentialOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` + // Rootfs VHD path with dm-verity metadata (SNP mode). + DmVerityRootFsVhd *string `protobuf:"bytes,2,opt,name=dm_verity_root_fs_vhd,json=dmVerityRootFsVhd,proto3,oneof" json:"dm_verity_root_fs_vhd,omitempty"` + // Enable dm-verity presentation of rootfs (standalone SCSI attachment). + DmVerityMode *bool `protobuf:"varint,3,opt,name=dm_verity_mode,json=dmVerityMode,proto3,oneof" json:"dm_verity_mode,omitempty"` + // dm-mod.create parameters for rootfs integrity. + DmVerityCreateArgs *string `protobuf:"bytes,4,opt,name=dm_verity_create_args,json=dmVerityCreateArgs,proto3,oneof" json:"dm_verity_create_args,omitempty"` + // Encrypt LCOW scratch disks. + EnableScratchEncryption *bool `protobuf:"varint,5,opt,name=enable_scratch_encryption,json=enableScratchEncryption,proto3,oneof" json:"enable_scratch_encryption,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LCOWConfidentialOptions) Reset() { + *x = LCOWConfidentialOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LCOWConfidentialOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LCOWConfidentialOptions) ProtoMessage() {} + +func (x *LCOWConfidentialOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LCOWConfidentialOptions.ProtoReflect.Descriptor instead. +func (*LCOWConfidentialOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{20} +} + +func (x *LCOWConfidentialOptions) GetOptions() *ConfidentialOptions { + if x != nil { + return x.Options + } + return nil +} + +func (x *LCOWConfidentialOptions) GetDmVerityRootFsVhd() string { + if x != nil && x.DmVerityRootFsVhd != nil { + return *x.DmVerityRootFsVhd + } + return "" +} + +func (x *LCOWConfidentialOptions) GetDmVerityMode() bool { + if x != nil && x.DmVerityMode != nil { + return *x.DmVerityMode + } + return false +} + +func (x *LCOWConfidentialOptions) GetDmVerityCreateArgs() string { + if x != nil && x.DmVerityCreateArgs != nil { + return *x.DmVerityCreateArgs + } + return "" +} + +func (x *LCOWConfidentialOptions) GetEnableScratchEncryption() bool { + if x != nil && x.EnableScratchEncryption != nil { + return *x.EnableScratchEncryption + } + return false +} + +type WCOWConfidentialOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // WCOW common confidential options. + Options *ConfidentialOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` + // Disable secure boot (WCOW-only; testing/debugging). + DisableSecureBoot *bool `protobuf:"varint,2,opt,name=disable_secure_boot,json=disableSecureBoot,proto3,oneof" json:"disable_secure_boot,omitempty"` + // Attach EFI/boot VHD in writable mode (capture boot traces). + WritableEfi *bool `protobuf:"varint,3,opt,name=writable_efi,json=writableEfi,proto3,oneof" json:"writable_efi,omitempty"` + // allows overriding isolation type of a confidential pod. + IsolationType *string `protobuf:"bytes,4,opt,name=isolation_type,json=isolationType,proto3,oneof" json:"isolation_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WCOWConfidentialOptions) Reset() { + *x = WCOWConfidentialOptions{} + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WCOWConfidentialOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WCOWConfidentialOptions) ProtoMessage() {} + +func (x *WCOWConfidentialOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WCOWConfidentialOptions.ProtoReflect.Descriptor instead. +func (*WCOWConfidentialOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP(), []int{21} +} + +func (x *WCOWConfidentialOptions) GetOptions() *ConfidentialOptions { + if x != nil { + return x.Options + } + return nil +} + +func (x *WCOWConfidentialOptions) GetDisableSecureBoot() bool { + if x != nil && x.DisableSecureBoot != nil { + return *x.DisableSecureBoot + } + return false +} + +func (x *WCOWConfidentialOptions) GetWritableEfi() bool { + if x != nil && x.WritableEfi != nil { + return *x.WritableEfi + } + return false +} + +func (x *WCOWConfidentialOptions) GetIsolationType() string { + if x != nil && x.IsolationType != nil { + return *x.IsolationType + } + return "" +} + +var File_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto protoreflect.FileDescriptor + +const file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDesc = "" + + "\n" + + "Tgithub.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.proto\x12\x1ccontainerd.runhcs.sandbox.v1\"\xb9\x01\n" + + "\x05Specs\x12I\n" + + "\aprocess\x18\x01 \x01(\v2-.containerd.runhcs.sandbox.v1.ProcessIsolatedH\x00R\aprocess\x12R\n" + + "\n" + + "hypervisor\x18\x02 \x01(\v20.containerd.runhcs.sandbox.v1.HypervisorIsolatedH\x00R\n" + + "hypervisorB\x11\n" + + "\x0fisolation_level\"\x11\n" + + "\x0fProcessIsolated\"\xcd\x05\n" + + "\x12HypervisorIsolated\x12F\n" + + "\x04lcow\x18\x01 \x01(\v20.containerd.runhcs.sandbox.v1.LinuxHyperVOptionsH\x00R\x04lcow\x12H\n" + + "\x04wcow\x18\x02 \x01(\v22.containerd.runhcs.sandbox.v1.WindowsHyperVOptionsH\x00R\x04wcow\x12E\n" + + "\tcpuConfig\x18\x03 \x01(\v2'.containerd.runhcs.sandbox.v1.CPUConfigR\tcpuConfig\x12N\n" + + "\fmemoryConfig\x18\x04 \x01(\v2*.containerd.runhcs.sandbox.v1.MemoryConfigR\fmemoryConfig\x12Q\n" + + "\rstorageConfig\x18\x05 \x01(\v2+.containerd.runhcs.sandbox.v1.StorageConfigR\rstorageConfig\x12H\n" + + "\n" + + "numaConfig\x18\x06 \x01(\v2(.containerd.runhcs.sandbox.v1.NUMAConfigR\n" + + "numaConfig\x12Z\n" + + "\x10additionalConfig\x18\a \x01(\v2..containerd.runhcs.sandbox.v1.AdditionalConfigR\x10additionalConfig\x12%\n" + + "\fcpu_group_id\x18\b \x01(\tH\x01R\n" + + "cpuGroupId\x88\x01\x01\x127\n" + + "\x15resource_partition_id\x18\t \x01(\tH\x02R\x13resourcePartitionId\x88\x01\x01B\n" + + "\n" + + "\bplatformB\x0f\n" + + "\r_cpu_group_idB\x18\n" + + "\x16_resource_partition_id\"\x8e\x02\n" + + "\tCPUConfig\x12,\n" + + "\x0fprocessor_count\x18\x01 \x01(\x05H\x00R\x0eprocessorCount\x88\x01\x01\x12,\n" + + "\x0fprocessor_limit\x18\x02 \x01(\x05H\x01R\x0eprocessorLimit\x88\x01\x01\x12.\n" + + "\x10processor_weight\x18\x03 \x01(\x05H\x02R\x0fprocessorWeight\x88\x01\x01\x12'\n" + + "\farchitecture\x18\x04 \x01(\tH\x03R\farchitecture\x88\x01\x01B\x12\n" + + "\x10_processor_countB\x12\n" + + "\x10_processor_limitB\x13\n" + + "\x11_processor_weightB\x0f\n" + + "\r_architecture\"\xa9\x04\n" + + "\fMemoryConfig\x12.\n" + + "\x11memory_size_in_mb\x18\x01 \x01(\x04H\x00R\x0ememorySizeInMb\x88\x01\x01\x12/\n" + + "\x12low_mmio_gap_in_mb\x18\x02 \x01(\x04H\x01R\x0elowMmioGapInMb\x88\x01\x01\x123\n" + + "\x14high_mmio_base_in_mb\x18\x03 \x01(\x04H\x02R\x10highMmioBaseInMb\x88\x01\x01\x121\n" + + "\x13high_mmio_gap_in_mb\x18\x04 \x01(\x04H\x03R\x0fhighMmioGapInMb\x88\x01\x01\x12.\n" + + "\x10allow_overcommit\x18\x05 \x01(\bH\x04R\x0fallowOvercommit\x88\x01\x01\x12;\n" + + "\x17fully_physically_backed\x18\x06 \x01(\bH\x05R\x15fullyPhysicallyBacked\x88\x01\x01\x129\n" + + "\x16enable_deferred_commit\x18\a \x01(\bH\x06R\x14enableDeferredCommit\x88\x01\x01B\x14\n" + + "\x12_memory_size_in_mbB\x15\n" + + "\x13_low_mmio_gap_in_mbB\x17\n" + + "\x15_high_mmio_base_in_mbB\x16\n" + + "\x14_high_mmio_gap_in_mbB\x13\n" + + "\x11_allow_overcommitB\x1a\n" + + "\x18_fully_physically_backedB\x19\n" + + "\x17_enable_deferred_commit\"\xac\x02\n" + + "\rStorageConfig\x12<\n" + + "\x18storage_qos_iops_maximum\x18\x01 \x01(\x05H\x00R\x15storageQosIopsMaximum\x88\x01\x01\x12F\n" + + "\x1dstorage_qos_bandwidth_maximum\x18\x02 \x01(\x05H\x01R\x1astorageQosBandwidthMaximum\x88\x01\x01\x12:\n" + + "\x17no_writable_file_shares\x18\x03 \x01(\bH\x02R\x14noWritableFileShares\x88\x01\x01B\x1b\n" + + "\x19_storage_qos_iops_maximumB \n" + + "\x1e_storage_qos_bandwidth_maximumB\x1a\n" + + "\x18_no_writable_file_shares\"\xc9\x03\n" + + "\n" + + "NUMAConfig\x12D\n" + + "\x1dmax_memory_size_per_numa_node\x18\x01 \x01(\x04H\x00R\x18maxMemorySizePerNumaNode\x88\x01\x01\x12C\n" + + "\x1cmax_processors_per_numa_node\x18\x02 \x01(\rH\x01R\x18maxProcessorsPerNumaNode\x88\x01\x01\x12A\n" + + "\x1dpreferred_physical_numa_nodes\x18\x03 \x03(\rR\x1apreferredPhysicalNumaNodes\x12;\n" + + "\x1anuma_mapped_physical_nodes\x18\x04 \x03(\rR\x17numaMappedPhysicalNodes\x122\n" + + "\x15numa_processor_counts\x18\x05 \x03(\rR\x13numaProcessorCounts\x129\n" + + "\x19numa_memory_blocks_counts\x18\x06 \x03(\x04R\x16numaMemoryBlocksCountsB \n" + + "\x1e_max_memory_size_per_numa_nodeB\x1f\n" + + "\x1d_max_processors_per_numa_node\"\xc2\x04\n" + + "\x10AdditionalConfig\x125\n" + + "\x14network_config_proxy\x18\x01 \x01(\tH\x00R\x12networkConfigProxy\x88\x01\x01\x127\n" + + "\x15process_dump_location\x18\x02 \x01(\tH\x01R\x13processDumpLocation\x88\x01\x01\x123\n" + + "\x13dump_directory_path\x18\x03 \x01(\tH\x02R\x11dumpDirectoryPath\x88\x01\x01\x12\x84\x01\n" + + "\x18additional_hyperv_config\x18\x04 \x03(\v2J.containerd.runhcs.sandbox.v1.AdditionalConfig.AdditionalHypervConfigEntryR\x16additionalHypervConfig\x12&\n" + + "\fconsole_pipe\x18\x05 \x01(\tH\x03R\vconsolePipe\x88\x01\x01\x1a~\n" + + "\x1bAdditionalHypervConfigEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12I\n" + + "\x05value\x18\x02 \x01(\v23.containerd.runhcs.sandbox.v1.HvSocketServiceConfigR\x05value:\x028\x01B\x17\n" + + "\x15_network_config_proxyB\x18\n" + + "\x16_process_dump_locationB\x16\n" + + "\x14_dump_directory_pathB\x0f\n" + + "\r_console_pipe\"\xd6\x02\n" + + "\x15HvSocketServiceConfig\x12=\n" + + "\x18bind_security_descriptor\x18\x01 \x01(\tH\x00R\x16bindSecurityDescriptor\x88\x01\x01\x12C\n" + + "\x1bconnect_security_descriptor\x18\x02 \x01(\tH\x01R\x19connectSecurityDescriptor\x88\x01\x01\x125\n" + + "\x14allow_wildcard_binds\x18\x03 \x01(\bH\x02R\x12allowWildcardBinds\x88\x01\x01\x12\x1f\n" + + "\bdisabled\x18\x04 \x01(\bH\x03R\bdisabled\x88\x01\x01B\x1b\n" + + "\x19_bind_security_descriptorB\x1e\n" + + "\x1c_connect_security_descriptorB\x17\n" + + "\x15_allow_wildcard_bindsB\v\n" + + "\t_disabled\"\xc6\x02\n" + + "\x14WindowsHyperVOptions\x12`\n" + + "\x12windowsBootOptions\x18\x01 \x01(\v20.containerd.runhcs.sandbox.v1.WindowsBootOptionsR\x12windowsBootOptions\x12c\n" + + "\x13windowsGuestOptions\x18\x02 \x01(\v21.containerd.runhcs.sandbox.v1.WindowsGuestOptionsR\x13windowsGuestOptions\x12g\n" + + "\x13confidentialOptions\x18\x03 \x01(\v25.containerd.runhcs.sandbox.v1.WCOWConfidentialOptionsR\x13confidentialOptions\"\xba\x01\n" + + "\x12WindowsBootOptions\x12G\n" + + "\x1ddisable_compartment_namespace\x18\x01 \x01(\bH\x00R\x1bdisableCompartmentNamespace\x88\x01\x01\x12'\n" + + "\rno_direct_map\x18\x02 \x01(\bH\x01R\vnoDirectMap\x88\x01\x01B \n" + + "\x1e_disable_compartment_namespaceB\x10\n" + + "\x0e_no_direct_map\"\xc6\x02\n" + + "\x13WindowsGuestOptions\x12<\n" + + "\x18no_inherit_host_timezone\x18\x01 \x01(\bH\x00R\x15noInheritHostTimezone\x88\x01\x01\x12e\n" + + "\x18additional_registry_keys\x18\x02 \x03(\v2+.containerd.runhcs.sandbox.v1.RegistryValueR\x16additionalRegistryKeys\x12&\n" + + "\fforward_logs\x18\x03 \x01(\bH\x01R\vforwardLogs\x88\x01\x01\x12$\n" + + "\vlog_sources\x18\x04 \x01(\tH\x02R\n" + + "logSources\x88\x01\x01B\x1b\n" + + "\x19_no_inherit_host_timezoneB\x0f\n" + + "\r_forward_logsB\x0e\n" + + "\f_log_sources\"}\n" + + "\vRegistryKey\x12>\n" + + "\x04hive\x18\x01 \x01(\x0e2*.containerd.runhcs.sandbox.v1.RegistryHiveR\x04hive\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1a\n" + + "\bvolatile\x18\x03 \x01(\bR\bvolatile\"\xce\x02\n" + + "\rRegistryValue\x12;\n" + + "\x03key\x18\x01 \x01(\v2).containerd.runhcs.sandbox.v1.RegistryKeyR\x03key\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12C\n" + + "\x04type\x18\x03 \x01(\x0e2/.containerd.runhcs.sandbox.v1.RegistryValueTypeR\x04type\x12!\n" + + "\fstring_value\x18\x04 \x01(\tR\vstringValue\x12!\n" + + "\fbinary_value\x18\x05 \x01(\tR\vbinaryValue\x12\x1f\n" + + "\vdword_value\x18\x06 \x01(\x05R\n" + + "dwordValue\x12\x1f\n" + + "\vqword_value\x18\a \x01(\x05R\n" + + "qwordValue\x12\x1f\n" + + "\vcustom_type\x18\b \x01(\x05R\n" + + "customType\"\x9a\x03\n" + + "\x12LinuxHyperVOptions\x12Z\n" + + "\x10linuxBootOptions\x18\x01 \x01(\v2..containerd.runhcs.sandbox.v1.LinuxBootOptionsR\x10linuxBootOptions\x12]\n" + + "\x11linuxGuestOptions\x18\x02 \x01(\v2/.containerd.runhcs.sandbox.v1.LinuxGuestOptionsR\x11linuxGuestOptions\x12`\n" + + "\x12linuxDeviceOptions\x18\x03 \x01(\v20.containerd.runhcs.sandbox.v1.LinuxDeviceOptionsR\x12linuxDeviceOptions\x12g\n" + + "\x13confidentialOptions\x18\x04 \x01(\v25.containerd.runhcs.sandbox.v1.LCOWConfidentialOptionsR\x13confidentialOptions\"\xf5\x03\n" + + "\x10LinuxBootOptions\x12+\n" + + "\x0fboot_files_path\x18\x01 \x01(\tH\x00R\rbootFilesPath\x88\x01\x01\x12(\n" + + "\rkernel_direct\x18\x02 \x01(\bH\x01R\fkernelDirect\x88\x01\x01\x123\n" + + "\x13kernel_boot_options\x18\x03 \x01(\tH\x02R\x11kernelBootOptions\x88\x01\x01\x12k\n" + + "\x16preferred_root_fs_type\x18\x04 \x01(\x0e21.containerd.runhcs.sandbox.v1.PreferredRootFSTypeH\x03R\x13preferredRootFsType\x88\x01\x01\x12<\n" + + "\x18enable_cold_discard_hint\x18\x05 \x01(\bH\x04R\x15enableColdDiscardHint\x88\x01\x01\x12$\n" + + "\vhcl_enabled\x18\x06 \x01(\bH\x05R\n" + + "hclEnabled\x88\x01\x01B\x12\n" + + "\x10_boot_files_pathB\x10\n" + + "\x0e_kernel_directB\x16\n" + + "\x14_kernel_boot_optionsB\x19\n" + + "\x17_preferred_root_fs_typeB\x1b\n" + + "\x19_enable_cold_discard_hintB\x0e\n" + + "\f_hcl_enabled\"\xc0\x02\n" + + "\x11LinuxGuestOptions\x12>\n" + + "\x19disable_time_sync_service\x18\x01 \x01(\bH\x00R\x16disableTimeSyncService\x88\x01\x01\x12*\n" + + "\x11extra_vsock_ports\x18\x02 \x03(\rR\x0fextraVsockPorts\x125\n" + + "\x14policy_based_routing\x18\x03 \x01(\bH\x01R\x12policyBasedRouting\x88\x01\x01\x127\n" + + "\x15writable_overlay_dirs\x18\x04 \x01(\bH\x02R\x13writableOverlayDirs\x88\x01\x01B\x1c\n" + + "\x1a_disable_time_sync_serviceB\x17\n" + + "\x15_policy_based_routingB\x18\n" + + "\x16_writable_overlay_dirs\"\x87\x03\n" + + "\x12LinuxDeviceOptions\x122\n" + + "\x13vp_mem_device_count\x18\x01 \x01(\rH\x00R\x10vpMemDeviceCount\x88\x01\x01\x12.\n" + + "\x11vp_mem_size_bytes\x18\x02 \x01(\x04H\x01R\x0evpMemSizeBytes\x88\x01\x01\x129\n" + + "\x17vp_mem_no_multi_mapping\x18\x03 \x01(\bH\x02R\x13vpMemNoMultiMapping\x88\x01\x01\x12&\n" + + "\fvpci_enabled\x18\x04 \x01(\bH\x03R\vvpciEnabled\x88\x01\x01\x12O\n" + + "\x10assigned_devices\x18\x05 \x03(\v2$.containerd.runhcs.sandbox.v1.DeviceR\x0fassignedDevicesB\x16\n" + + "\x14_vp_mem_device_countB\x14\n" + + "\x12_vp_mem_size_bytesB\x1a\n" + + "\x18_vp_mem_no_multi_mappingB\x0f\n" + + "\r_vpci_enabled\"1\n" + + "\x06Device\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x17\n" + + "\aid_type\x18\x02 \x01(\tR\x06idType\"\x9f\x03\n" + + "\x13ConfidentialOptions\x12-\n" + + "\x10guest_state_file\x18\x01 \x01(\tH\x00R\x0eguestStateFile\x88\x01\x01\x12,\n" + + "\x0fsecurity_policy\x18\x02 \x01(\tH\x01R\x0esecurityPolicy\x88\x01\x01\x12=\n" + + "\x18security_policy_enforcer\x18\x03 \x01(\tH\x02R\x16securityPolicyEnforcer\x88\x01\x01\x12:\n" + + "\x17uvm_reference_info_file\x18\x04 \x01(\tH\x03R\x14uvmReferenceInfoFile\x88\x01\x01\x125\n" + + "\x14no_security_hardware\x18\x05 \x01(\bH\x04R\x12noSecurityHardware\x88\x01\x01B\x13\n" + + "\x11_guest_state_fileB\x12\n" + + "\x10_security_policyB\x1b\n" + + "\x19_security_policy_enforcerB\x1a\n" + + "\x18_uvm_reference_info_fileB\x17\n" + + "\x15_no_security_hardware\"\xa6\x03\n" + + "\x17LCOWConfidentialOptions\x12K\n" + + "\aoptions\x18\x01 \x01(\v21.containerd.runhcs.sandbox.v1.ConfidentialOptionsR\aoptions\x125\n" + + "\x15dm_verity_root_fs_vhd\x18\x02 \x01(\tH\x00R\x11dmVerityRootFsVhd\x88\x01\x01\x12)\n" + + "\x0edm_verity_mode\x18\x03 \x01(\bH\x01R\fdmVerityMode\x88\x01\x01\x126\n" + + "\x15dm_verity_create_args\x18\x04 \x01(\tH\x02R\x12dmVerityCreateArgs\x88\x01\x01\x12?\n" + + "\x19enable_scratch_encryption\x18\x05 \x01(\bH\x03R\x17enableScratchEncryption\x88\x01\x01B\x18\n" + + "\x16_dm_verity_root_fs_vhdB\x11\n" + + "\x0f_dm_verity_modeB\x18\n" + + "\x16_dm_verity_create_argsB\x1c\n" + + "\x1a_enable_scratch_encryption\"\xab\x02\n" + + "\x17WCOWConfidentialOptions\x12K\n" + + "\aoptions\x18\x01 \x01(\v21.containerd.runhcs.sandbox.v1.ConfidentialOptionsR\aoptions\x123\n" + + "\x13disable_secure_boot\x18\x02 \x01(\bH\x00R\x11disableSecureBoot\x88\x01\x01\x12&\n" + + "\fwritable_efi\x18\x03 \x01(\bH\x01R\vwritableEfi\x88\x01\x01\x12*\n" + + "\x0eisolation_type\x18\x04 \x01(\tH\x02R\risolationType\x88\x01\x01B\x16\n" + + "\x14_disable_secure_bootB\x0f\n" + + "\r_writable_efiB\x11\n" + + "\x0f_isolation_type*w\n" + + "\fRegistryHive\x12\x18\n" + + "\x14REGISTRY_HIVE_SYSTEM\x10\x00\x12\x1a\n" + + "\x16REGISTRY_HIVE_SOFTWARE\x10\x01\x12\x1a\n" + + "\x16REGISTRY_HIVE_SECURITY\x10\x02\x12\x15\n" + + "\x11REGISTRY_HIVE_SAM\x10\x03*\xa5\x02\n" + + "\x11RegistryValueType\x12\x1c\n" + + "\x18REGISTRY_VALUE_TYPE_NONE\x10\x00\x12\x1e\n" + + "\x1aREGISTRY_VALUE_TYPE_STRING\x10\x01\x12'\n" + + "#REGISTRY_VALUE_TYPE_EXPANDED_STRING\x10\x02\x12$\n" + + " REGISTRY_VALUE_TYPE_MULTI_STRING\x10\x03\x12\x1e\n" + + "\x1aREGISTRY_VALUE_TYPE_BINARY\x10\x04\x12\x1e\n" + + "\x1aREGISTRY_VALUE_TYPE_D_WORD\x10\x05\x12\x1e\n" + + "\x1aREGISTRY_VALUE_TYPE_Q_WORD\x10\x06\x12#\n" + + "\x1fREGISTRY_VALUE_TYPE_CUSTOM_TYPE\x10\a*X\n" + + "\x13PreferredRootFSType\x12!\n" + + "\x1dPREFERRED_ROOT_FS_TYPE_INITRD\x10\x00\x12\x1e\n" + + "\x1aPREFERRED_ROOT_FS_TYPE_VHD\x10\x01BHZFgithub.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/sandboxspecb\x06proto3" + +var ( + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescOnce sync.Once + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescData []byte +) + +func file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescGZIP() []byte { + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescOnce.Do(func() { + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDesc), len(file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDesc))) + }) + return file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDescData +} + +var file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_goTypes = []any{ + (RegistryHive)(0), // 0: containerd.runhcs.sandbox.v1.RegistryHive + (RegistryValueType)(0), // 1: containerd.runhcs.sandbox.v1.RegistryValueType + (PreferredRootFSType)(0), // 2: containerd.runhcs.sandbox.v1.PreferredRootFSType + (*Specs)(nil), // 3: containerd.runhcs.sandbox.v1.Specs + (*ProcessIsolated)(nil), // 4: containerd.runhcs.sandbox.v1.ProcessIsolated + (*HypervisorIsolated)(nil), // 5: containerd.runhcs.sandbox.v1.HypervisorIsolated + (*CPUConfig)(nil), // 6: containerd.runhcs.sandbox.v1.CPUConfig + (*MemoryConfig)(nil), // 7: containerd.runhcs.sandbox.v1.MemoryConfig + (*StorageConfig)(nil), // 8: containerd.runhcs.sandbox.v1.StorageConfig + (*NUMAConfig)(nil), // 9: containerd.runhcs.sandbox.v1.NUMAConfig + (*AdditionalConfig)(nil), // 10: containerd.runhcs.sandbox.v1.AdditionalConfig + (*HvSocketServiceConfig)(nil), // 11: containerd.runhcs.sandbox.v1.HvSocketServiceConfig + (*WindowsHyperVOptions)(nil), // 12: containerd.runhcs.sandbox.v1.WindowsHyperVOptions + (*WindowsBootOptions)(nil), // 13: containerd.runhcs.sandbox.v1.WindowsBootOptions + (*WindowsGuestOptions)(nil), // 14: containerd.runhcs.sandbox.v1.WindowsGuestOptions + (*RegistryKey)(nil), // 15: containerd.runhcs.sandbox.v1.RegistryKey + (*RegistryValue)(nil), // 16: containerd.runhcs.sandbox.v1.RegistryValue + (*LinuxHyperVOptions)(nil), // 17: containerd.runhcs.sandbox.v1.LinuxHyperVOptions + (*LinuxBootOptions)(nil), // 18: containerd.runhcs.sandbox.v1.LinuxBootOptions + (*LinuxGuestOptions)(nil), // 19: containerd.runhcs.sandbox.v1.LinuxGuestOptions + (*LinuxDeviceOptions)(nil), // 20: containerd.runhcs.sandbox.v1.LinuxDeviceOptions + (*Device)(nil), // 21: containerd.runhcs.sandbox.v1.Device + (*ConfidentialOptions)(nil), // 22: containerd.runhcs.sandbox.v1.ConfidentialOptions + (*LCOWConfidentialOptions)(nil), // 23: containerd.runhcs.sandbox.v1.LCOWConfidentialOptions + (*WCOWConfidentialOptions)(nil), // 24: containerd.runhcs.sandbox.v1.WCOWConfidentialOptions + nil, // 25: containerd.runhcs.sandbox.v1.AdditionalConfig.AdditionalHypervConfigEntry +} +var file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_depIdxs = []int32{ + 4, // 0: containerd.runhcs.sandbox.v1.Specs.process:type_name -> containerd.runhcs.sandbox.v1.ProcessIsolated + 5, // 1: containerd.runhcs.sandbox.v1.Specs.hypervisor:type_name -> containerd.runhcs.sandbox.v1.HypervisorIsolated + 17, // 2: containerd.runhcs.sandbox.v1.HypervisorIsolated.lcow:type_name -> containerd.runhcs.sandbox.v1.LinuxHyperVOptions + 12, // 3: containerd.runhcs.sandbox.v1.HypervisorIsolated.wcow:type_name -> containerd.runhcs.sandbox.v1.WindowsHyperVOptions + 6, // 4: containerd.runhcs.sandbox.v1.HypervisorIsolated.cpuConfig:type_name -> containerd.runhcs.sandbox.v1.CPUConfig + 7, // 5: containerd.runhcs.sandbox.v1.HypervisorIsolated.memoryConfig:type_name -> containerd.runhcs.sandbox.v1.MemoryConfig + 8, // 6: containerd.runhcs.sandbox.v1.HypervisorIsolated.storageConfig:type_name -> containerd.runhcs.sandbox.v1.StorageConfig + 9, // 7: containerd.runhcs.sandbox.v1.HypervisorIsolated.numaConfig:type_name -> containerd.runhcs.sandbox.v1.NUMAConfig + 10, // 8: containerd.runhcs.sandbox.v1.HypervisorIsolated.additionalConfig:type_name -> containerd.runhcs.sandbox.v1.AdditionalConfig + 25, // 9: containerd.runhcs.sandbox.v1.AdditionalConfig.additional_hyperv_config:type_name -> containerd.runhcs.sandbox.v1.AdditionalConfig.AdditionalHypervConfigEntry + 13, // 10: containerd.runhcs.sandbox.v1.WindowsHyperVOptions.windowsBootOptions:type_name -> containerd.runhcs.sandbox.v1.WindowsBootOptions + 14, // 11: containerd.runhcs.sandbox.v1.WindowsHyperVOptions.windowsGuestOptions:type_name -> containerd.runhcs.sandbox.v1.WindowsGuestOptions + 24, // 12: containerd.runhcs.sandbox.v1.WindowsHyperVOptions.confidentialOptions:type_name -> containerd.runhcs.sandbox.v1.WCOWConfidentialOptions + 16, // 13: containerd.runhcs.sandbox.v1.WindowsGuestOptions.additional_registry_keys:type_name -> containerd.runhcs.sandbox.v1.RegistryValue + 0, // 14: containerd.runhcs.sandbox.v1.RegistryKey.hive:type_name -> containerd.runhcs.sandbox.v1.RegistryHive + 15, // 15: containerd.runhcs.sandbox.v1.RegistryValue.key:type_name -> containerd.runhcs.sandbox.v1.RegistryKey + 1, // 16: containerd.runhcs.sandbox.v1.RegistryValue.type:type_name -> containerd.runhcs.sandbox.v1.RegistryValueType + 18, // 17: containerd.runhcs.sandbox.v1.LinuxHyperVOptions.linuxBootOptions:type_name -> containerd.runhcs.sandbox.v1.LinuxBootOptions + 19, // 18: containerd.runhcs.sandbox.v1.LinuxHyperVOptions.linuxGuestOptions:type_name -> containerd.runhcs.sandbox.v1.LinuxGuestOptions + 20, // 19: containerd.runhcs.sandbox.v1.LinuxHyperVOptions.linuxDeviceOptions:type_name -> containerd.runhcs.sandbox.v1.LinuxDeviceOptions + 23, // 20: containerd.runhcs.sandbox.v1.LinuxHyperVOptions.confidentialOptions:type_name -> containerd.runhcs.sandbox.v1.LCOWConfidentialOptions + 2, // 21: containerd.runhcs.sandbox.v1.LinuxBootOptions.preferred_root_fs_type:type_name -> containerd.runhcs.sandbox.v1.PreferredRootFSType + 21, // 22: containerd.runhcs.sandbox.v1.LinuxDeviceOptions.assigned_devices:type_name -> containerd.runhcs.sandbox.v1.Device + 22, // 23: containerd.runhcs.sandbox.v1.LCOWConfidentialOptions.options:type_name -> containerd.runhcs.sandbox.v1.ConfidentialOptions + 22, // 24: containerd.runhcs.sandbox.v1.WCOWConfidentialOptions.options:type_name -> containerd.runhcs.sandbox.v1.ConfidentialOptions + 11, // 25: containerd.runhcs.sandbox.v1.AdditionalConfig.AdditionalHypervConfigEntry.value:type_name -> containerd.runhcs.sandbox.v1.HvSocketServiceConfig + 26, // [26:26] is the sub-list for method output_type + 26, // [26:26] is the sub-list for method input_type + 26, // [26:26] is the sub-list for extension type_name + 26, // [26:26] is the sub-list for extension extendee + 0, // [0:26] is the sub-list for field type_name +} + +func init() { + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_init() +} +func file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_init() { + if File_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto != nil { + return + } + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[0].OneofWrappers = []any{ + (*Specs_Process)(nil), + (*Specs_Hypervisor)(nil), + } + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[2].OneofWrappers = []any{ + (*HypervisorIsolated_Lcow)(nil), + (*HypervisorIsolated_Wcow)(nil), + } + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[3].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[4].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[5].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[6].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[7].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[8].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[10].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[11].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[15].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[16].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[17].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[19].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[20].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes[21].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDesc), len(file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_rawDesc)), + NumEnums: 3, + NumMessages: 23, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_goTypes, + DependencyIndexes: file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_depIdxs, + EnumInfos: file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_enumTypes, + MessageInfos: file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_msgTypes, + }.Build() + File_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto = out.File + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_goTypes = nil + file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_sandboxspec_sandbox_proto_depIdxs = nil +} diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.proto b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.proto new file mode 100644 index 0000000000..4302e41514 --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox.proto @@ -0,0 +1,439 @@ +syntax = "proto3"; + +package containerd.runhcs.sandbox.v1; + +option go_package = "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/sandboxspec"; + +// ---------------------------------------------------------------------------- +// High-level proto structure for sandbox options +// These options are used to define a sandbox for all types of pods. +// ---------------------------------------------------------------------------- +// +// Specs +// ├─ isolation_level (oneof) +// │ ├─ ProcessIsolated +// │ └─ HypervisorIsolated +// │ ├─ platform (oneof) +// │ │ ├─ LinuxHyperVOptions +// │ │ └─ WindowsHyperVOptions +// │ ├─ CPUConfig +// │ ├─ MemoryConfig +// │ ├─ StorageConfig +// │ ├─ NUMAConfig +// │ └─ AdditionalConfig +// │ └─ cpu_group_id +// │ └─ resource_partition_id +// +// LinuxHyperVOptions +// ├─ LinuxBootOptions +// ├─ LinuxGuestOptions +// ├─ LinuxDeviceOptions +// └─ LCOWConfidentialOptions +// +// WindowsHyperVOptions +// ├─ WindowsBootOptions +// ├─ WindowsGuestOptions +// └─ WCOWConfidentialOptions +// +// AdditionalConfig +// └─ HvSocketServiceConfig (map) +// +// Confidential options +// ├─ LCOWConfidentialOptions → ConfidentialOptions +// └─ WCOWConfidentialOptions → ConfidentialOptions +// + +// ---------------------------------------------------------------------------- +// Top-level Sandbox specification +// ---------------------------------------------------------------------------- + +message Specs { + // Sandbox isolation mode. + oneof isolation_level { + // Process-isolated sandbox (no UVM). + ProcessIsolated process = 1; + // Hypervisor-isolated sandbox (UVM-backed). + HypervisorIsolated hypervisor = 2; + } +} + +// ---------------------------------------------------------------------------- +// Process-isolated sandbox +// ---------------------------------------------------------------------------- + +message ProcessIsolated { + // No options for process isolation as of now; +} + +// ---------------------------------------------------------------------------- +// Hypervisor-isolated sandbox (UVM-backed) +// ---------------------------------------------------------------------------- + +message HypervisorIsolated { + // Platform-specific UVM options. + oneof platform { + // Linux UVM options. + LinuxHyperVOptions lcow = 1; + // Windows UVM options. + WindowsHyperVOptions wcow = 2; + } + + // UVM CPU topology. + CPUConfig cpuConfig = 3; + + // UVM memory sizing and commit policy; MMIO aperture tuning. + MemoryConfig memoryConfig = 4; + + // UVM storage QoS caps and file-share hardening. + StorageConfig storageConfig = 5; + + // UVM vNUMA hints (implicit/explicit topology). + NUMAConfig numaConfig = 6; + + // Misc sandbox controls: networking proxy, dump paths, HvSocket services, console pipe. + AdditionalConfig additionalConfig = 7; + + // Assign the UVM to a CPU group. Mutually exclusive with resource_partition_id. + optional string cpu_group_id = 8; + + // Resource partition GUID to associate the UVM with (has its own CPU group). + // Mutually exclusive with cpu_group_id. + optional string resource_partition_id = 9; +} + +// ---------------------------------------------------------------------------- +// CPU configuration +// ---------------------------------------------------------------------------- + +message CPUConfig { + // vCPU count override for the UVM. On UVM, count/limit/weight may be combined. + optional int32 processor_count = 1; + + // vCPU percentage cap: 1..100000 (100000 = 100%). Omitted => platform default. + optional int32 processor_limit = 2; + + // vCPU scheduling weight: 0..10000 (100 default). Omitted => default. + optional int32 processor_weight = 3; + + // architecture represents the architecture of the platform. + optional string architecture = 4; +} + +// ---------------------------------------------------------------------------- +// Memory configuration +// ---------------------------------------------------------------------------- + +message MemoryConfig { + // Total UVM memory size in MB (MB units; OCI uses bytes). + optional uint64 memory_size_in_mb = 1; + + // MMIO aperture tuning (low gap/base/high gap in MB). + optional uint64 low_mmio_gap_in_mb = 2; + optional uint64 high_mmio_base_in_mb = 3; + optional uint64 high_mmio_gap_in_mb = 4; + + // Allow virtual memory overcommit (true by default). Set false for fully physical backing. + optional bool allow_overcommit = 5; + + // Enforce fully physically backed memory, including future device additions. + optional bool fully_physically_backed = 6; + + // Enable deferred commit for virtual memory (defaults to false). + optional bool enable_deferred_commit = 7; +} + +// ---------------------------------------------------------------------------- +// Storage configuration +// ---------------------------------------------------------------------------- + +message StorageConfig { + // Max storage IOPS; 0/omitted => platform default. + optional int32 storage_qos_iops_maximum = 1; + + // Max storage bandwidth in bytes/sec; 0/omitted => platform default. + optional int32 storage_qos_bandwidth_maximum = 2; + + // Disallow any writable file shares (e.g., VSMB/Plan9) to the UVM. + optional bool no_writable_file_shares = 3; +} + +// ---------------------------------------------------------------------------- +// NUMA configuration +// ---------------------------------------------------------------------------- + +message NUMAConfig { + // Implicit vNUMA: max memory per node (MB). + optional uint64 max_memory_size_per_numa_node = 1; + + // Implicit vNUMA: max processors per node. + optional uint32 max_processors_per_numa_node = 2; + + // Implicit vNUMA: preferred physical NUMA nodes. + repeated uint32 preferred_physical_numa_nodes = 3; + + // Explicit vNUMA: pNUMA -> vNUMA mapping by index. + repeated uint32 numa_mapped_physical_nodes = 4; + + // Explicit vNUMA: processor counts per vNUMA index. + repeated uint32 numa_processor_counts = 5; + + // Explicit vNUMA: memory block counts per vNUMA index. + repeated uint64 numa_memory_blocks_counts = 6; +} + +// ---------------------------------------------------------------------------- +// Additional sandbox controls +// ---------------------------------------------------------------------------- + +message AdditionalConfig { + // ncproxy service address for network setup; when set, use ncproxy. + optional string network_config_proxy = 1; + + // In-guest path for container process dumps; prefer a mounted volume over scratch. + optional string process_dump_location = 2; + + // Host directory to collect UVM crash dumps. + optional string dump_directory_path = 3; + + // HvSocket per-service configuration (bind/connect SDDL, wildcard, disabled). + map additional_hyperv_config = 4; + + // Serial console named pipe (e.g., \\.\pipe\) for the UVM console. + optional string console_pipe = 5; +} + +message HvSocketServiceConfig { + // Host bind permission SDDL. + optional string bind_security_descriptor = 1; + + // Host connect permission SDDL. + optional string connect_security_descriptor = 2; + + // Allow wildcard binds per policy. + optional bool allow_wildcard_binds = 3; + + // Disable service (refuse new, cancel existing connections). + optional bool disabled = 4; +} + +// ---------------------------------------------------------------------------- +// Windows Hyper-V (WCOW) configuration +// ---------------------------------------------------------------------------- + +message WindowsHyperVOptions { + // Boot configuration for WCOW UVM. + WindowsBootOptions windowsBootOptions = 1; + + // Guest configuration for WCOW UVM. + WindowsGuestOptions windowsGuestOptions = 2; + + // Confidential computing options for WCOW. + WCOWConfidentialOptions confidentialOptions = 3; +} + +message WindowsBootOptions { + // Disable network compartment namespacing in the WCOW UVM. + optional bool disable_compartment_namespace = 1; + + // Disable direct mapping for VSMB shares in the WCOW UVM. + optional bool no_direct_map = 2; +} + +message WindowsGuestOptions { + // Do not inherit host timezone; default WCOW UVM time is UTC. + optional bool no_inherit_host_timezone = 1; + + // Additional registry entries to apply in the guest. + repeated RegistryValue additional_registry_keys = 2; + + // Specifies whether to forward logs to the host or not. + optional bool forward_logs = 3; + + // Specifies the log sources to be forwarded to the host. + optional string log_sources = 4; +} + +// ---------------------------------------------------------------------------- +// Registry +// ---------------------------------------------------------------------------- + +enum RegistryHive { + REGISTRY_HIVE_SYSTEM = 0; + REGISTRY_HIVE_SOFTWARE = 1; + REGISTRY_HIVE_SECURITY = 2; + REGISTRY_HIVE_SAM = 3; +} + +message RegistryKey { + // Target hive. + RegistryHive hive = 1; + + // Key path. + string name = 2; + + // Volatile key flag. + bool volatile = 3; +} + +enum RegistryValueType { + REGISTRY_VALUE_TYPE_NONE = 0; + REGISTRY_VALUE_TYPE_STRING = 1; + REGISTRY_VALUE_TYPE_EXPANDED_STRING = 2; + REGISTRY_VALUE_TYPE_MULTI_STRING = 3; + REGISTRY_VALUE_TYPE_BINARY = 4; + REGISTRY_VALUE_TYPE_D_WORD = 5; + REGISTRY_VALUE_TYPE_Q_WORD = 6; + REGISTRY_VALUE_TYPE_CUSTOM_TYPE = 7; +} + +message RegistryValue { + // Value location (hive + key path). + RegistryKey key = 1; + + // Value name. + string name = 2; + + // Value type. + RegistryValueType type = 3; + + // Typed payloads (one populated per type). + string string_value = 4; + string binary_value = 5; + int32 dword_value = 6; + int32 qword_value = 7; + int32 custom_type = 8; +} + +// ---------------------------------------------------------------------------- +// Linux Hyper-V (LCOW) configuration +// ---------------------------------------------------------------------------- + +message LinuxHyperVOptions { + // Boot configuration for LCOW UVM. + LinuxBootOptions linuxBootOptions = 1; + + // Guest configuration for LCOW UVM. + LinuxGuestOptions linuxGuestOptions = 2; + + // Device configuration for LCOW UVM. + LinuxDeviceOptions linuxDeviceOptions = 3; + + // Confidential computing options for LCOW. + LCOWConfidentialOptions confidentialOptions = 4; +} + +message LinuxBootOptions { + // Root path for LCOW boot files. + optional string boot_files_path = 1; + + // Boot directly to kernel (skip UEFI). + optional bool kernel_direct = 2; + + // Extra kernel cmdline options. + optional string kernel_boot_options = 3; + + // Preferred rootfs type selection (INITRD/VHD). + optional PreferredRootFSType preferred_root_fs_type = 4; + + // Enable cold discard hint for trimming non‑zeroed pages. + optional bool enable_cold_discard_hint = 5; + + // Host Compatibility Layer toggle (presence-aware). + optional bool hcl_enabled = 6; +} + +message LinuxGuestOptions { + // Disable LCOW time-sync service. + optional bool disable_time_sync_service = 1; + + // Extra vsock ports to expose. + repeated uint32 extra_vsock_ports = 2; + + // Enable policy-based routing in guest. + optional bool policy_based_routing = 3; + + // Allow writable overlays for /var and /etc. + optional bool writable_overlay_dirs = 4; +} + +message LinuxDeviceOptions { + // Max vPMem device count. + optional uint32 vp_mem_device_count = 1; + + // vPMem device size (bytes). + optional uint64 vp_mem_size_bytes = 2; + + // Disable LCOW vPMem layer multi-mapping. + optional bool vp_mem_no_multi_mapping = 3; + + // Enable PCI support in LCOW kernel. + optional bool vpci_enabled = 4; + + // Assigned devices (e.g., SR-IOV). + repeated Device assigned_devices = 5; +} + +enum PreferredRootFSType { + PREFERRED_ROOT_FS_TYPE_INITRD = 0; + PREFERRED_ROOT_FS_TYPE_VHD = 1; +} + +message Device { + // Device identifier: interface class GUID, etc. + string id = 1; + + // Device identifier type: "class", etc. + string id_type = 2; +} + +// ---------------------------------------------------------------------------- +// Confidential computing options +// ---------------------------------------------------------------------------- + +message ConfidentialOptions { + // Guest state file (VMGS) path used by confidential UVM modes. + optional string guest_state_file = 1; + + // Security policy to enforce inside the guest. + optional string security_policy = 2; + + // Security policy enforcer selection ("open-door", "standard", "rego"). + optional string security_policy_enforcer = 3; + + // Signed UVM reference info file passed to guest. + optional string uvm_reference_info_file = 4; + + // no_security_hardware allows to do testing and development without requiring SNP hardware. + optional bool no_security_hardware = 5; +} + +message LCOWConfidentialOptions { + // LCOW common confidential options. + ConfidentialOptions options = 1; + + // Rootfs VHD path with dm-verity metadata (SNP mode). + optional string dm_verity_root_fs_vhd = 2; + + // Enable dm-verity presentation of rootfs (standalone SCSI attachment). + optional bool dm_verity_mode = 3; + + // dm-mod.create parameters for rootfs integrity. + optional string dm_verity_create_args = 4; + + // Encrypt LCOW scratch disks. + optional bool enable_scratch_encryption = 5; +} + +message WCOWConfidentialOptions { + // WCOW common confidential options. + ConfidentialOptions options = 1; + + // Disable secure boot (WCOW-only; testing/debugging). + optional bool disable_secure_boot = 2; + + // Attach EFI/boot VHD in writable mode (capture boot traces). + optional bool writable_efi = 3; + + // allows overriding isolation type of a confidential pod. + optional string isolation_type = 4; +} diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs.go b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs.go new file mode 100644 index 0000000000..b5d6b3c23c --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs.go @@ -0,0 +1,689 @@ +package sandboxspec + +import ( + "context" + "fmt" + "strings" + + runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" + iannotations "github.com/Microsoft/hcsshim/internal/annotations" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/oci" + shimannotations "github.com/Microsoft/hcsshim/pkg/annotations" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// Generate generates Specs based on provided options and annotations. +// These specifications define the configuration for the sandbox environment. +func Generate( + opts *runhcsoptions.Options, + annotations map[string]string, + devices []specs.WindowsDevice, +) (*Specs, error) { + if opts == nil { + return nil, fmt.Errorf("no runhcs options provided") + } + + // Decide Isolation based on options: PROCESS vs HYPERVISOR + switch opts.SandboxIsolation { + case runhcsoptions.Options_PROCESS: + // Windows process isolation -> no UVM + return &Specs{ + IsolationLevel: &Specs_Process{ + Process: &ProcessIsolated{}, + }, + }, nil + + case runhcsoptions.Options_HYPERVISOR: + ctx := context.Background() + // UVM-backed isolation + osName, arch, err := splitPlatform(opts.SandboxPlatform) + if err != nil { + return nil, fmt.Errorf("failed to parse platform: %w", err) + } + + // Process annotations prior to parsing them into Specs. + err = processAnnotations(ctx, opts, annotations) + if err != nil { + return nil, fmt.Errorf("failed to process annotations: %w", err) + } + + // Create HypervisorIsolated spec + hyper := &HypervisorIsolated{} + + // CPU Configuration + cpuConfig, err := parseCPUParameters(ctx, opts, annotations, arch) + if err != nil { + return nil, fmt.Errorf("failed to parse CPU parameters: %w", err) + } + + hyper.CpuConfig = cpuConfig + + // Memory Configuration + memoryConfig, err := parseMemoryParameters(ctx, opts, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Memory parameters: %w", err) + } + + hyper.MemoryConfig = memoryConfig + + // Storage Configuration + storageConfig, err := parseStorageParameters(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Storage parameters: %w", err) + } + + hyper.StorageConfig = storageConfig + + // NUMA Configuration + numaConfig, err := parseNUMAParameters(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse NUMA parameters: %w", err) + } + + hyper.NumaConfig = numaConfig + + // Additional Configurations + additionalConfig, err := parseAdditionalConfigurations(ctx, opts, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Additional parameters: %w", err) + } + + hyper.AdditionalConfig = additionalConfig + + // CPU group configuration + cpuGroupID := oci.ParseAnnotationsString(annotations, shimannotations.CPUGroupID, "") + if cpuGroupID != "" { + hyper.CpuGroupID = &cpuGroupID + } + + // Resource Partition ID + resourcePartitionID := oci.ParseAnnotationsString(annotations, shimannotations.ResourcePartitionID, "") + if resourcePartitionID != "" { + hyper.ResourcePartitionID = &resourcePartitionID + } + + switch osName { + case "linux": + // LCOW platform-specific options + lcow := &LinuxHyperVOptions{} + + // Linux Boot Options + bootOptions, err := parseLinuxBootOptions(ctx, opts, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Linux boot options: %w", err) + } + + lcow.LinuxBootOptions = bootOptions + + guestOptions, err := parseLinuxGuestOptions(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Linux guest options: %w", err) + } + + lcow.LinuxGuestOptions = guestOptions + + deviceOptions, err := parseLinuxDeviceOptions(ctx, annotations, devices) + if err != nil { + return nil, fmt.Errorf("failed to parse Linux device options: %w", err) + } + + lcow.LinuxDeviceOptions = deviceOptions + + confidentialOptions, err := parseLinuxConfidentialOptions(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Linux confidential options: %w", err) + } + + lcow.ConfidentialOptions = confidentialOptions + + hyper.Platform = &HypervisorIsolated_Lcow{lcow} + + case "windows": + // WCOW platform-specific options + wcow := &WindowsHyperVOptions{} + + bootOptions, err := parseWindowsBootOptions(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Windows boot options: %w", err) + } + + wcow.WindowsBootOptions = bootOptions + + guestOptions, err := parseWindowsGuestOptions(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Windows guest options: %w", err) + } + + wcow.WindowsGuestOptions = guestOptions + + confidentialOptions, err := parseWindowsConfidentialOptions(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse Windows confidential options: %w", err) + } + + wcow.ConfidentialOptions = confidentialOptions + + hyper.Platform = &HypervisorIsolated_Wcow{wcow} + + default: + return nil, fmt.Errorf("unsupported sandbox platform os: %s", osName) + } + + return &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: hyper, + }, + }, nil + + default: + return nil, fmt.Errorf("unsupported sandbox_isolation: %v", opts.SandboxIsolation) + } +} + +// processAnnotations applies default annotations and processes them. +func processAnnotations(ctx context.Context, opts *runhcsoptions.Options, annotations map[string]string) error { + // Apply default annotations. + for key, value := range opts.DefaultContainerAnnotations { + // Only set default if not already set in annotations + if _, exists := annotations[key]; !exists { + annotations[key] = value + } + } + + err := oci.ProcessAnnotations(ctx, annotations) + if err != nil { + return err + } + + return nil +} + +// parseCPUParameters parses CPU related parameters from annotations and options. +func parseCPUParameters(ctx context.Context, opts *runhcsoptions.Options, annotations map[string]string, arch string) (*CPUConfig, error) { + cpu := &CPUConfig{} + + if _, ok := annotations[shimannotations.ProcessorCount]; ok { + cpuCount := oci.ParseAnnotationsInt32(ctx, annotations, shimannotations.ProcessorCount, 0) + if cpuCount != 0 { + cpu.ProcessorCount = &cpuCount + } + } else if opts.VmProcessorCount != 0 { + cpu.ProcessorCount = &opts.VmProcessorCount + } + + cpuLimit := oci.ParseAnnotationsInt32(ctx, annotations, shimannotations.ProcessorLimit, 0) + if cpuLimit != 0 { + cpu.ProcessorLimit = &cpuLimit + } + + cpuWeight := oci.ParseAnnotationsInt32(ctx, annotations, shimannotations.ProcessorWeight, 0) + if cpuWeight != 0 { + cpu.ProcessorWeight = &cpuWeight + } + + if arch != "" { + cpu.Architecture = &arch + } + + return cpu, nil +} + +// parseMemoryParameters parses memory related parameters from annotations and options. +func parseMemoryParameters(ctx context.Context, opts *runhcsoptions.Options, annotations map[string]string) (*MemoryConfig, error) { + mem := &MemoryConfig{} + + if _, ok := annotations[shimannotations.MemorySizeInMB]; ok { + memorySizeMB := oci.ParseAnnotationsUint64(ctx, annotations, shimannotations.MemorySizeInMB, 0) + if memorySizeMB != 0 { + mem.MemorySizeInMb = &memorySizeMB + } + } else if opts.VmMemorySizeInMb != 0 { + memorySizeMB := uint64(opts.VmMemorySizeInMb) + mem.MemorySizeInMb = &memorySizeMB + } + + lowMMIOGapInMB := oci.ParseAnnotationsUint64(ctx, annotations, shimannotations.MemoryLowMMIOGapInMB, 0) + if lowMMIOGapInMB != 0 { + mem.LowMmioGapInMb = &lowMMIOGapInMB + } + + highMMIOBaseInMB := oci.ParseAnnotationsUint64(ctx, annotations, shimannotations.MemoryHighMMIOBaseInMB, 0) + if highMMIOBaseInMB != 0 { + mem.HighMmioBaseInMb = &highMMIOBaseInMB + } + + highMMIOGapInMB := oci.ParseAnnotationsUint64(ctx, annotations, shimannotations.MemoryHighMMIOGapInMB, 0) + if highMMIOGapInMB != 0 { + mem.HighMmioGapInMb = &highMMIOGapInMB + } + + allowOvercommit := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.AllowOvercommit) + mem.AllowOvercommit = allowOvercommit + + enableDeferredCommit := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.EnableDeferredCommit) + mem.EnableDeferredCommit = enableDeferredCommit + + fullyPhysicallyBacked := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.FullyPhysicallyBacked) + mem.FullyPhysicallyBacked = fullyPhysicallyBacked + + return mem, nil +} + +// parseStorageParameters parses storage related parameters from annotations and options. +func parseStorageParameters(ctx context.Context, annotations map[string]string) (*StorageConfig, error) { + storage := &StorageConfig{} + + noWritableFileShares := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.DisableWritableFileShares) + storage.NoWritableFileShares = noWritableFileShares + + storageQosBandwidthMaximum := oci.ParseAnnotationsInt32(ctx, annotations, shimannotations.StorageQoSBandwidthMaximum, 0) + if storageQosBandwidthMaximum != 0 { + storage.StorageQosBandwidthMaximum = &storageQosBandwidthMaximum + } + + storageQosIopsMaximum := oci.ParseAnnotationsInt32(ctx, annotations, shimannotations.StorageQoSIopsMaximum, 0) + if storageQosIopsMaximum != 0 { + storage.StorageQosIopsMaximum = &storageQosIopsMaximum + } + + return storage, nil +} + +// parseNUMAParameters parses NUMA related parameters from annotations. +func parseNUMAParameters(ctx context.Context, annotations map[string]string) (*NUMAConfig, error) { + numa := &NUMAConfig{} + + maxProcessorsPerNumaNode := oci.ParseAnnotationsUint32(ctx, annotations, shimannotations.NumaMaximumProcessorsPerNode, 0) + if maxProcessorsPerNumaNode != 0 { + numa.MaxProcessorsPerNumaNode = &maxProcessorsPerNumaNode + } + + maxMemorySizePerNumaNode := oci.ParseAnnotationsUint64(ctx, annotations, shimannotations.NumaMaximumMemorySizePerNode, 0) + if maxMemorySizePerNumaNode != 0 { + numa.MaxMemorySizePerNumaNode = &maxMemorySizePerNumaNode + } + + preferredPhysicalNumaNodes := oci.ParseAnnotationCommaSeparatedUint32(ctx, annotations, shimannotations.NumaPreferredPhysicalNodes, []uint32{}) + numa.PreferredPhysicalNumaNodes = preferredPhysicalNumaNodes + + numaMappedPhysicalNodes := oci.ParseAnnotationCommaSeparatedUint32(ctx, annotations, shimannotations.NumaMappedPhysicalNodes, []uint32{}) + numa.NumaMappedPhysicalNodes = numaMappedPhysicalNodes + + numaProcessorCounts := oci.ParseAnnotationCommaSeparatedUint32(ctx, annotations, shimannotations.NumaCountOfProcessors, []uint32{}) + numa.NumaProcessorCounts = numaProcessorCounts + + numaMemoryBlocksCount := oci.ParseAnnotationCommaSeparatedUint64(ctx, annotations, shimannotations.NumaCountOfMemoryBlocks, []uint64{}) + numa.NumaMemoryBlocksCounts = numaMemoryBlocksCount + + return numa, nil +} + +// parseAdditionalConfigurations parses additional configurations from annotations and options. +func parseAdditionalConfigurations(ctx context.Context, opts *runhcsoptions.Options, annotations map[string]string) (*AdditionalConfig, error) { + additionalConfig := &AdditionalConfig{} + + networkConfigProxy := oci.ParseAnnotationsString(annotations, shimannotations.NetworkConfigProxy, "") + if networkConfigProxy != "" { + additionalConfig.NetworkConfigProxy = &networkConfigProxy + } else if opts.NCProxyAddr != "" { + additionalConfig.NetworkConfigProxy = &opts.NCProxyAddr + } + + processDumpLocation := oci.ParseAnnotationsString(annotations, shimannotations.ContainerProcessDumpLocation, "") + if processDumpLocation != "" { + additionalConfig.ProcessDumpLocation = &processDumpLocation + } + + dumpDirectoryPath := oci.ParseAnnotationsString(annotations, shimannotations.DumpDirectoryPath, "") + if dumpDirectoryPath != "" { + additionalConfig.DumpDirectoryPath = &dumpDirectoryPath + } + + consolePipe := oci.ParseAnnotationsString(annotations, iannotations.UVMConsolePipe, "") + if consolePipe != "" { + additionalConfig.ConsolePipe = &consolePipe + } + + hvSocketServiceTable, err := parseHVSocketServiceTableFromAnnotations(ctx, annotations) + if err != nil { + return nil, fmt.Errorf("failed to parse HVSocket service table: %w", err) + } + additionalConfig.AdditionalHypervConfig = hvSocketServiceTable + + return additionalConfig, nil +} + +// parseHVSocketServiceTableFromAnnotations parses HVSocket service table from annotations. +func parseHVSocketServiceTableFromAnnotations(ctx context.Context, annotations map[string]string) (map[string]*HvSocketServiceConfig, error) { + hcsHvSocketServiceTable := oci.ParseHVSocketServiceTable(ctx, annotations) + if len(hcsHvSocketServiceTable) == 0 { + return make(map[string]*HvSocketServiceConfig), nil + } + + sc := make(map[string]*HvSocketServiceConfig, len(hcsHvSocketServiceTable)) + for name, entry := range hcsHvSocketServiceTable { + conf := &HvSocketServiceConfig{} + conf.BindSecurityDescriptor = &entry.BindSecurityDescriptor + conf.ConnectSecurityDescriptor = &entry.ConnectSecurityDescriptor + conf.AllowWildcardBinds = &entry.AllowWildcardBinds + conf.Disabled = &entry.Disabled + sc[name] = conf + } + + return sc, nil +} + +// parseLinuxBootOptions parses Linux boot options from annotations and options. +func parseLinuxBootOptions(ctx context.Context, opts *runhcsoptions.Options, annotations map[string]string) (*LinuxBootOptions, error) { + bootOptions := &LinuxBootOptions{} + + if _, ok := annotations[shimannotations.BootFilesRootPath]; ok { + bootFilesRootPath := oci.ParseAnnotationsString(annotations, shimannotations.BootFilesRootPath, "") + if bootFilesRootPath != "" { + bootOptions.BootFilesPath = &bootFilesRootPath + } + } else if opts.BootFilesRootPath != "" { + bootOptions.BootFilesPath = &opts.BootFilesRootPath + } + + kernelDirect := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.KernelDirectBoot) + bootOptions.KernelDirect = kernelDirect + + kernelBootOptions := oci.ParseAnnotationsString(annotations, shimannotations.KernelBootOptions, "") + if kernelBootOptions != "" { + bootOptions.KernelBootOptions = &kernelBootOptions + } + + enableColdDiscardHint := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.EnableColdDiscardHint) + bootOptions.EnableColdDiscardHint = enableColdDiscardHint + + hclEnabled := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.LCOWHclEnabled) + bootOptions.HclEnabled = hclEnabled + + preferredRootfsType := oci.ParseAnnotationsString(annotations, shimannotations.PreferredRootFSType, "") + if preferredRootfsType != "" { + var t PreferredRootFSType + switch preferredRootfsType { + case "initrd": + t = PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_INITRD + case "vhd": + t = PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_VHD + default: + return nil, fmt.Errorf("invalid PreferredRootFSType: %s", preferredRootfsType) + } + bootOptions.PreferredRootFsType = &t + } + + return bootOptions, nil +} + +// parseLinuxGuestOptions parses Linux guest options from annotations. +func parseLinuxGuestOptions(ctx context.Context, annotations map[string]string) (*LinuxGuestOptions, error) { + guestOptions := &LinuxGuestOptions{} + + disableTimeSyncService := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.DisableLCOWTimeSyncService) + guestOptions.DisableTimeSyncService = disableTimeSyncService + + networkingPolicyBasedRouting := oci.ParseAnnotationsNullableBool(ctx, annotations, iannotations.NetworkingPolicyBasedRouting) + guestOptions.PolicyBasedRouting = networkingPolicyBasedRouting + + writableOverlayDirs := oci.ParseAnnotationsNullableBool(ctx, annotations, iannotations.WritableOverlayDirs) + guestOptions.WritableOverlayDirs = writableOverlayDirs + + extraVsockPorts := oci.ParseAnnotationCommaSeparatedUint32(ctx, annotations, iannotations.ExtraVSockPorts, []uint32{}) + guestOptions.ExtraVsockPorts = extraVsockPorts + + return guestOptions, nil +} + +// parseLinuxDeviceOptions parses Linux device options from annotations. +func parseLinuxDeviceOptions(ctx context.Context, annotations map[string]string, devices []specs.WindowsDevice) (*LinuxDeviceOptions, error) { + deviceOptions := &LinuxDeviceOptions{} + + vpMemDeviceCount := oci.ParseAnnotationsUint32(ctx, annotations, shimannotations.VPMemCount, 0) + if vpMemDeviceCount != 0 { + deviceOptions.VpMemDeviceCount = &vpMemDeviceCount + } + + vpMemSizeBytes := oci.ParseAnnotationsUint64(ctx, annotations, shimannotations.VPMemSize, 0) + if vpMemSizeBytes != 0 { + deviceOptions.VpMemSizeBytes = &vpMemSizeBytes + } + + vpMemNoMultiMapping := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.VPMemNoMultiMapping) + deviceOptions.VpMemNoMultiMapping = vpMemNoMultiMapping + + vpciEnabled := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.VPCIEnabled) + deviceOptions.VpciEnabled = vpciEnabled + + devicesToAdd := make([]*Device, 0, len(devices)) + for _, dev := range devices { + devAdd := &Device{ + ID: dev.ID, + IdType: dev.IDType, + } + devicesToAdd = append(devicesToAdd, devAdd) + } + + deviceOptions.AssignedDevices = devicesToAdd + + return deviceOptions, nil +} + +// parseLinuxConfidentialOptions parses Linux confidential options from annotations. +func parseLinuxConfidentialOptions(ctx context.Context, annotations map[string]string) (*LCOWConfidentialOptions, error) { + lcowConfidentialOptions := &LCOWConfidentialOptions{} + + confidentialOptions := &ConfidentialOptions{} + + guestStateFile := oci.ParseAnnotationsString(annotations, shimannotations.LCOWGuestStateFile, "") + if guestStateFile != "" { + confidentialOptions.GuestStateFile = &guestStateFile + } + + securityPolicy := oci.ParseAnnotationsString(annotations, shimannotations.LCOWSecurityPolicy, "") + if securityPolicy != "" { + confidentialOptions.SecurityPolicy = &securityPolicy + } + + securityPolicyEnforcer := oci.ParseAnnotationsString(annotations, shimannotations.LCOWSecurityPolicyEnforcer, "") + if securityPolicyEnforcer != "" { + confidentialOptions.SecurityPolicyEnforcer = &securityPolicyEnforcer + } + + uvmReferenceInfoFile := oci.ParseAnnotationsString(annotations, shimannotations.LCOWReferenceInfoFile, "") + if uvmReferenceInfoFile != "" { + confidentialOptions.UvmReferenceInfoFile = &uvmReferenceInfoFile + } + + noSecurityHardware := oci.ParseAnnotationsBool(ctx, annotations, shimannotations.NoSecurityHardware, false) + confidentialOptions.NoSecurityHardware = &noSecurityHardware + + lcowConfidentialOptions.Options = confidentialOptions + + enableScratchEncryption := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.LCOWEncryptedScratchDisk) + lcowConfidentialOptions.EnableScratchEncryption = enableScratchEncryption + + dmVerityMode := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.DmVerityMode) + lcowConfidentialOptions.DmVerityMode = dmVerityMode + + dmVerityRootFsVhd := oci.ParseAnnotationsString(annotations, shimannotations.DmVerityRootFsVhd, "") + if dmVerityRootFsVhd != "" { + lcowConfidentialOptions.DmVerityRootFsVhd = &dmVerityRootFsVhd + } + + dmVerityCreateArgs := oci.ParseAnnotationsString(annotations, shimannotations.DmVerityCreateArgs, "") + if dmVerityCreateArgs != "" { + lcowConfidentialOptions.DmVerityCreateArgs = &dmVerityCreateArgs + } + + return lcowConfidentialOptions, nil +} + +// parseWindowsBootOptions parses Windows boot options from annotations. +func parseWindowsBootOptions(ctx context.Context, annotations map[string]string) (*WindowsBootOptions, error) { + bootOptions := &WindowsBootOptions{} + + disableCompartmentNamespace := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.DisableCompartmentNamespace) + bootOptions.DisableCompartmentNamespace = disableCompartmentNamespace + + noDirectMap := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.VSMBNoDirectMap) + bootOptions.NoDirectMap = noDirectMap + + return bootOptions, nil +} + +// parseWindowsGuestOptions parses Windows guest options from annotations. +func parseWindowsGuestOptions(ctx context.Context, annotations map[string]string) (*WindowsGuestOptions, error) { + guestOptions := &WindowsGuestOptions{} + + noInheritTimezone := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.NoInheritHostTimezone) + guestOptions.NoInheritHostTimezone = noInheritTimezone + + hcsRegistryKeys := oci.ParseAdditionalRegistryValues(ctx, annotations) + guestOptions.AdditionalRegistryKeys = registryValuesToProto(hcsRegistryKeys) + + forwardLogs := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.ForwardLogs) + guestOptions.ForwardLogs = forwardLogs + + logSources := oci.ParseAnnotationsString(annotations, shimannotations.LogSources, "") + if logSources != "" { + guestOptions.LogSources = &logSources + } + + return guestOptions, nil +} + +// parseWindowsConfidentialOptions parses Windows confidential options from annotations. +func parseWindowsConfidentialOptions(ctx context.Context, annotations map[string]string) (*WCOWConfidentialOptions, error) { + wcowConfidentialOptions := &WCOWConfidentialOptions{} + + confidentialOptions := &ConfidentialOptions{} + + securityPolicy := oci.ParseAnnotationsString(annotations, shimannotations.WCOWSecurityPolicy, "") + if securityPolicy != "" { + confidentialOptions.SecurityPolicy = &securityPolicy + } + + guestStateFile := oci.ParseAnnotationsString(annotations, shimannotations.WCOWGuestStateFile, "") + if guestStateFile != "" { + confidentialOptions.GuestStateFile = &guestStateFile + } + + securityPolicyEnforcer := oci.ParseAnnotationsString(annotations, shimannotations.WCOWSecurityPolicyEnforcer, "") + if securityPolicyEnforcer != "" { + confidentialOptions.SecurityPolicyEnforcer = &securityPolicyEnforcer + } + + uvmReferenceInfoFile := oci.ParseAnnotationsString(annotations, shimannotations.WCOWReferenceInfoFile, "") + if uvmReferenceInfoFile != "" { + confidentialOptions.UvmReferenceInfoFile = &uvmReferenceInfoFile + } + + noSecurityHardware := oci.ParseAnnotationsBool(ctx, annotations, shimannotations.NoSecurityHardware, false) + confidentialOptions.NoSecurityHardware = &noSecurityHardware + + wcowConfidentialOptions.Options = confidentialOptions + + writableEFI := oci.ParseAnnotationsNullableBool(ctx, annotations, shimannotations.WCOWWritableEFI) + wcowConfidentialOptions.WritableEfi = writableEFI + + disableSecureBoot := oci.ParseAnnotationsBool(ctx, annotations, shimannotations.WCOWDisableSecureBoot, false) + wcowConfidentialOptions.DisableSecureBoot = &disableSecureBoot + + isolationType := oci.ParseAnnotationsString(annotations, shimannotations.WCOWIsolationType, "") + if isolationType != "" { + wcowConfidentialOptions.IsolationType = &isolationType + } + + return wcowConfidentialOptions, nil +} + +// ----------------------------------------------------------------------------- +// Small utilities to reduce nil-check boilerplate +// ----------------------------------------------------------------------------- + +// splitPlatform expects "linux/amd64" or "windows/amd64" +// and splits it into osName and arch. +func splitPlatform(p string) (osName, arch string, err error) { + if p == "" { + return "", "", fmt.Errorf("sandbox_platform empty; expected \"linux/amd64\" or \"windows/amd64\"") + } + parts := strings.Split(p, "/") + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("invalid sandbox_platform %q; expected \"linux/amd64\" or \"windows/amd64\"", p) + } + return parts[0], parts[1], nil +} + +// Convert a slice of hcsschema.RegistryValue -> slice of *proto RegistryValue. +func registryValuesToProto(in []hcsschema.RegistryValue) []*RegistryValue { + out := make([]*RegistryValue, 0, len(in)) + for _, reg := range in { + var key *RegistryKey + if reg.Key != nil { + key = &RegistryKey{ + Hive: mapHcsHiveToProto(reg.Key.Hive), + Name: strings.TrimSpace(reg.Key.Name), + Volatile: reg.Key.Volatile, + } + } + + rv := &RegistryValue{ + Key: key, + Name: strings.TrimSpace(reg.Name), + Type: mapHcsRegValueTypeToProto(reg.Type_), + StringValue: reg.StringValue, + BinaryValue: reg.BinaryValue, + DwordValue: reg.DWordValue, + QwordValue: reg.QWordValue, + CustomType: reg.CustomType, + } + + out = append(out, rv) + } + return out +} + +// Map hcsschema.RegistryHive -> proto RegistryHive. +func mapHcsHiveToProto(h hcsschema.RegistryHive) RegistryHive { + switch h { + case hcsschema.RegistryHive_SYSTEM: + return RegistryHive_REGISTRY_HIVE_SYSTEM + case hcsschema.RegistryHive_SOFTWARE: + return RegistryHive_REGISTRY_HIVE_SOFTWARE + case hcsschema.RegistryHive_SECURITY: + return RegistryHive_REGISTRY_HIVE_SECURITY + case hcsschema.RegistryHive_SAM: + return RegistryHive_REGISTRY_HIVE_SAM + default: + // Choose a sensible default. SYSTEM matches your proto->HCS default. + return RegistryHive_REGISTRY_HIVE_SYSTEM + } +} + +// Map hcsschema.RegistryValueType -> proto RegistryValueType. +func mapHcsRegValueTypeToProto(t hcsschema.RegistryValueType) RegistryValueType { + switch t { + case hcsschema.RegistryValueType_NONE: + return RegistryValueType_REGISTRY_VALUE_TYPE_NONE + case hcsschema.RegistryValueType_STRING: + return RegistryValueType_REGISTRY_VALUE_TYPE_STRING + case hcsschema.RegistryValueType_EXPANDED_STRING: + return RegistryValueType_REGISTRY_VALUE_TYPE_EXPANDED_STRING + case hcsschema.RegistryValueType_MULTI_STRING: + return RegistryValueType_REGISTRY_VALUE_TYPE_MULTI_STRING + case hcsschema.RegistryValueType_BINARY: + return RegistryValueType_REGISTRY_VALUE_TYPE_BINARY + case hcsschema.RegistryValueType_D_WORD: + return RegistryValueType_REGISTRY_VALUE_TYPE_D_WORD + case hcsschema.RegistryValueType_Q_WORD: + return RegistryValueType_REGISTRY_VALUE_TYPE_Q_WORD + case hcsschema.RegistryValueType_CUSTOM_TYPE: + return RegistryValueType_REGISTRY_VALUE_TYPE_CUSTOM_TYPE + default: + return RegistryValueType_REGISTRY_VALUE_TYPE_NONE + } +} diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs_test.go b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs_test.go new file mode 100644 index 0000000000..d21ae2e9bd --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/sandbox_specs_test.go @@ -0,0 +1,836 @@ +package sandboxspec + +import ( + "encoding/json" + "testing" + + "google.golang.org/protobuf/proto" + + runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" + iannotations "github.com/Microsoft/hcsshim/internal/annotations" + shimannotations "github.com/Microsoft/hcsshim/pkg/annotations" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// ptr is a helper to return a pointer to a value. +// Required for initializing optional pointer fields in structs. +func ptr[T any](v T) *T { + return &v +} + +func TestGenerateSpecss(t *testing.T) { + type testCase struct { + name string + opts *runhcsoptions.Options + annotations map[string]string + devices []specs.WindowsDevice + expected *Specs + expectError bool + } + + tests := []testCase{ + // ==================================================================== + // SECTION 1: LCOW (Linux) Specific Tests + // ==================================================================== + { + name: "LCOW_Boot_And_Guest_Options_Comprehensive", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + // Boot Options + shimannotations.KernelBootOptions: "debug", + shimannotations.KernelDirectBoot: "true", + shimannotations.LCOWHclEnabled: "true", + shimannotations.EnableColdDiscardHint: "true", + shimannotations.PreferredRootFSType: "initrd", + shimannotations.BootFilesRootPath: "/boot/files", + // Guest Options + shimannotations.DisableLCOWTimeSyncService: "true", + iannotations.NetworkingPolicyBasedRouting: "true", + iannotations.WritableOverlayDirs: "true", + iannotations.ExtraVSockPorts: "1024,2048", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{ + KernelBootOptions: ptr("debug"), + KernelDirect: ptr(true), + HclEnabled: ptr(true), + EnableColdDiscardHint: ptr(true), + PreferredRootFsType: ptr(PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_INITRD), + BootFilesPath: ptr("/boot/files"), + }, + LinuxGuestOptions: &LinuxGuestOptions{ + DisableTimeSyncService: ptr(true), + PolicyBasedRouting: ptr(true), + WritableOverlayDirs: ptr(true), + ExtraVsockPorts: []uint32{1024, 2048}, + }, + LinuxDeviceOptions: &LinuxDeviceOptions{ + AssignedDevices: []*Device{}, + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + { + name: "LCOW_DeviceOptions_Comprehensive", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + shimannotations.VPMemCount: "4", + shimannotations.VPMemSize: "1073741824", // 1GiB + shimannotations.VPCIEnabled: "true", + shimannotations.VPMemNoMultiMapping: "true", + }, + devices: []specs.WindowsDevice{ + {ID: "1111-1111", IDType: "class"}, + {ID: "2222-2222", IDType: "class"}, + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{}, + LinuxGuestOptions: &LinuxGuestOptions{ExtraVsockPorts: []uint32{}}, + LinuxDeviceOptions: &LinuxDeviceOptions{ + VpMemDeviceCount: ptr(uint32(4)), + VpMemSizeBytes: ptr(uint64(1073741824)), + VpciEnabled: ptr(true), + VpMemNoMultiMapping: ptr(true), + AssignedDevices: []*Device{ + {ID: "1111-1111", IdType: "class"}, + {ID: "2222-2222", IdType: "class"}, + }, + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + { + name: "LCOW_Confidential_Comprehensive", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + shimannotations.LCOWGuestStateFile: "guest_state.vmgs", + shimannotations.LCOWSecurityPolicy: "abc123", + shimannotations.LCOWSecurityPolicyEnforcer: "XYZ", + shimannotations.LCOWReferenceInfoFile: "uvm_ref_info.json", + shimannotations.NoSecurityHardware: "false", + shimannotations.DmVerityMode: "true", + shimannotations.DmVerityRootFsVhd: "/host/paths/rootfs.vhd", + shimannotations.DmVerityCreateArgs: "1 /dev/vda1 /dev/vda2", + shimannotations.LCOWEncryptedScratchDisk: "true", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{}, + LinuxGuestOptions: &LinuxGuestOptions{ExtraVsockPorts: []uint32{}}, + LinuxDeviceOptions: &LinuxDeviceOptions{AssignedDevices: []*Device{}}, + ConfidentialOptions: &LCOWConfidentialOptions{ + DmVerityMode: ptr(true), + DmVerityRootFsVhd: ptr("/host/paths/rootfs.vhd"), + DmVerityCreateArgs: ptr("1 /dev/vda1 /dev/vda2"), + EnableScratchEncryption: ptr(true), + Options: &ConfidentialOptions{ + NoSecurityHardware: ptr(false), + GuestStateFile: ptr("guest_state.vmgs"), + SecurityPolicy: ptr("abc123"), + SecurityPolicyEnforcer: ptr("XYZ"), + UvmReferenceInfoFile: ptr("uvm_ref_info.json"), + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "LCOW_RunHCSOptions_Override", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + // Use boot files from Options when annotation is missing. + BootFilesRootPath: "/default/boot/files", + VmProcessorCount: 4, + VmMemorySizeInMb: 100, + NCProxyAddr: "//./pipe/proxy", + }, + annotations: map[string]string{}, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{ + ProcessorCount: ptr(int32(4)), + Architecture: ptr("amd64"), + }, + MemoryConfig: &MemoryConfig{ + MemorySizeInMb: ptr(uint64(100)), + }, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{ + NetworkConfigProxy: ptr("//./pipe/proxy"), + }, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{ + BootFilesPath: ptr("/default/boot/files"), + }, + LinuxGuestOptions: &LinuxGuestOptions{ + ExtraVsockPorts: []uint32{}, + }, + LinuxDeviceOptions: &LinuxDeviceOptions{ + AssignedDevices: []*Device{}, + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + { + name: "LCOW_MissingValues", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{}, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{}, + LinuxGuestOptions: &LinuxGuestOptions{ + ExtraVsockPorts: []uint32{}, + }, + LinuxDeviceOptions: &LinuxDeviceOptions{ + AssignedDevices: []*Device{}, + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + + // ==================================================================== + // SECTION 2: WCOW (Windows) Specific Tests + // ==================================================================== + { + name: "WCOW_Boot_Guest_And_Registry", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: map[string]string{ + // Boot Options + shimannotations.DisableCompartmentNamespace: "true", + shimannotations.VSMBNoDirectMap: "true", + // Guest Options + shimannotations.NoInheritHostTimezone: "true", + // Registry + iannotations.AdditionalRegistryValues: `[ + { + "Key": {"Hive": "Software", "Name": "Software\\TestKey"}, + "Name": "TestVal", + "Type": "String", + "StringValue": "MyValue" + } + ]`, + shimannotations.ForwardLogs: "true", + shimannotations.LogSources: "Microsoft-Windows-Containers-GuestLog", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{ + DisableCompartmentNamespace: ptr(true), + NoDirectMap: ptr(true), + }, + WindowsGuestOptions: &WindowsGuestOptions{ + NoInheritHostTimezone: ptr(true), + AdditionalRegistryKeys: []*RegistryValue{ + { + Key: &RegistryKey{ + Hive: RegistryHive_REGISTRY_HIVE_SOFTWARE, + Name: "Software\\TestKey", + }, + Name: "TestVal", + Type: RegistryValueType_REGISTRY_VALUE_TYPE_STRING, + StringValue: "MyValue", + }, + }, + ForwardLogs: ptr(true), + LogSources: ptr("Microsoft-Windows-Containers-GuestLog"), + }, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(false), + }, + }, + }, + }, + }, + }, + }, + { + name: "WCOW_Confidential_Comprehensive", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: map[string]string{ + shimannotations.WCOWDisableSecureBoot: "true", + shimannotations.WCOWWritableEFI: "true", + shimannotations.WCOWIsolationType: "NoIsolation", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{}, + WindowsGuestOptions: &WindowsGuestOptions{AdditionalRegistryKeys: []*RegistryValue{}}, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(true), + WritableEfi: ptr(true), + IsolationType: ptr("NoIsolation"), + }, + }, + }, + }, + }, + }, + }, + { + name: "WCOW_MissingValues", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: map[string]string{}, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{}, + WindowsGuestOptions: &WindowsGuestOptions{AdditionalRegistryKeys: []*RegistryValue{}}, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(false), + }, + }, + }, + }, + }, + }, + }, + + // ==================================================================== + // SECTION 3: Common Resources (Memory, Storage, Additional) + // ==================================================================== + { + name: "Memory_Storage_Comprehensive", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + // Memory + shimannotations.MemorySizeInMB: "2048", + shimannotations.MemoryLowMMIOGapInMB: "128", + shimannotations.MemoryHighMMIOBaseInMB: "512", + shimannotations.MemoryHighMMIOGapInMB: "256", + shimannotations.AllowOvercommit: "false", + shimannotations.FullyPhysicallyBacked: "true", + shimannotations.EnableDeferredCommit: "true", + // Storage + shimannotations.DisableWritableFileShares: "true", + shimannotations.StorageQoSBandwidthMaximum: "1048576", // 1MB/s + shimannotations.StorageQoSIopsMaximum: "500", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{ + MemorySizeInMb: ptr(uint64(2048)), + LowMmioGapInMb: ptr(uint64(128)), + HighMmioBaseInMb: ptr(uint64(512)), + HighMmioGapInMb: ptr(uint64(256)), + AllowOvercommit: ptr(false), + FullyPhysicallyBacked: ptr(true), + EnableDeferredCommit: ptr(true), + }, + StorageConfig: &StorageConfig{ + NoWritableFileShares: ptr(true), + StorageQosBandwidthMaximum: ptr(int32(1048576)), + StorageQosIopsMaximum: ptr(int32(500)), + }, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{}, + LinuxGuestOptions: &LinuxGuestOptions{ExtraVsockPorts: []uint32{}}, + LinuxDeviceOptions: &LinuxDeviceOptions{AssignedDevices: []*Device{}}, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + { + name: "AdditionalConfig_Comprehensive", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: map[string]string{ + shimannotations.NetworkConfigProxy: "//./pipe/proxy", + shimannotations.ContainerProcessDumpLocation: "C:\\dumps", + shimannotations.DumpDirectoryPath: "C:\\host\\dumps", + iannotations.UVMConsolePipe: "\\\\.\\pipe\\vm-console", + "io.microsoft.virtualmachine.hv-socket.service-table.00000000-0000-0000-0000-000000000001": `{"AllowWildcardBinds": true, "BindSecurityDescriptor": "D:P(A;;FA;;;WD)"}`, + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{ + NetworkConfigProxy: ptr("//./pipe/proxy"), + ProcessDumpLocation: ptr("C:\\dumps"), + DumpDirectoryPath: ptr("C:\\host\\dumps"), + ConsolePipe: ptr("\\\\.\\pipe\\vm-console"), + AdditionalHypervConfig: map[string]*HvSocketServiceConfig{ + "00000000-0000-0000-0000-000000000001": { + AllowWildcardBinds: ptr(true), + BindSecurityDescriptor: ptr("D:P(A;;FA;;;WD)"), + ConnectSecurityDescriptor: ptr(""), + Disabled: ptr(false), + }, + }, + }, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{}, + WindowsGuestOptions: &WindowsGuestOptions{AdditionalRegistryKeys: []*RegistryValue{}}, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(false), + }, + }, + }, + }, + }, + }, + }, + + // ==================================================================== + // SECTION 4: Logic, Precedence and Error Handling + // ==================================================================== + { + name: "Mixed_Defaults_And_Overrides_Logic", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + // Default annotations passed via Options + DefaultContainerAnnotations: map[string]string{ + shimannotations.ProcessorCount: "2", + shimannotations.StorageQoSIopsMaximum: "100", + }, + }, + annotations: map[string]string{ + // This should OVERRIDE the DefaultContainerAnnotations above + shimannotations.ProcessorCount: "8", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{ + Architecture: ptr("amd64"), + ProcessorCount: ptr(int32(8)), // Overridden + }, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{ + StorageQosIopsMaximum: ptr(int32(100)), // From default + }, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{}, + WindowsGuestOptions: &WindowsGuestOptions{AdditionalRegistryKeys: []*RegistryValue{}}, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(false), + }, + }, + }, + }, + }, + }, + }, + { + name: "Explicit_NUMA_Topology", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + shimannotations.NumaMappedPhysicalNodes: "0,1", + shimannotations.NumaCountOfProcessors: "4,4", + shimannotations.NumaCountOfMemoryBlocks: "8192,8192", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{ + NumaMappedPhysicalNodes: []uint32{0, 1}, + NumaProcessorCounts: []uint32{4, 4}, + NumaMemoryBlocksCounts: []uint64{8192, 8192}, + }, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{}, + LinuxGuestOptions: &LinuxGuestOptions{ExtraVsockPorts: []uint32{}}, + LinuxDeviceOptions: &LinuxDeviceOptions{AssignedDevices: []*Device{}}, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + { + name: "CPUGroup_And_ResourcePartition", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: map[string]string{ + shimannotations.CPUGroupID: "cg-123", + shimannotations.ResourcePartitionID: "rp-abc", + }, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + CpuGroupID: ptr("cg-123"), + ResourcePartitionID: ptr("rp-abc"), + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{}, + WindowsGuestOptions: &WindowsGuestOptions{AdditionalRegistryKeys: []*RegistryValue{}}, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(false), + }, + }, + }, + }, + }, + }, + }, + + // ==================================================================== + // SECTION 5: Edge Cases, Nil Checks, and Errors + // ==================================================================== + { + name: "ProcessIsolation_Returns_ProcessSpec", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_PROCESS, + }, + annotations: nil, + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Process{ + Process: &ProcessIsolated{}, + }, + }, + }, + { + name: "NilOptions_ShouldError", + opts: nil, + annotations: map[string]string{}, + expectError: true, + expected: nil, + }, + { + name: "Platform_Empty_ShouldError", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "", + }, + annotations: map[string]string{}, + expectError: true, + expected: nil, + }, + { + name: "Platform_UnsupportedOS_ShouldError", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "darwin/arm64", + }, + annotations: map[string]string{}, + expectError: true, + expected: nil, + }, + { + name: "LinuxBoot_PreferredRootFSType_Invalid_ShouldError", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + shimannotations.PreferredRootFSType: "not-a-valid-type", + }, + expectError: true, + expected: nil, + }, + { + name: "Safety_Garbage_Inputs_ShouldNotPanic", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "linux/amd64", + }, + annotations: map[string]string{ + shimannotations.ProcessorCount: "NOT_A_NUMBER", + shimannotations.MemorySizeInMB: "-100", + shimannotations.NumaPreferredPhysicalNodes: "garbage,data", + }, + expectError: false, + // Should return a valid default spec because parsing errors are logged + // and ignored (returning default values like 0/nil). + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{}, + LinuxGuestOptions: &LinuxGuestOptions{ExtraVsockPorts: []uint32{}}, + LinuxDeviceOptions: &LinuxDeviceOptions{AssignedDevices: []*Device{}}, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + }, + }, + }, + }, + }, + }, + }, + { + name: "Safety_Nil_Maps_And_Slices", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: nil, // Nil annotations map + devices: nil, // Nil devices slice + expectError: false, + expected: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + StorageConfig: &StorageConfig{}, + NumaConfig: &NUMAConfig{}, + AdditionalConfig: &AdditionalConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{}, + WindowsGuestOptions: &WindowsGuestOptions{AdditionalRegistryKeys: []*RegistryValue{}}, + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{NoSecurityHardware: ptr(false)}, + DisableSecureBoot: ptr(false), + }, + }, + }, + }, + }, + }, + }, + + // ==================================================================== + // SECTION 6: NEGATIVE TEST CASES (Expect Errors) + // ==================================================================== + { + name: "Negative_Conflicting_HostProcess_Annotations", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/amd64", + }, + annotations: map[string]string{ + shimannotations.HostProcessContainer: "true", + shimannotations.DisableHostProcessContainer: "true", + }, + expectError: true, + expected: nil, + }, + { + name: "Negative_Invalid_Platform_Format_NoSlash", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows_amd64", + }, + annotations: map[string]string{}, + expectError: true, + expected: nil, + }, + { + name: "Negative_Invalid_Platform_Format_MissingArch", + opts: &runhcsoptions.Options{ + SandboxIsolation: runhcsoptions.Options_HYPERVISOR, + SandboxPlatform: "windows/", + }, + annotations: map[string]string{}, + expectError: true, + expected: nil, + }, + } + + for _, tt := range tests { + safeTestRun(t, tt.name, func(t *testing.T) { + t.Helper() + got, err := Generate(tt.opts, tt.annotations, tt.devices) + + // 1. Error Validation + if tt.expectError { + if err == nil { + t.Error("Expected error, got nil") + } + return + } + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // 2. Golden Object Comparison using proto.Equal + if !proto.Equal(got, tt.expected) { + // Since we can't use cmp.Diff, we use JSON for a readable diff in the error logs + gotJSON, _ := json.MarshalIndent(got, "", " ") + wantJSON, _ := json.MarshalIndent(tt.expected, "", " ") + t.Errorf("GenerateSpecss() mismatch.\nGot:\n%s\n\nWant:\n%s", gotJSON, wantJSON) + } + }) + } +} + +// safeTestRun wraps the test execution to catch any panics. +func safeTestRun(t *testing.T, name string, testFunc func(t *testing.T)) { + t.Helper() + t.Run(name, func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Fatalf("PANIC DETECTED in test case '%s': %v", name, r) + } + }() + testFunc(t) + }) +} diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs.go b/cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs.go new file mode 100644 index 0000000000..858b9f961a --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs.go @@ -0,0 +1,627 @@ +//go:build windows + +package sandboxspec + +import ( + "context" + "fmt" + "maps" + "runtime" + "strings" + + "github.com/Microsoft/go-winio/pkg/guid" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/log" + "github.com/Microsoft/hcsshim/internal/oci" + "github.com/Microsoft/hcsshim/internal/uvm" + "github.com/containerd/platforms" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" +) + +var ( + // linuxPlatformFormat represents the format for linux platform. + // Example: linux/amd64 + linuxPlatformFormat = "linux/%s" + // windowsPlatformFormat represents the format for windows platform. + // Example: windows/amd64 + windowsPlatformFormat = "windows/%s" +) + +// BuildUVMOptions creates either LCOW or WCOW options from Specs. +// Defaults are set by NewDefaultOptionsLCOW/NewDefaultOptionsWCOW and +// then overridden by any fields present in the proto. +func BuildUVMOptions(ctx context.Context, spec *Specs, id, owner string) (*uvm.OptionsLCOW, *uvm.OptionsWCOW, *platforms.Platform, error) { + if spec == nil { + return nil, nil, nil, fmt.Errorf("nil sandbox specs") + } + + switch isolation := spec.IsolationLevel.(type) { + case *Specs_Process: + // Process isolation: no UVM to create. + return nil, nil, nil, fmt.Errorf("uvm options cannot be created for process isolation") + + case *Specs_Hypervisor: + hypervisor := isolation.Hypervisor + if hypervisor == nil { + return nil, nil, nil, fmt.Errorf("hypervisor section is nil for isolation_level=hypervisor") + } + + switch platform := hypervisor.Platform.(type) { + case *HypervisorIsolated_Lcow: + if platform.Lcow == nil { + return nil, nil, nil, fmt.Errorf("lcow params are nil for isolation_level=hypervisor") + } + + var plat *platforms.Platform + var err error + + optionsLCOW := uvm.NewDefaultOptionsLCOW(id, owner) + + // Platform-specific overlays + if lb := platform.Lcow.GetLinuxBootOptions(); lb != nil { + applyLinuxBootOptions(ctx, optionsLCOW, lb) + } + if lg := platform.Lcow.GetLinuxGuestOptions(); lg != nil { + applyLinuxGuestOptions(optionsLCOW, lg) + } + if ld := platform.Lcow.GetLinuxDeviceOptions(); ld != nil { + if err = applyLinuxDeviceOptions(ctx, optionsLCOW, ld); err != nil { + return nil, nil, nil, err + } + } + + // Common overlays + if cpu := hypervisor.GetCpuConfig(); cpu != nil { + applyCPUConfig(optionsLCOW.Options, cpu) + plat, err = parsePlatform(cpu, true) + if err != nil { + return nil, nil, nil, err + } + } + if mem := hypervisor.GetMemoryConfig(); mem != nil { + applyMemoryConfig(optionsLCOW.Options, mem) + + if hypervisor.MemoryConfig.FullyPhysicallyBacked != nil && *hypervisor.MemoryConfig.FullyPhysicallyBacked { + optionsLCOW.AllowOvercommit = false + optionsLCOW.VPMemDeviceCount = 0 + } + } + if sto := hypervisor.GetStorageConfig(); sto != nil { + applyStorageConfig(optionsLCOW.Options, sto) + } + if numa := hypervisor.GetNumaConfig(); numa != nil { + applyNUMAConfig(optionsLCOW.Options, numa) + } + + if add := hypervisor.GetAdditionalConfig(); add != nil { + applyAdditionalConfig(ctx, optionsLCOW.Options, add) + } + + if err = applyHypervisorConfig(optionsLCOW.Options, hypervisor); err != nil { + return nil, nil, nil, err + } + // LCOW Confidential options + if lc := platform.Lcow.GetConfidentialOptions(); lc != nil { + applyLCOWConfidentialOptions(optionsLCOW, lc) + } + + return optionsLCOW, nil, plat, nil + + case *HypervisorIsolated_Wcow: + if platform.Wcow == nil { + return nil, nil, nil, fmt.Errorf("wcow params are nil for isolation_level=hypervisor") + } + + var plat *platforms.Platform + var err error + + optionsWCOW := uvm.NewDefaultOptionsWCOW(id, owner) + + // Platform-specific overlays + wb := platform.Wcow.GetWindowsBootOptions() + if wb != nil { + applyWindowsBootOptions(optionsWCOW, wb) + } + + wg := platform.Wcow.GetWindowsGuestOptions() + if wg != nil { + if err = applyWindowsGuestOptions(ctx, optionsWCOW, wg); err != nil { + return nil, nil, nil, err + } + } + + // Common overlays + if cpu := hypervisor.GetCpuConfig(); cpu != nil { + applyCPUConfig(optionsWCOW.Options, cpu) + plat, err = parsePlatform(cpu, false) + if err != nil { + return nil, nil, nil, err + } + } + if mem := hypervisor.GetMemoryConfig(); mem != nil { + applyMemoryConfig(optionsWCOW.Options, mem) + + if hypervisor.MemoryConfig.FullyPhysicallyBacked != nil && *hypervisor.MemoryConfig.FullyPhysicallyBacked { + optionsWCOW.AllowOvercommit = false + } + } + if sto := hypervisor.GetStorageConfig(); sto != nil { + applyStorageConfig(optionsWCOW.Options, sto) + } + if numa := hypervisor.GetNumaConfig(); numa != nil { + applyNUMAConfig(optionsWCOW.Options, numa) + } + if add := hypervisor.GetAdditionalConfig(); add != nil { + applyAdditionalConfig(ctx, optionsWCOW.Options, add) + } + + if err = applyHypervisorConfig(optionsWCOW.Options, hypervisor); err != nil { + return nil, nil, nil, err + } + + // WCOW Confidential options + if wc := platform.Wcow.GetConfidentialOptions(); wc != nil { + err = applyWCOWConfidentialOptions(optionsWCOW, wc, wg, hypervisor.GetMemoryConfig()) + if err != nil { + return nil, nil, nil, err + } + } + + return nil, optionsWCOW, plat, nil + + default: + return nil, nil, nil, fmt.Errorf("hypervisor.platform must be LCOW or WCOW") + } + + default: + return nil, nil, nil, fmt.Errorf("unknown isolation_level") + } +} + +// ----------------------------------------------------------------------------- +// Common overlays +// ----------------------------------------------------------------------------- + +func applyCPUConfig(common *uvm.Options, cpu *CPUConfig) { + // processor_count: unset => keep defaults; set==0 => error + if cpu.ProcessorCount != nil && *cpu.ProcessorCount > 0 { + common.ProcessorCount = *cpu.ProcessorCount + } + + // processor_limit: unset => keep defaults; set==0 => error + if cpu.ProcessorLimit != nil && *cpu.ProcessorLimit > 0 { + common.ProcessorLimit = *cpu.ProcessorLimit + } + + // processor_weight: unset => keep defaults; set==0 => error + if cpu.ProcessorWeight != nil && *cpu.ProcessorWeight > 0 { + common.ProcessorWeight = *cpu.ProcessorWeight + } +} + +func parsePlatform(cpu *CPUConfig, isLinux bool) (*platforms.Platform, error) { + arch := runtime.GOARCH + if cpu.Architecture != nil { + arch = *cpu.Architecture + } + + var plat platforms.Platform + var err error + if isLinux { + plat, err = platforms.Parse(fmt.Sprintf(linuxPlatformFormat, arch)) + } else { + plat, err = platforms.Parse(fmt.Sprintf(windowsPlatformFormat, arch)) + } + + if err != nil { + return nil, fmt.Errorf("failed to parse platform: %w", err) + } + + return &plat, nil +} + +func applyMemoryConfig(common *uvm.Options, mem *MemoryConfig) { + // Additional check to ensure that Memory Size is non-zero. + if mem.MemorySizeInMb != nil && *mem.MemorySizeInMb > 0 { + common.MemorySizeInMB = *mem.MemorySizeInMb + } + + // MMIO: only overlay when non-zero in proto (your defaults are zero unless tuned) + setU64(&common.LowMMIOGapInMB, mem.LowMmioGapInMb) + setU64(&common.HighMMIOBaseInMB, mem.HighMmioBaseInMb) + setU64(&common.HighMMIOGapInMB, mem.HighMmioGapInMb) + + setBool(&common.AllowOvercommit, mem.AllowOvercommit) + setBool(&common.FullyPhysicallyBacked, mem.FullyPhysicallyBacked) + setBool(&common.EnableDeferredCommit, mem.EnableDeferredCommit) +} + +func applyStorageConfig(common *uvm.Options, sto *StorageConfig) { + if sto.StorageQosIopsMaximum != nil && *sto.StorageQosIopsMaximum > 0 { + common.StorageQoSIopsMaximum = *sto.StorageQosIopsMaximum + } + + if sto.StorageQosBandwidthMaximum != nil && *sto.StorageQosBandwidthMaximum > 0 { + common.StorageQoSBandwidthMaximum = *sto.StorageQosBandwidthMaximum + } + + setBool(&common.NoWritableFileShares, sto.NoWritableFileShares) +} + +func applyNUMAConfig(common *uvm.Options, n *NUMAConfig) { + setU32(&common.MaxProcessorsPerNumaNode, n.MaxProcessorsPerNumaNode) + setU64(&common.MaxMemorySizePerNumaNode, n.MaxMemorySizePerNumaNode) + + if len(n.PreferredPhysicalNumaNodes) > 0 { + common.PreferredPhysicalNumaNodes = copyU32(n.PreferredPhysicalNumaNodes) + } + if len(n.NumaMappedPhysicalNodes) > 0 { + common.NumaMappedPhysicalNodes = copyU32(n.NumaMappedPhysicalNodes) + } + if len(n.NumaProcessorCounts) > 0 { + common.NumaProcessorCounts = copyU32(n.NumaProcessorCounts) + } + if len(n.NumaMemoryBlocksCounts) > 0 { + common.NumaMemoryBlocksCounts = copyU64(n.NumaMemoryBlocksCounts) + } +} + +func applyAdditionalConfig(ctx context.Context, common *uvm.Options, a *AdditionalConfig) { + setStr(&common.NetworkConfigProxy, a.NetworkConfigProxy) + setStr(&common.ProcessDumpLocation, a.ProcessDumpLocation) + setStr(&common.DumpDirectoryPath, a.DumpDirectoryPath) + setStr(&common.ConsolePipe, a.ConsolePipe) + + if len(a.AdditionalHypervConfig) > 0 { + maps.Copy(common.AdditionalHyperVConfig, parseHVSocketServiceTable(ctx, a.AdditionalHypervConfig)) + } +} + +func parseHVSocketServiceTable(ctx context.Context, hyperVConfig map[string]*HvSocketServiceConfig) map[string]hcsschema.HvSocketServiceConfig { + parsedServiceTable := make(map[string]hcsschema.HvSocketServiceConfig) + + for key, val := range hyperVConfig { + parsedGUID, err := guid.FromString(key) + if err != nil { + log.G(ctx).WithError(err).Warn("invalid GUID string for Hyper-V socket service configuration annotation") + continue + } + guidStr := parsedGUID.String() // overwrite the GUID string to standardize format (capitalization) + + cfg := hcsschema.HvSocketServiceConfig{} + setStr(&cfg.BindSecurityDescriptor, val.BindSecurityDescriptor) + setStr(&cfg.ConnectSecurityDescriptor, val.ConnectSecurityDescriptor) + setBool(&cfg.AllowWildcardBinds, val.AllowWildcardBinds) + setBool(&cfg.Disabled, val.Disabled) + + if _, found := parsedServiceTable[guidStr]; found { + log.G(ctx).WithFields(logrus.Fields{ + "guid": guidStr, + }).Warn("overwritting existing Hyper-V socket service configuration") + } + + if log.G(ctx).Logger.IsLevelEnabled(logrus.TraceLevel) { + log.G(ctx).WithField("configuration", log.Format(ctx, cfg)).Trace("found Hyper-V socket service configuration annotation") + } + + parsedServiceTable[guidStr] = cfg + } + + return parsedServiceTable +} + +func applyHypervisorConfig(common *uvm.Options, hypervisor *HypervisorIsolated) error { + setStr(&common.CPUGroupID, hypervisor.CpuGroupID) + + if hypervisor.ResourcePartitionID != nil { + resourcePartitionID := *hypervisor.ResourcePartitionID + resourcePartitionIDGUID, err := guid.FromString(resourcePartitionID) + if err != nil { + return fmt.Errorf("failed to parse resource partition id %q to GUID: %w", resourcePartitionID, err) + } + common.ResourcePartitionID = &resourcePartitionIDGUID + } + + return nil +} + +// ----------------------------------------------------------------------------- +// LCOW overlays +// ----------------------------------------------------------------------------- + +func applyLinuxBootOptions(ctx context.Context, opts *uvm.OptionsLCOW, lb *LinuxBootOptions) { + setBool(&opts.EnableColdDiscardHint, lb.EnableColdDiscardHint) + + if lb.BootFilesPath != nil { + // Prefer the helper to update associated fields automatically. + opts.UpdateBootFilesPath(ctx, *lb.BootFilesPath) + } + + setStr(&opts.KernelBootOptions, lb.KernelBootOptions) + + setBool(&opts.KernelDirect, lb.KernelDirect) + if !opts.KernelDirect { + opts.KernelFile = uvm.KernelFile + } + + if lb.PreferredRootFsType != nil { + switch *lb.PreferredRootFsType { + case PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_INITRD: + opts.PreferredRootFSType = uvm.PreferredRootFSTypeInitRd + case PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_VHD: + opts.PreferredRootFSType = uvm.PreferredRootFSTypeVHD + default: + log.G(ctx).Warn("PreferredRootFsType must be 'initrd' or 'vhd'") + } + } + + switch opts.PreferredRootFSType { + case uvm.PreferredRootFSTypeInitRd: + opts.RootFSFile = uvm.InitrdFile + case uvm.PreferredRootFSTypeVHD: + opts.RootFSFile = uvm.VhdFile + } + + // HCL is presence-aware + if lb.HclEnabled != nil { + val := *lb.HclEnabled + opts.HclEnabled = &val + } else { + opts.HclEnabled = nil + } +} + +func applyLinuxGuestOptions(opts *uvm.OptionsLCOW, lg *LinuxGuestOptions) { + setBool(&opts.DisableTimeSyncService, lg.DisableTimeSyncService) + + if len(lg.ExtraVsockPorts) > 0 { + opts.ExtraVSockPorts = copyU32(lg.ExtraVsockPorts) + } + setBool(&opts.PolicyBasedRouting, lg.PolicyBasedRouting) + setBool(&opts.WritableOverlayDirs, lg.WritableOverlayDirs) +} + +func applyLinuxDeviceOptions(ctx context.Context, opts *uvm.OptionsLCOW, ld *LinuxDeviceOptions) error { + setU32(&opts.VPMemDeviceCount, ld.VpMemDeviceCount) + setU64(&opts.VPMemSizeBytes, ld.VpMemSizeBytes) + setBool(&opts.VPMemNoMultiMapping, ld.VpMemNoMultiMapping) + setBool(&opts.VPCIEnabled, ld.VpciEnabled) + + windowsDevices := make([]specs.WindowsDevice, 0, len(ld.AssignedDevices)) + for _, device := range ld.AssignedDevices { + windowsDevices = append(windowsDevices, specs.WindowsDevice{ + ID: device.ID, + IDType: device.IdType, + }) + } + opts.AssignedDevices = oci.ParseDevices(ctx, windowsDevices) + + return nil +} + +func applyLCOWConfidentialOptions(opts *uvm.OptionsLCOW, lc *LCOWConfidentialOptions) { + if lc.Options != nil { + applyCommonConfidentialLCOW(opts.ConfidentialLCOWOptions, lc.Options) + } + + setStr(&opts.GuestStateFile, lc.Options.GuestStateFile) + setStr(&opts.DmVerityRootFsVhd, lc.DmVerityRootFsVhd) + setBool(&opts.DmVerityMode, lc.DmVerityMode) + setStr(&opts.DmVerityCreateArgs, lc.DmVerityCreateArgs) + + if lc.Options.NoSecurityHardware != nil { + oci.HandleLCOWSecurityPolicyWithNoSecurityHardware(*lc.Options.NoSecurityHardware, opts) + } + + if len(opts.SecurityPolicy) > 0 { + opts.EnableScratchEncryption = true + setBool(&opts.EnableScratchEncryption, lc.EnableScratchEncryption) + } +} + +// ----------------------------------------------------------------------------- +// WCOW overlays +// ----------------------------------------------------------------------------- + +func applyWindowsBootOptions(opts *uvm.OptionsWCOW, wb *WindowsBootOptions) { + setBool(&opts.DisableCompartmentNamespace, wb.DisableCompartmentNamespace) + setBool(&opts.NoDirectMap, wb.NoDirectMap) +} + +func applyWindowsGuestOptions(ctx context.Context, opts *uvm.OptionsWCOW, wg *WindowsGuestOptions) error { + setBool(&opts.NoInheritHostTimezone, wg.NoInheritHostTimezone) + + if len(wg.AdditionalRegistryKeys) != 0 { + opts.AdditionalRegistryKeys = append(opts.AdditionalRegistryKeys, + oci.ValidateAndFilterRegistryValues(ctx, registryValuesFromProto(wg))...) + } + + setBool(&opts.ForwardLogs, wg.ForwardLogs) + setStr(&opts.LogSources, wg.LogSources) + + return nil +} + +func applyWCOWConfidentialOptions( + opts *uvm.OptionsWCOW, + wc *WCOWConfidentialOptions, + guestConfig *WindowsGuestOptions, + memConfig *MemoryConfig) error { + setStr(&opts.SecurityPolicy, wc.Options.SecurityPolicy) + + if len(opts.SecurityPolicy) > 0 { + if wc.Options != nil { + applyCommonConfidentialWCOW(opts.ConfidentialWCOWOptions, wc.Options) + } + + opts.SecurityPolicyEnabled = true + setBool(&opts.DisableSecureBoot, wc.DisableSecureBoot) + + // overcommit isn't allowed when running in confidential mode and minimum of 2GB memory is required. + // We can change default values here, but if user provided specific values in annotations we should error out. + if memConfig == nil || memConfig.GetMemorySizeInMb() == 0 { + // No memory config provided, set to minimum required. + opts.MemorySizeInMB = 2048 + } + if opts.MemorySizeInMB < 2048 { + return fmt.Errorf("minimum 2048MB of memory is required for confidential pods, got: %d", opts.MemorySizeInMB) + } + + opts.IsolationType = "SecureNestedPaging" + if wc.Options.NoSecurityHardware != nil && *wc.Options.NoSecurityHardware { + opts.IsolationType = "GuestStateOnly" + } + setStr(&opts.IsolationType, wc.IsolationType) + err := oci.HandleWCOWIsolationType(opts.IsolationType, opts) + if err != nil { + return err + } + + if guestConfig == nil || guestConfig.ForwardLogs == nil { + // Disable log forwarding by default for confidential containers. + opts.ForwardLogs = false + } + } + + setBool(&opts.WritableEFI, wc.WritableEfi) + + return nil +} + +// ----------------------------------------------------------------------------- +// Confidential (common) +// ----------------------------------------------------------------------------- + +func applyCommonConfidentialLCOW(opts *uvm.ConfidentialLCOWOptions, c *ConfidentialOptions) { + setStr(&opts.SecurityPolicy, c.SecurityPolicy) + setStr(&opts.SecurityPolicyEnforcer, c.SecurityPolicyEnforcer) + setStr(&opts.UVMReferenceInfoFile, c.UvmReferenceInfoFile) +} + +func applyCommonConfidentialWCOW(opts *uvm.ConfidentialWCOWOptions, c *ConfidentialOptions) { + setStr(&opts.GuestStateFilePath, c.GuestStateFile) + setStr(&opts.SecurityPolicyEnforcer, c.SecurityPolicyEnforcer) + setStr(&opts.UVMReferenceInfoFile, c.UvmReferenceInfoFile) +} + +// Proto adapter: map proto values to hcsschema.RegistryValue. +func registryValuesFromProto(wgo *WindowsGuestOptions) []hcsschema.RegistryValue { + if wgo == nil || len(wgo.AdditionalRegistryKeys) == 0 { + return []hcsschema.RegistryValue{} + } + + out := make([]hcsschema.RegistryValue, 0, len(wgo.AdditionalRegistryKeys)) + for _, pv := range wgo.AdditionalRegistryKeys { + if pv == nil { + continue + } + + var key *hcsschema.RegistryKey + if pv.Key != nil { + key = &hcsschema.RegistryKey{ + Hive: mapProtoHive(pv.Key.Hive), + Name: strings.TrimSpace(pv.Key.Name), + Volatile: pv.Key.Volatile, + } + } + + out = append(out, hcsschema.RegistryValue{ + Key: key, + Name: strings.TrimSpace(pv.Name), + Type_: mapProtoRegValueType(pv.Type), + StringValue: pv.StringValue, + BinaryValue: pv.BinaryValue, + DWordValue: pv.DwordValue, + QWordValue: pv.QwordValue, + CustomType: pv.CustomType, + }) + } + return out +} + +// ----------------------------------------------------------------------------- +// Small utilities to reduce nil-check boilerplate +// ----------------------------------------------------------------------------- + +// Map proto RegistryHive -> hcsschema.RegistryHive. +func mapProtoHive(h RegistryHive) hcsschema.RegistryHive { + switch h { + case RegistryHive_REGISTRY_HIVE_SYSTEM: + return hcsschema.RegistryHive_SYSTEM + case RegistryHive_REGISTRY_HIVE_SOFTWARE: + return hcsschema.RegistryHive_SOFTWARE + case RegistryHive_REGISTRY_HIVE_SECURITY: + return hcsschema.RegistryHive_SECURITY + case RegistryHive_REGISTRY_HIVE_SAM: + return hcsschema.RegistryHive_SAM + default: + return hcsschema.RegistryHive_SYSTEM + } +} + +// Map proto RegistryValueType -> hcsschema.RegistryValueType. +func mapProtoRegValueType(t RegistryValueType) hcsschema.RegistryValueType { + switch t { + case RegistryValueType_REGISTRY_VALUE_TYPE_NONE: + return hcsschema.RegistryValueType_NONE + case RegistryValueType_REGISTRY_VALUE_TYPE_STRING: + return hcsschema.RegistryValueType_STRING + case RegistryValueType_REGISTRY_VALUE_TYPE_EXPANDED_STRING: + return hcsschema.RegistryValueType_EXPANDED_STRING + case RegistryValueType_REGISTRY_VALUE_TYPE_MULTI_STRING: + return hcsschema.RegistryValueType_MULTI_STRING + case RegistryValueType_REGISTRY_VALUE_TYPE_BINARY: + return hcsschema.RegistryValueType_BINARY + case RegistryValueType_REGISTRY_VALUE_TYPE_D_WORD: + return hcsschema.RegistryValueType_D_WORD + case RegistryValueType_REGISTRY_VALUE_TYPE_Q_WORD: + return hcsschema.RegistryValueType_Q_WORD + case RegistryValueType_REGISTRY_VALUE_TYPE_CUSTOM_TYPE: + return hcsschema.RegistryValueType_CUSTOM_TYPE + default: + return hcsschema.RegistryValueType_NONE + } +} + +// setStr sets dst to the value of src if src is non-nil. +func setStr(dst *string, src *string) { + if src != nil { + *dst = *src + } +} + +// setBool sets dst to the value of src if src is non-nil. +func setBool(dst *bool, src *bool) { + if src != nil { + *dst = *src + } +} + +// setU32 sets dst to the value of src if src is non-nil. +func setU32(dst *uint32, src *uint32) { + if src != nil { + *dst = *src + } +} + +// setU64 sets dst to the value of src if src is non-nil. +func setU64(dst *uint64, src *uint64) { + if src != nil { + *dst = *src + } +} + +// copyU32 returns a copy of in. +func copyU32(in []uint32) []uint32 { + out := make([]uint32, len(in)) + copy(out, in) + return out +} + +// copyU64 returns a copy of in. +func copyU64(in []uint64) []uint64 { + out := make([]uint64, len(in)) + copy(out, in) + return out +} diff --git a/cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs_test.go b/cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs_test.go new file mode 100644 index 0000000000..8e18531f86 --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/sandboxspec/uvm_specs_test.go @@ -0,0 +1,752 @@ +//go:build windows + +package sandboxspec + +import ( + "context" + "reflect" + "testing" + + "github.com/Microsoft/go-winio/pkg/guid" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/uvm" + + "github.com/containerd/platforms" + "github.com/google/go-cmp/cmp" +) + +func TestBuildUVMOptions(t *testing.T) { + // Common test constants + const ( + id = "test-id" + owner = "test-owner" + ) + validGUID := "00000000-0000-0000-0000-000000000001" + + // Helper to create a base LCOW option set for expectations + baseLCOW := func() *uvm.OptionsLCOW { + return uvm.NewDefaultOptionsLCOW(id, owner) + } + + // Helper to create a base WCOW option set for expectations + baseWCOW := func() *uvm.OptionsWCOW { + return uvm.NewDefaultOptionsWCOW(id, owner) + } + + type testCase struct { + name string + spec *Specs + expectedLCOW *uvm.OptionsLCOW + expectedWCOW *uvm.OptionsWCOW + expectedPlat *platforms.Platform + expectError bool + } + + tests := []testCase{ + // ==================================================================== + // LCOW Tests + // ==================================================================== + { + name: "LCOW_Success_FullMapping", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{ + Architecture: ptr("amd64"), + ProcessorCount: ptr(int32(4)), + }, + MemoryConfig: &MemoryConfig{ + MemorySizeInMb: ptr(uint64(2048)), + }, + StorageConfig: &StorageConfig{ + StorageQosIopsMaximum: ptr(int32(1000)), + }, + ResourcePartitionID: ptr(validGUID), + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{ + KernelDirect: ptr(true), + KernelBootOptions: ptr("debug"), + }, + LinuxGuestOptions: &LinuxGuestOptions{ + DisableTimeSyncService: ptr(true), + }, + }, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + o.ProcessorCount = 4 + o.MemorySizeInMB = 2048 + o.StorageQoSIopsMaximum = 1000 + g, _ := guid.FromString(validGUID) + o.ResourcePartitionID = &g + + // LCOW Specifics + o.KernelDirect = true + o.KernelBootOptions = "debug" + o.DisableTimeSyncService = true + o.EnableScratchEncryption = false // default + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + // LCOW Confidential Overrides + // Testing that Confidential options are applied correctly. + { + name: "LCOW_Confidential_Overrides", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + SecurityPolicy: ptr("policy-string"), + }, + }, + }, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + o.SecurityPolicy = "policy-string" + o.EnableScratchEncryption = true // implicitly set + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + + // LCOW "Kitchen Sink" + // Testing the interaction of Custom Boot, complex NUMA, Device assignment, + // and Confidential settings simultaneously. + { + name: "LCOW_KitchenSink", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{ + Architecture: ptr("amd64"), + ProcessorCount: ptr(int32(8)), + ProcessorLimit: ptr(int32(90000)), // 90% + ProcessorWeight: ptr(int32(500)), + }, + MemoryConfig: &MemoryConfig{ + MemorySizeInMb: ptr(uint64(4096)), + LowMmioGapInMb: ptr(uint64(128)), + HighMmioBaseInMb: ptr(uint64(1024)), + AllowOvercommit: ptr(false), + }, + NumaConfig: &NUMAConfig{ + MaxProcessorsPerNumaNode: ptr(uint32(4)), + PreferredPhysicalNumaNodes: []uint32{0, 1}, + }, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{ + // Setting a custom path should trigger UpdateBootFilesPath logic + BootFilesPath: ptr(`C:\Custom\Boot`), + PreferredRootFsType: ptr(PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_VHD), + HclEnabled: ptr(true), + }, + LinuxGuestOptions: &LinuxGuestOptions{ + ExtraVsockPorts: []uint32{8080, 9090}, + PolicyBasedRouting: ptr(true), + WritableOverlayDirs: ptr(true), + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + SecurityPolicy: ptr("base64-policy-data"), + }, + DmVerityMode: ptr(true), + }, + // Device options with mocked values + LinuxDeviceOptions: &LinuxDeviceOptions{ + VpMemDeviceCount: ptr(uint32(16)), + VpciEnabled: ptr(true), + // Note: Actual device ID parsing depends on 'oci.ParseDevices' logic. + // We assume simple passthrough for the unit test context here. + AssignedDevices: []*Device{ + {ID: "class/8888", IdType: "vpci"}, + }, + }, + }, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + // CPU & Memory + o.ProcessorCount = 8 + o.ProcessorLimit = 90000 + o.ProcessorWeight = 500 + o.MemorySizeInMB = 4096 + o.LowMMIOGapInMB = 128 + o.HighMMIOBaseInMB = 1024 + o.AllowOvercommit = false + + // NUMA + o.MaxProcessorsPerNumaNode = 4 + o.PreferredPhysicalNumaNodes = []uint32{0, 1} + + // Boot Options (UpdateBootFilesPath logic simulation) + o.BootFilesPath = `C:\Custom\Boot` + // Note: UpdateBootFilesPath in the real code checks for file existence (os.Stat). + // In a unit test environment without those files, it updates the path string + // but might not auto-update RootFSFile unless mocked. + // Based on your provided code, it sets the path string at minimum. + o.PreferredRootFSType = uvm.PreferredRootFSTypeVHD + o.RootFSFile = uvm.VhdFile // VHD type implies this file name + hcl := true + o.HclEnabled = &hcl + + // Guest Options + o.ExtraVSockPorts = []uint32{8080, 9090} + o.PolicyBasedRouting = true + o.WritableOverlayDirs = true + + // Confidential + o.SecurityPolicy = "base64-policy-data" + o.DmVerityMode = true + o.EnableScratchEncryption = true // Side effect of having SecurityPolicy + + // Devices + o.VPMemDeviceCount = 16 + o.VPCIEnabled = true + devs := make([]uvm.VPCIDeviceID, 0) + devs = append(devs, uvm.NewVPCIDeviceID("class", 8888)) + o.AssignedDevices = devs + + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + + // Logic Test: Logic_LCOW_Overrides Overrides for LCOW + // - FullyPhysicallyBacked == true, then AllowOvercommit=false and VPMemDeviceCount=0 (for LCOW). + // - Check for KernelFile when KernelDirect is false. + // - Validate the PreferredRootFsType mapping. + { + name: "Logic_LCOW_Overrides", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{ + FullyPhysicallyBacked: ptr(true), + // Even if we explicitly ask for overcommit, PhysicallyBacked should win + AllowOvercommit: ptr(true), + }, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxBootOptions: &LinuxBootOptions{ + KernelDirect: ptr(false), + PreferredRootFsType: ptr(PreferredRootFSType_PREFERRED_ROOT_FS_TYPE_INITRD), + }, + LinuxDeviceOptions: &LinuxDeviceOptions{ + // Even if we ask for devices, PhysicallyBacked should force 0 + VpMemDeviceCount: ptr(uint32(50)), + }, + }, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + o.FullyPhysicallyBacked = true + o.AllowOvercommit = false // Overridden + o.VPMemDeviceCount = 0 // Overridden + o.KernelDirect = false + o.KernelFile = uvm.KernelFile + o.PreferredRootFSType = uvm.PreferredRootFSTypeInitRd + o.RootFSFile = uvm.InitrdFile + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + + // Logic Test: LCOW SNP Enforcement (NoSecurityHardware = false) + // This verifies that valid SNP hardware settings FORCE specific overrides, + // ignoring conflicting user inputs (like VpMemDeviceCount). + { + name: "Logic_LCOW_SNP_Hardware_Enforcement", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + // User tries to enable Overcommit, but SNP should force it to false + MemoryConfig: &MemoryConfig{AllowOvercommit: ptr(true)}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxDeviceOptions: &LinuxDeviceOptions{ + // User tries to add VPMem, but SNP (without VHD boot) forces 0 + VpMemDeviceCount: ptr(uint32(10)), + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + GuestStateFile: ptr("abcd"), + SecurityPolicy: ptr("policy-string"), + NoSecurityHardware: ptr(false), // Enforce Hardware rules + }, + DmVerityRootFsVhd: ptr("hello"), + }, + }, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + o.SecurityPolicy = "policy-string" + o.EnableScratchEncryption = true + + // --- Forced Overrides by HandleLCOWSecurityPolicyWithNoSecurityHardware --- + o.VPMemDeviceCount = 0 + o.AllowOvercommit = false + o.SecurityPolicyEnabled = true + o.GuestStateFile = uvm.GuestStateFile // uvm.GuestStateFile + o.KernelBootOptions = "" + o.PreferredRootFSType = uvm.PreferredRootFSTypeNA // uvm.PreferredRootFSTypeNA + o.RootFSFile = "" + o.DmVerityRootFsVhd = uvm.DefaultDmVerityRootfsVhd // uvm.DefaultDmVerityRootfsVhd + o.DmVerityMode = true + + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + + // Logic Test: LCOW SNP Dev Mode (NoSecurityHardware = true) + // This verifies that when NoSecurityHardware is set, we SKIP the enforcement + // logic, allowing "unsafe" configurations like VPMem and Overcommit to persist. + { + name: "Logic_LCOW_SNP_NoSecurityHardware_Skip", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + // These settings should be preserved because we are skipping enforcement + MemoryConfig: &MemoryConfig{AllowOvercommit: ptr(true)}, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{ + LinuxDeviceOptions: &LinuxDeviceOptions{ + VpMemDeviceCount: ptr(uint32(10)), + }, + ConfidentialOptions: &LCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + SecurityPolicy: ptr("policy-string"), + NoSecurityHardware: ptr(true), // Skip Enforcement + }, + }, + }, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + o.SecurityPolicy = "policy-string" + + // --- Values should REMAIN as set by user --- + o.VPMemDeviceCount = 10 + o.AllowOvercommit = true + + // Side effect still happens because policy string exists + o.EnableScratchEncryption = true + + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + + // ==================================================================== + // WCOW Tests + // ==================================================================== + { + name: "WCOW_Success_FullMapping", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{ + Architecture: ptr("amd64"), + ProcessorCount: ptr(int32(2)), + }, + AdditionalConfig: &AdditionalConfig{ + ConsolePipe: ptr(`\\.\pipe\test`), + }, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{ + NoDirectMap: ptr(true), + }, + WindowsGuestOptions: &WindowsGuestOptions{ + NoInheritHostTimezone: ptr(true), + LogSources: ptr("Microsoft-Windows-HyperV-Guest-Logs"), + }, + }, + }, + }, + }, + }, + expectedWCOW: func() *uvm.OptionsWCOW { + o := baseWCOW() + o.ProcessorCount = 2 + o.ConsolePipe = `\\.\pipe\test` + o.NoDirectMap = true + o.NoInheritHostTimezone = true + o.ForwardLogs = true // By default for non-confidential + o.LogSources = "Microsoft-Windows-HyperV-Guest-Logs" + return o + }(), + expectedPlat: &platforms.Platform{OS: "windows", Architecture: "amd64"}, + }, + { + name: "WCOW_Confidential_Overrides", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + SecurityPolicy: ptr("policy"), + }, + IsolationType: ptr("SNP"), // Short for SecureNestedPaging + }, + }, + }, + }, + }, + }, + expectedWCOW: func() *uvm.OptionsWCOW { + o := baseWCOW() + o.SecurityPolicy = "policy" + o.SecurityPolicyEnabled = true + o.MemorySizeInMB = 2048 // Default minimum forced by confidential + o.IsolationType = "SecureNestedPaging" + o.AllowOvercommit = false // Forced by SNP + o.ForwardLogs = false // Default for confidential + return o + }(), + expectedPlat: &platforms.Platform{OS: "windows", Architecture: "amd64"}, + }, + // WCOW "Kitchen Sink" with Registry Complexity + // Testing Registry mapping, complex types, and filtering logic interactions. + { + name: "WCOW_KitchenSink", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{ + FullyPhysicallyBacked: ptr(true), + // Even if we explicitly ask for overcommit, PhysicallyBacked should win + AllowOvercommit: ptr(true), + }, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + WindowsBootOptions: &WindowsBootOptions{ + DisableCompartmentNamespace: ptr(true), + }, + WindowsGuestOptions: &WindowsGuestOptions{ + // We must use registry keys that pass the `ValidateAndFilterRegistryValues` allow-list. + // Allowed: HKLM\Software\... + AdditionalRegistryKeys: []*RegistryValue{ + { + Key: &RegistryKey{ + Hive: RegistryHive_REGISTRY_HIVE_SOFTWARE, + Name: "Software\\ContainerPlat\\Test", + }, + Name: "StringVal", + Type: RegistryValueType_REGISTRY_VALUE_TYPE_STRING, + StringValue: "MyString", + }, + { + Key: &RegistryKey{ + Hive: RegistryHive_REGISTRY_HIVE_SOFTWARE, + Name: "Software\\ContainerPlat\\Test", + }, + Name: "DwordVal", + Type: RegistryValueType_REGISTRY_VALUE_TYPE_D_WORD, + DwordValue: 12345, + }, + }, + }, + }, + }, + }, + }, + }, + expectedWCOW: func() *uvm.OptionsWCOW { + o := baseWCOW() + o.DisableCompartmentNamespace = true + o.AdditionalRegistryKeys = []hcsschema.RegistryValue{ + { + Key: &hcsschema.RegistryKey{Hive: hcsschema.RegistryHive_SOFTWARE, Name: "Software\\ContainerPlat\\Test"}, + Name: "StringVal", + Type_: hcsschema.RegistryValueType_STRING, + StringValue: "MyString", + }, + { + Key: &hcsschema.RegistryKey{Hive: hcsschema.RegistryHive_SOFTWARE, Name: "Software\\ContainerPlat\\Test"}, + Name: "DwordVal", + Type_: hcsschema.RegistryValueType_D_WORD, + DWordValue: 12345, + }, + } + o.FullyPhysicallyBacked = true + o.AllowOvercommit = false // Overridden + return o + }(), + expectedPlat: &platforms.Platform{OS: "windows", Architecture: "amd64"}, + }, + // Logic Test: WCOW Confidential Memory Constraint + // Confidential WCOW requires at least 2048MB. + { + name: "Logic_WCOW_Confidential_LowMemory_Error", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{ + MemorySizeInMb: ptr(uint64(1024)), // Too low + }, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + SecurityPolicy: ptr("policy"), + }, + }, + }, + }, + }, + }, + }, + expectError: true, // Should fail validation + }, + // Logic Test: WCOW Isolation Type Shorthands + // Verifying that "VBS" maps to "VirtualizationBasedSecurity" + { + name: "Logic_WCOW_IsolationType", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{ + AllowOvercommit: ptr(true), // Should be overridden + }, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + SecurityPolicy: ptr("policy"), + }, + IsolationType: ptr("VBS"), + }, + }, + }, + }, + }, + }, + expectedWCOW: func() *uvm.OptionsWCOW { + o := baseWCOW() + o.SecurityPolicy = "policy" + o.SecurityPolicyEnabled = true + o.MemorySizeInMB = 2048 + o.IsolationType = "VirtualizationBasedSecurity" // Expanded + o.AllowOvercommit = false + o.ForwardLogs = false + return o + }(), + expectedPlat: &platforms.Platform{OS: "windows", Architecture: "amd64"}, + }, + { + name: "WCOW_Non_Confidential_DoesNotOverride", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + MemoryConfig: &MemoryConfig{}, + Platform: &HypervisorIsolated_Wcow{ + Wcow: &WindowsHyperVOptions{ + ConfidentialOptions: &WCOWConfidentialOptions{ + Options: &ConfidentialOptions{ + GuestStateFile: ptr("abcd"), + }, + DisableSecureBoot: ptr(true), + IsolationType: ptr("SNP"), // Short for SecureNestedPaging + }, + }, + }, + }, + }, + }, + expectedWCOW: func() *uvm.OptionsWCOW { + o := baseWCOW() + return o + }(), + expectedPlat: &platforms.Platform{OS: "windows", Architecture: "amd64"}, + }, + + // ==================================================================== + // Common Config Tests (Registry, HvSocket) + // ==================================================================== + { + name: "Common_HvSocket_ServiceTable", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + AdditionalConfig: &AdditionalConfig{ + AdditionalHypervConfig: map[string]*HvSocketServiceConfig{ + validGUID: { + AllowWildcardBinds: ptr(true), + Disabled: ptr(false), + }, + }, + }, + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{}, + }, + }, + }, + }, + expectedLCOW: func() *uvm.OptionsLCOW { + o := baseLCOW() + o.AdditionalHyperVConfig[validGUID] = hcsschema.HvSocketServiceConfig{ + AllowWildcardBinds: true, + Disabled: false, + } + return o + }(), + expectedPlat: &platforms.Platform{OS: "linux", Architecture: "amd64"}, + }, + + // ==================================================================== + // Error Cases + // ==================================================================== + { + name: "Error_NilSpec", + spec: nil, + expectError: true, + }, + { + name: "Error_ProcessIsolation", + spec: &Specs{ + IsolationLevel: &Specs_Process{}, + }, + expectError: true, + }, + { + name: "Error_MissingHypervisor", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: nil, + }, + }, + expectError: true, + }, + { + name: "Error_MissingPlatform_LCOW", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + Platform: &HypervisorIsolated_Lcow{ + Lcow: nil, + }, + }, + }, + }, + expectError: true, + }, + { + name: "Error_MissingPlatform_WCOW", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + Platform: &HypervisorIsolated_Wcow{ + Wcow: nil, + }, + }, + }, + }, + expectError: true, + }, + { + name: "Error_Invalid_ResourcePartition_GUID", + spec: &Specs{ + IsolationLevel: &Specs_Hypervisor{ + Hypervisor: &HypervisorIsolated{ + CpuConfig: &CPUConfig{Architecture: ptr("amd64")}, + ResourcePartitionID: ptr("not-a-guid"), + Platform: &HypervisorIsolated_Lcow{ + Lcow: &LinuxHyperVOptions{}, + }, + }, + }, + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotLCOW, gotWCOW, gotPlat, err := BuildUVMOptions(context.Background(), tt.spec, id, owner) + + if tt.expectError { + if err == nil { + t.Error("Expected error, got nil") + } + return + } + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // Validate Platform + if !reflect.DeepEqual(gotPlat, tt.expectedPlat) { + t.Errorf("Platform mismatch.\nGot: %+v\nWant: %+v", gotPlat, tt.expectedPlat) + } + + opts := cmp.Options{ + cmp.AllowUnexported(uvm.VPCIDeviceID{}), + } + + if tt.expectedLCOW != nil { + if gotLCOW == nil { + t.Fatal("Expected LCOW options, got nil") + } + + gotLCOW.OutputHandlerCreator = nil + tt.expectedLCOW.OutputHandlerCreator = nil + + if diff := cmp.Diff(tt.expectedLCOW, gotLCOW, opts); diff != "" { + t.Errorf("LCOW Options mismatch (-want +got):\n%s", diff) + } + } else if tt.expectedWCOW != nil { + if gotWCOW == nil { + t.Fatal("Expected WCOW options, got nil") + } + + gotWCOW.OutputHandlerCreator = nil + tt.expectedWCOW.OutputHandlerCreator = nil + + if diff := cmp.Diff(tt.expectedWCOW, gotWCOW, opts); diff != "" { + t.Errorf("WCOW Options mismatch (-want +got):\n%s", diff) + } + } else { + t.Fatal("Test case did not specify expected LCOW or WCOW output") + } + }) + } +} diff --git a/cmd/containerd-shim-runhcs-v1/service_internal.go b/cmd/containerd-shim-runhcs-v1/service_internal.go index 53821191b7..a50bb12224 100644 --- a/cmd/containerd-shim-runhcs-v1/service_internal.go +++ b/cmd/containerd-shim-runhcs-v1/service_internal.go @@ -107,7 +107,7 @@ func (s *service) createInternal(ctx context.Context, req *task.CreateTaskReques spec = oci.UpdateSpecFromOptions(spec, shimOpts) // expand annotations after defaults have been loaded in from options - err = oci.ProcessAnnotations(ctx, &spec) + err = oci.ProcessAnnotations(ctx, spec.Annotations) // since annotation expansion is used to toggle security features // raise it rather than suppress and move on if err != nil { diff --git a/internal/oci/annotations.go b/internal/oci/annotations.go index 7463bc9dfe..e0d64a6129 100644 --- a/internal/oci/annotations.go +++ b/internal/oci/annotations.go @@ -24,7 +24,7 @@ var ErrAnnotationExpansionConflict = errors.New("annotation expansion conflict") var ErrGenericAnnotationConflict = errors.New("specified annotations conflict") // ProcessAnnotations expands annotations into their corresponding annotation groups. -func ProcessAnnotations(ctx context.Context, s *specs.Spec) error { +func ProcessAnnotations(ctx context.Context, specAnnotations map[string]string) error { // Named `Process` and not `Expand` since this function may be expanded (pun intended) to // deal with other annotation issues and validation. @@ -36,11 +36,11 @@ func ProcessAnnotations(ctx context.Context, s *specs.Spec) error { var errs []error for key, exps := range annotations.AnnotationExpansionMap() { // check if annotation is present - if val, ok := s.Annotations[key]; ok { + if val, ok := specAnnotations[key]; ok { // ideally, some normalization would occur here (ie, "True" -> "true") // but strings may be case-sensitive for _, k := range exps { - if v, ok := s.Annotations[k]; ok && val != v { + if v, ok := specAnnotations[k]; ok && val != v { err := fmt.Errorf("%w: %q = %q and %q = %q", ErrAnnotationExpansionConflict, key, val, k, v) errs = append(errs, err) log.G(ctx).WithFields(logrus.Fields{ @@ -51,26 +51,26 @@ func ProcessAnnotations(ctx context.Context, s *specs.Spec) error { }).WithError(err).Warning("annotation expansion would overwrite conflicting value") continue } - s.Annotations[k] = val + specAnnotations[k] = val } } } // validate host process containers annotations are not conflicting - disableHPC := ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableHostProcessContainer, false) - enableHPC := ParseAnnotationsBool(ctx, s.Annotations, annotations.HostProcessContainer, false) + disableHPC := ParseAnnotationsBool(ctx, specAnnotations, annotations.DisableHostProcessContainer, false) + enableHPC := ParseAnnotationsBool(ctx, specAnnotations, annotations.HostProcessContainer, false) if disableHPC && enableHPC { err := fmt.Errorf("%w: host process container annotations %q = %q and %q = %q", ErrGenericAnnotationConflict, - annotations.DisableHostProcessContainer, s.Annotations[annotations.DisableHostProcessContainer], - annotations.HostProcessContainer, s.Annotations[annotations.HostProcessContainer]) + annotations.DisableHostProcessContainer, specAnnotations[annotations.DisableHostProcessContainer], + annotations.HostProcessContainer, specAnnotations[annotations.HostProcessContainer]) errs = append(errs, err) log.G(ctx).WithFields(logrus.Fields{ logfields.OCIAnnotation: annotations.DisableHostProcessContainer, - logfields.Value: s.Annotations[annotations.DisableHostProcessContainer], + logfields.Value: specAnnotations[annotations.DisableHostProcessContainer], logfields.OCIAnnotation + "-conflict": annotations.HostProcessContainer, - logfields.Value + "-conflict": s.Annotations[annotations.HostProcessContainer], + logfields.Value + "-conflict": specAnnotations[annotations.HostProcessContainer], }).WithError(err).Warning("Host process container and disable host process container cannot both be true") } @@ -86,10 +86,10 @@ func ParseAnnotationsDisableGMSA(ctx context.Context, s *specs.Spec) bool { return ParseAnnotationsBool(ctx, s.Annotations, annotations.WCOWDisableGMSA, false) } -// parseAdditionalRegistryValues extracts the additional registry values to set from annotations. +// ParseAdditionalRegistryValues extracts the additional registry values to set from annotations. // // Like the [parseAnnotation*] functions, this logs errors but does not return them. -func parseAdditionalRegistryValues(ctx context.Context, a map[string]string) []hcsschema.RegistryValue { +func ParseAdditionalRegistryValues(ctx context.Context, a map[string]string) []hcsschema.RegistryValue { // rather than have users deal with nil vs []hcsschema.RegistryValue as returns, always // return the latter. // this is mostly to make testing easier, since its awkward to have to differentiate between @@ -108,12 +108,16 @@ func parseAdditionalRegistryValues(ctx context.Context, a map[string]string) []h } // basic error checking: warn about and delete invalid registry keys - rvs := make([]hcsschema.RegistryValue, 0, len(t)) - for _, rv := range t { + return ValidateAndFilterRegistryValues(ctx, t) +} + +func ValidateAndFilterRegistryValues(ctx context.Context, input []hcsschema.RegistryValue) []hcsschema.RegistryValue { + rvs := make([]hcsschema.RegistryValue, 0, len(input)) + + for _, rv := range input { entry := log.G(ctx).WithFields(logrus.Fields{ - logfields.OCIAnnotation: k, - logfields.Value: v, - "registry-value": log.Format(ctx, rv), + logfields.Value: log.Format(ctx, rv), + "registry-value": log.Format(ctx, rv), }) if rv.Key == nil { @@ -157,7 +161,10 @@ func parseAdditionalRegistryValues(ctx context.Context, a map[string]string) []h // multiple values are set b2i := map[bool]int{true: 1} // hack to convert bool to int - if (b2i[rv.StringValue != ""] + b2i[rv.BinaryValue != ""] + b2i[rv.DWordValue != 0] + b2i[rv.QWordValue != 0]) > 1 { + if (b2i[rv.StringValue != ""] + + b2i[rv.BinaryValue != ""] + + b2i[rv.DWordValue != 0] + + b2i[rv.QWordValue != 0]) > 1 { entry.Warning("multiple values set") continue } @@ -204,10 +211,10 @@ func parseAdditionalRegistryValues(ctx context.Context, a map[string]string) []h return slices.Clip(rvs) } -// parseHVSocketServiceTable extracts any additional Hyper-V socket service configurations from annotations. +// ParseHVSocketServiceTable extracts any additional Hyper-V socket service configurations from annotations. // // Like the [parseAnnotation*] functions, this logs errors but does not return them. -func parseHVSocketServiceTable(ctx context.Context, a map[string]string) map[string]hcsschema.HvSocketServiceConfig { +func ParseHVSocketServiceTable(ctx context.Context, a map[string]string) map[string]hcsschema.HvSocketServiceConfig { sc := make(map[string]hcsschema.HvSocketServiceConfig) // TODO(go1.23) use range over functions to implement a functional `filter | map $ a` for k, v := range a { diff --git a/internal/oci/annotations_test.go b/internal/oci/annotations_test.go index eee585fa7b..2879f9f196 100644 --- a/internal/oci/annotations_test.go +++ b/internal/oci/annotations_test.go @@ -117,11 +117,10 @@ func TestProccessAnnotations_HostProcessContainer(t *testing.T) { for _, tt := range testAnnotations { t.Run(tt.name, func(t *testing.T) { spec := specs.Spec{ - Windows: &specs.Windows{}, Annotations: tt.an, } - err := ProcessAnnotations(ctx, &spec) + err := ProcessAnnotations(ctx, spec.Annotations) if err != nil && len(tt.errs) == 0 { t.Fatalf("ProcessAnnotations should have succeeded, instead got %v", err) } @@ -181,7 +180,7 @@ func TestProccessAnnotations_Expansion(t *testing.T) { annotations.DisableUnsafeOperations: v, } - err := ProcessAnnotations(ctx, &tt.spec) + err := ProcessAnnotations(ctx, tt.spec.Annotations) if err != nil { subtest.Fatalf("could not update spec from options: %v", err) } @@ -206,7 +205,7 @@ func TestProccessAnnotations_Expansion(t *testing.T) { annotations.DisableUnsafeOperations, annotations.DisableWritableFileShares) - err := ProcessAnnotations(ctx, &tt.spec) + err := ProcessAnnotations(ctx, tt.spec.Annotations) if !errors.Is(err, ErrAnnotationExpansionConflict) { t.Fatalf("UpdateSpecFromOptions should have failed with %q, actual was %v", errExp, err) } @@ -348,7 +347,7 @@ func TestParseAdditionalRegistryValues(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Logf("registry values:\n%s", tt.give) v := strings.ReplaceAll(tt.give, "\n", "") - rvs := parseAdditionalRegistryValues(ctx, map[string]string{ + rvs := ParseAdditionalRegistryValues(ctx, map[string]string{ "some-random-annotation": "random", "not-microsoft.virtualmachine.wcow.additional-reg-keys": "this is fake", iannotations.AdditionalRegistryValues: v, @@ -460,7 +459,7 @@ func TestParseHVSocketServiceTable(t *testing.T) { maps.Copy(annots, tt.give) t.Logf("annotations:\n%v", annots) - rvs := parseHVSocketServiceTable(ctx, annots) + rvs := ParseHVSocketServiceTable(ctx, annots) t.Logf("got %v", rvs) want := tt.want if want == nil { diff --git a/internal/oci/uvm.go b/internal/oci/uvm.go index 1c5f32c55f..0ea9e056f2 100644 --- a/internal/oci/uvm.go +++ b/internal/oci/uvm.go @@ -198,6 +198,15 @@ func handleLCOWSecurityPolicy(ctx context.Context, a map[string]string, lopts *u // this is not a security issue as the attestation will fail without a genuine report noSecurityHardware := ParseAnnotationsBool(ctx, a, annotations.NoSecurityHardware, false) + HandleLCOWSecurityPolicyWithNoSecurityHardware(noSecurityHardware, lopts) + + if len(lopts.SecurityPolicy) > 0 { + // will only be false if explicitly set false by the annotation. We will otherwise default to true when there is a security policy + lopts.EnableScratchEncryption = ParseAnnotationsBool(ctx, a, annotations.LCOWEncryptedScratchDisk, true) + } +} + +func HandleLCOWSecurityPolicyWithNoSecurityHardware(noSecurityHardware bool, lopts *uvm.OptionsLCOW) { // if there is a security policy (and SNP) we currently boot in a way that doesn't support any boot options // this might change if the building of the vmgs file were to be done on demand but that is likely // much slower and noy very useful. We do respect the filename of the vmgs file so if it is necessary to @@ -222,11 +231,6 @@ func handleLCOWSecurityPolicy(ctx context.Context, a map[string]string, lopts *u lopts.DmVerityRootFsVhd = uvm.DefaultDmVerityRootfsVhd lopts.DmVerityMode = true } - - if len(lopts.SecurityPolicy) > 0 { - // will only be false if explicitly set false by the annotation. We will otherwise default to true when there is a security policy - lopts.EnableScratchEncryption = ParseAnnotationsBool(ctx, a, annotations.LCOWEncryptedScratchDisk, true) - } } // handleWCOWSecurityPolicy handles parsing confidential pods related options and setting @@ -253,15 +257,18 @@ func handleWCOWSecurityPolicy(ctx context.Context, a map[string]string, wopts *u if noSecurityHardware := ParseAnnotationsBool(ctx, a, annotations.NoSecurityHardware, false); noSecurityHardware { wopts.IsolationType = "GuestStateOnly" } - if err := handleWCOWIsolationType(ctx, a, wopts); err != nil { + + if err := HandleWCOWIsolationType( + ParseAnnotationsString(a, annotations.WCOWIsolationType, wopts.IsolationType), + wopts, + ); err != nil { return err } return nil } -func handleWCOWIsolationType(ctx context.Context, a map[string]string, wopts *uvm.OptionsWCOW) error { - isolationType := ParseAnnotationsString(a, annotations.WCOWIsolationType, wopts.IsolationType) +func HandleWCOWIsolationType(isolationType string, wopts *uvm.OptionsWCOW) error { switch isolationType { case "SecureNestedPaging", "SNP": // Allow VBS & SNP shorthands wopts.IsolationType = "SecureNestedPaging" @@ -279,12 +286,22 @@ func handleWCOWIsolationType(ctx context.Context, a map[string]string, wopts *uv return nil } -func parseDevices(ctx context.Context, specWindows *specs.Windows) []uvm.VPCIDeviceID { +func parseDevicesFromSpec(ctx context.Context, specWindows *specs.Windows) []uvm.VPCIDeviceID { if specWindows == nil || specWindows.Devices == nil { return nil } - extraDevices := []uvm.VPCIDeviceID{} - for _, d := range specWindows.Devices { + + extraDevices := ParseDevices(ctx, specWindows.Devices) + + // nil out the devices on the spec so that they aren't re-added to the + // pause container. + specWindows.Devices = nil + return extraDevices +} + +func ParseDevices(ctx context.Context, windowsDevices []specs.WindowsDevice) []uvm.VPCIDeviceID { + var extraDevices []uvm.VPCIDeviceID + for _, d := range windowsDevices { pciID, index := devices.GetDeviceInfoFromPath(d.ID) if uvm.IsValidDeviceType(d.IDType) { key := uvm.NewVPCIDeviceID(pciID, index) @@ -295,9 +312,6 @@ func parseDevices(ctx context.Context, specWindows *specs.Windows) []uvm.VPCIDev }).Warnf("device type %s invalid, skipping", d.IDType) } } - // nil out the devices on the spec so that they aren't re-added to the - // pause container. - specWindows.Devices = nil return extraDevices } @@ -333,7 +347,7 @@ func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *spe opts.NumaMemoryBlocksCounts = ParseAnnotationCommaSeparatedUint64(ctx, s.Annotations, annotations.NumaCountOfMemoryBlocks, opts.NumaMemoryBlocksCounts) - maps.Copy(opts.AdditionalHyperVConfig, parseHVSocketServiceTable(ctx, s.Annotations)) + maps.Copy(opts.AdditionalHyperVConfig, ParseHVSocketServiceTable(ctx, s.Annotations)) // parse error yielding annotations var err error @@ -396,7 +410,7 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) ( lopts.HclEnabled = ParseAnnotationsNullableBool(ctx, s.Annotations, annotations.LCOWHclEnabled) // Add devices on the spec to the UVM's options - lopts.AssignedDevices = parseDevices(ctx, s.Windows) + lopts.AssignedDevices = parseDevicesFromSpec(ctx, s.Windows) lopts.PolicyBasedRouting = ParseAnnotationsBool(ctx, s.Annotations, iannotations.NetworkingPolicyBasedRouting, lopts.PolicyBasedRouting) return lopts, nil } else if IsWCOW(s) { @@ -408,7 +422,7 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) ( wopts.DisableCompartmentNamespace = ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableCompartmentNamespace, wopts.DisableCompartmentNamespace) wopts.NoDirectMap = ParseAnnotationsBool(ctx, s.Annotations, annotations.VSMBNoDirectMap, wopts.NoDirectMap) wopts.NoInheritHostTimezone = ParseAnnotationsBool(ctx, s.Annotations, annotations.NoInheritHostTimezone, wopts.NoInheritHostTimezone) - wopts.AdditionalRegistryKeys = append(wopts.AdditionalRegistryKeys, parseAdditionalRegistryValues(ctx, s.Annotations)...) + wopts.AdditionalRegistryKeys = append(wopts.AdditionalRegistryKeys, ParseAdditionalRegistryValues(ctx, s.Annotations)...) handleAnnotationFullyPhysicallyBacked(ctx, s.Annotations, wopts) // Writable EFI is valid for both confidential and regular Hyper-V isolated WCOW.