Skip to content

Commit f10bd37

Browse files
committed
Attach EFI VHD in read-only mode by default
EFI VHDs should always be attached as read-only by default to block UVMs from writing to it and corrupting its contents. A new annotation is added to allow attaching EFI VHDs in writable mode when debugging boot failures and such. When this annotation is included a copy of the EFI VHD is made next to the scratch VHD. This is based on the assumption that generally the scratch of the UVM would be stored in its own snapshot directory so adding another VHD in there shouldn't be a problem. It should get cleaned up when the snapshot is removed. This commit also adds the code to always grant VM group access to the VHDs and guest state files to avoid access denied failures. Signed-off-by: Amit Barve <ambarve@microsoft.com>
1 parent 8fb5561 commit f10bd37

File tree

4 files changed

+38
-5
lines changed

4 files changed

+38
-5
lines changed

cmd/containerd-shim-runhcs-v1/pod.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111
"sync"
1212

13+
"github.com/Microsoft/hcsshim/internal/copyfile"
1314
"github.com/Microsoft/hcsshim/internal/layers"
1415
"github.com/Microsoft/hcsshim/internal/log"
1516
"github.com/Microsoft/hcsshim/internal/oci"
@@ -58,6 +59,21 @@ func initializeWCOWBootFiles(ctx context.Context, wopts *uvm.OptionsWCOW, rootfs
5859
// we can enable this.
5960
return fmt.Errorf("hyperv isolation is not supported with block CIM layers yet")
6061
}
62+
63+
// writable EFI VHD is a valid config for both confidential and regular hyperv
64+
// isolated WCOW. Override the default value here if required.
65+
if wopts.WritableEFI {
66+
// when attaching EFI in writable mode, make a copy, we don't want the UVM
67+
// to modify the main copy. We currently make copy next to the scratch
68+
// VHD, this assumes that the scratch is located in the separate directory
69+
// dedicated for this UVM.
70+
writableEFIVHDPath := filepath.Join(filepath.Dir(wopts.BootFiles.BlockCIMFiles.ScratchVHDPath), filepath.Base(wopts.BootFiles.BlockCIMFiles.EFIVHDPath))
71+
if err := copyfile.CopyFile(ctx, wopts.BootFiles.BlockCIMFiles.EFIVHDPath, writableEFIVHDPath, false); err != nil {
72+
return fmt.Errorf("failed to copy EFI VHD at %s: %w", writableEFIVHDPath, err)
73+
}
74+
wopts.BootFiles.BlockCIMFiles.EFIVHDPath = writableEFIVHDPath
75+
}
76+
6177
return nil
6278
}
6379

internal/oci/uvm.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ func handleWCOWSecurityPolicy(ctx context.Context, a map[string]string, wopts *u
245245
wopts.SecurityPolicyEnforcer = ParseAnnotationsString(a, annotations.WCOWSecurityPolicyEnforcer, wopts.SecurityPolicyEnforcer)
246246
wopts.DisableSecureBoot = ParseAnnotationsBool(ctx, a, annotations.WCOWDisableSecureBoot, false)
247247
wopts.GuestStateFilePath = ParseAnnotationsString(a, annotations.WCOWGuestStateFile, uvm.GetDefaultConfidentialVMGSPath())
248+
wopts.WritableEFI = ParseAnnotationsBool(ctx, a, annotations.WCOWWritableEFI, false)
248249
if ParseAnnotationsBool(ctx, a, annotations.WCOWNoSecurityHardware, false) {
249250
wopts.NoSecurityHardware = true
250251
wopts.IsolationType = "VirtualizationBasedSecurity"

internal/uvm/create_wcow.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type ConfidentialWCOWOptions struct {
4242
IsolationType string
4343
DisableSecureBoot bool
4444
FirmwareParameters string
45+
WritableEFI bool
4546
}
4647

4748
// OptionsWCOW are the set of options passed to CreateWCOW() to create a utility vm.
@@ -385,26 +386,37 @@ func prepareSecurityConfigDoc(ctx context.Context, uvm *UtilityVM, opts *Options
385386
Minor: 0,
386387
}
387388

389+
// TODO(ambarve): only scratch VHD is unique per VM, EFI & Boot CIM VHDs are
390+
// shared across UVMs, so we don't need to assign VM group access to them every
391+
// time. It should have been done once while deploying the package.
392+
if err := wclayer.GrantVmAccess(ctx, uvm.id, opts.BootFiles.BlockCIMFiles.EFIVHDPath); err != nil {
393+
return nil, errors.Wrap(err, "failed to grant vm access to EFI VHD")
394+
}
395+
388396
if err := wclayer.GrantVmAccess(ctx, uvm.id, opts.BootFiles.BlockCIMFiles.BootCIMVHDPath); err != nil {
389-
return nil, errors.Wrap(err, "failed to grant vm access to boot CIM VHD")
397+
return nil, errors.Wrap(err, "failed to grant vm access to Boot CIM VHD")
390398
}
391399

392-
if err := wclayer.GrantVmAccess(ctx, uvm.id, opts.BootFiles.BlockCIMFiles.EFIVHDPath); err != nil {
393-
return nil, errors.Wrap(err, "failed to grant vm access to EFI VHD")
400+
if err := wclayer.GrantVmAccess(ctx, uvm.id, opts.GuestStateFilePath); err != nil {
401+
return nil, errors.Wrap(err, "failed to grant vm access to guest state file")
394402
}
395403

396404
if err := wclayer.GrantVmAccess(ctx, uvm.id, opts.BootFiles.BlockCIMFiles.ScratchVHDPath); err != nil {
397405
return nil, errors.Wrap(err, "failed to grant vm access to scratch VHD")
398406
}
399407

408+
// boot depends on scratch being attached at LUN 0, it MUST ALWAYS remain at LUN 0
400409
doc.VirtualMachine.Devices.Scsi[guestrequest.ScsiControllerGuids[0]].Attachments["0"] = hcsschema.Attachment{
401410
Path: opts.BootFiles.BlockCIMFiles.ScratchVHDPath,
402411
Type_: "VirtualDisk",
403412
}
413+
404414
doc.VirtualMachine.Devices.Scsi[guestrequest.ScsiControllerGuids[0]].Attachments["1"] = hcsschema.Attachment{
405-
Path: opts.BootFiles.BlockCIMFiles.EFIVHDPath,
406-
Type_: "VirtualDisk",
415+
Path: opts.BootFiles.BlockCIMFiles.EFIVHDPath,
416+
Type_: "VirtualDisk",
417+
ReadOnly: !opts.WritableEFI,
407418
}
419+
408420
doc.VirtualMachine.Devices.Scsi[guestrequest.ScsiControllerGuids[0]].Attachments["2"] = hcsschema.Attachment{
409421
Path: opts.BootFiles.BlockCIMFiles.BootCIMVHDPath,
410422
Type_: "VirtualDisk",

pkg/annotations/annotations.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ const (
205205
// Allows disabling secure boot for testing and debugging scenarios, secure boot doesn't apply to confidential LCOW so
206206
// this is a WCOW only config
207207
WCOWDisableSecureBoot = "io.microsoft.virtualmachine.wcow.no_secure_boot"
208+
209+
// Attaches the EFI/boot VHD in the writable mode (instead of the default read-only mode). This is usually required
210+
// when debugging boot to capture bootstat traces.
211+
WCOWWritableEFI = "io.microsoft.virtualmachine.wcow.writable_efi"
208212
)
209213

210214
// WCOW host process container annotations.

0 commit comments

Comments
 (0)