diff --git a/guest/linux/ioctl.go b/guest/linux/ioctl.go new file mode 100644 index 0000000000..c87a3da9f5 --- /dev/null +++ b/guest/linux/ioctl.go @@ -0,0 +1,49 @@ +//go:build linux +// +build linux + +// Package linux contains definitions required for making a linux ioctl. +package linux + +import ( + "os" + "unsafe" + + "golang.org/x/sys/unix" +) + +// 32 bits to describe an ioctl: +// 0-7: NR (command for a given ioctl type) +// 8-15: TYPE (ioctl type) +// 16-29: SIZE (payload size) +// 30-31: DIR (direction of ioctl, can be: none/write/read/write-read) +const ( + IocWrite = 1 + IocRead = 2 + IocNRBits = 8 + IocTypeBits = 8 + IocSizeBits = 14 + IocDirBits = 2 + + IocNRMask = (1 << IocNRBits) - 1 + IocTypeMask = (1 << IocTypeBits) - 1 + IocSizeMask = (1 << IocSizeBits) - 1 + IocDirMask = (1 << IocDirBits) - 1 + IocTypeShift = IocNRBits + IocSizeShift = IocTypeShift + IocTypeBits + IocDirShift = IocSizeShift + IocSizeBits + IocWRBase = (IocRead | IocWrite) << IocDirShift +) + +// Ioctl makes a syscall described by `command` with data `dataPtr` to device +// driver file `f`. +func Ioctl(f *os.File, command int, dataPtr unsafe.Pointer) error { + if _, _, err := unix.Syscall( + unix.SYS_IOCTL, + f.Fd(), + uintptr(command), + uintptr(dataPtr), + ); err != 0 { + return err + } + return nil +} diff --git a/guest/runtime/hcsv2/hostdata.go b/guest/runtime/hcsv2/hostdata.go new file mode 100644 index 0000000000..562ed006e1 --- /dev/null +++ b/guest/runtime/hcsv2/hostdata.go @@ -0,0 +1,34 @@ +//go:build linux +// +build linux + +package hcsv2 + +import ( + "bytes" + "fmt" + "os" + + "github.com/Microsoft/hcsshim/pkg/amdsevsnp" +) + +// validateHostData fetches SNP report (if applicable) and validates `hostData` against +// HostData set at UVM launch. +func validateHostData(hostData []byte) error { + report, err := amdsevsnp.FetchParsedSNPReport(nil) + if err != nil { + // For non-SNP hardware /dev/sev will not exist + if os.IsNotExist(err) { + return nil + } + return err + } + + if bytes.Compare(hostData, report.HostData) != 0 { + return fmt.Errorf( + "security policy digest %q doesn't match HostData provided at launch %q", + hostData, + report.HostData, + ) + } + return nil +} diff --git a/guest/runtime/hcsv2/uvm.go b/guest/runtime/hcsv2/uvm.go index d5e004fc6a..b1abecc811 100644 --- a/guest/runtime/hcsv2/uvm.go +++ b/guest/runtime/hcsv2/uvm.go @@ -95,6 +95,15 @@ func (h *Host) SetSecurityPolicy(base64Policy string) error { return err } + hostData, err := securitypolicy.NewSecurityPolicyDigest(base64Policy) + if err != nil { + return err + } + + if err := validateHostData(hostData[:]); err != nil { + return err + } + h.securityPolicyEnforcer = p h.securityPolicyEnforcerSet = true diff --git a/guest/storage/devicemapper/devicemapper.go b/guest/storage/devicemapper/devicemapper.go index 3b313284c1..3f9b6797e7 100644 --- a/guest/storage/devicemapper/devicemapper.go +++ b/guest/storage/devicemapper/devicemapper.go @@ -12,6 +12,8 @@ import ( "unsafe" "golang.org/x/sys/unix" + + "github.com/Microsoft/hcsshim/internal/guest/linux" ) // CreateFlags modify the operation of CreateDevice @@ -28,24 +30,9 @@ var ( ) const ( - _IOC_WRITE = 1 - _IOC_READ = 2 - _IOC_NRBITS = 8 - _IOC_TYPEBITS = 8 - _IOC_SIZEBITS = 14 - _IOC_DIRBITS = 2 - - _IOC_NRMASK = ((1 << _IOC_NRBITS) - 1) - _IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1) - _IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1) - _IOC_DIRMASK = ((1 << _IOC_DIRBITS) - 1) - _IOC_TYPESHIFT = (_IOC_NRBITS) - _IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS) - _IOC_DIRSHIFT = (_IOC_SIZESHIFT + _IOC_SIZEBITS) - _DM_IOCTL = 0xfd _DM_IOCTL_SIZE = 312 - _DM_IOCTL_BASE = (_IOC_READ|_IOC_WRITE)<<_IOC_DIRSHIFT | _DM_IOCTL<<_IOC_TYPESHIFT | _DM_IOCTL_SIZE<<_IOC_SIZESHIFT + _DM_IOCTL_BASE = linux.IocWRBase | _DM_IOCTL<