Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add guest package for fetching attestation report via syscall #1341

Merged
merged 2 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
BASE:=base.tar.gz
DEV_BUILD:=0

GO:=go
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
Expand All @@ -16,6 +17,12 @@ GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)

SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))

DELTA_TARGET=out/delta.tar.gz

ifeq "$(DEV_BUILD)" "1"
DELTA_TARGET=out/delta-dev.tar.gz
endif

# The link aliases for gcstools
GCS_TOOLS=\
generichook \
Expand Down Expand Up @@ -55,22 +62,32 @@ out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools bin/cmd/ho
tar -zcf $@ -C rootfs .
rm -rf rootfs

# This target includes utilities which may be useful for testing purposes.
out/delta-dev.tar.gz: out/delta.tar.gz bin/internal/tools/snp-report
rm -rf rootfs-dev
mkdir rootfs-dev
tar -xzf out/delta.tar.gz -C rootfs-dev
cp bin/internal/tools/snp-report rootfs-dev/bin/
tar -zcf $@ -C rootfs-dev .
rm -rf rootfs-dev

out/rootfs.tar.gz: out/initrd.img
rm -rf rootfs-conv
mkdir rootfs-conv
gunzip -c out/initrd.img | (cd rootfs-conv && cpio -imd)
tar -zcf $@ -C rootfs-conv .
rm -rf rootfs-conv

out/initrd.img: $(BASE) out/delta.tar.gz $(SRCROOT)/hack/catcpio.sh
$(SRCROOT)/hack/catcpio.sh "$(BASE)" out/delta.tar.gz > out/initrd.img.uncompressed
out/initrd.img: $(BASE) $(DELTA_TARGET) $(SRCROOT)/hack/catcpio.sh
$(SRCROOT)/hack/catcpio.sh "$(BASE)" $(DELTA_TARGET) > out/initrd.img.uncompressed
gzip -c out/initrd.img.uncompressed > $@
rm out/initrd.img.uncompressed

-include deps/cmd/gcs.gomake
-include deps/cmd/gcstools.gomake
-include deps/cmd/hooks/wait-paths.gomake
-include deps/cmd/tar2ext4.gomake
-include deps/internal/tools/snp-report.gomake

# Implicit rule for includes that define Go targets.
%.gomake: $(SRCROOT)/Makefile
Expand Down
49 changes: 49 additions & 0 deletions internal/guest/linux/ioctl.go
Original file line number Diff line number Diff line change
@@ -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 (
anmaxvl marked this conversation as resolved.
Show resolved Hide resolved
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
)
anmaxvl marked this conversation as resolved.
Show resolved Hide resolved

// 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
}
34 changes: 34 additions & 0 deletions internal/guest/runtime/hcsv2/hostdata.go
Original file line number Diff line number Diff line change
@@ -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
}
9 changes: 9 additions & 0 deletions internal/guest/runtime/hcsv2/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
38 changes: 12 additions & 26 deletions internal/guest/storage/devicemapper/devicemapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"unsafe"

"golang.org/x/sys/unix"

"github.com/Microsoft/hcsshim/internal/guest/linux"
)

// CreateFlags modify the operation of CreateDevice
Expand All @@ -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<<linux.IocTypeShift | _DM_IOCTL_SIZE<<linux.IocSizeShift

_DM_READONLY_FLAG = 1 << 0
_DM_SUSPEND_FLAG = 1 << 1
Expand Down Expand Up @@ -132,11 +119,10 @@ func (err *dmError) Error() string {
return "device-mapper " + op + ": " + err.Err.Error()
}

// ioctl issues the specified device-mapper ioctl
func ioctl(f *os.File, code int, data *dmIoctl) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(), uintptr(code|_DM_IOCTL_BASE), uintptr(unsafe.Pointer(data)))
if errno != 0 {
return &dmError{Op: code, Err: errno}
// devMapperIoctl issues the specified device-mapper ioctl
func devMapperIoctl(f *os.File, code int, data *dmIoctl) error {
if err := linux.Ioctl(f, code|_DM_IOCTL_BASE, unsafe.Pointer(data)); err != nil {
return &dmError{Op: code, Err: err}
}
return nil
}
Expand All @@ -155,7 +141,7 @@ func openMapper() (f *os.File, err error) {
}()
var d dmIoctl
initIoctl(&d, int(unsafe.Sizeof(d)), "")
err = ioctl(f, _DM_VERSION, &d)
err = devMapperIoctl(f, _DM_VERSION, &d)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -240,7 +226,7 @@ func CreateDevice(name string, flags CreateFlags, targets []Target) (_ string, e
var d dmIoctl
size := int(unsafe.Sizeof(d))
initIoctl(&d, size, name)
err = ioctl(f, _DM_DEV_CREATE, &d)
err = devMapperIoctl(f, _DM_DEV_CREATE, &d)
if err != nil {
return "", err
}
Expand All @@ -256,12 +242,12 @@ func CreateDevice(name string, flags CreateFlags, targets []Target) (_ string, e
if flags&CreateReadOnly != 0 {
di.Flags |= _DM_READONLY_FLAG
}
err = ioctl(f, _DM_TABLE_LOAD, di)
err = devMapperIoctl(f, _DM_TABLE_LOAD, di)
if err != nil {
return "", err
}
initIoctl(&d, size, name)
err = ioctl(f, _DM_DEV_SUSPEND, &d)
err = devMapperIoctl(f, _DM_DEV_SUSPEND, &d)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -306,7 +292,7 @@ func RemoveDevice(name string) (err error) {
func removeDevice(f *os.File, name string) error {
var d dmIoctl
initIoctl(&d, int(unsafe.Sizeof(d)), name)
err := ioctl(f, _DM_DEV_REMOVE, &d)
err := devMapperIoctl(f, _DM_DEV_REMOVE, &d)
if err != nil {
return err
}
Expand Down
57 changes: 57 additions & 0 deletions internal/tools/snp-report/fake/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//go:build linux
// +build linux

package fake

import (
"encoding/hex"
"fmt"

"github.com/Microsoft/hcsshim/pkg/amdsevsnp"
)

const fakeSNPReport = "01000000010000001f00030000000000010000000000000000000000000000000200000000000000000000000000000000000000010000000000000000000028010000000000000000000000000000007ab000a323b3c873f5b81bbe584e7c1a26bcf40dc27e00f8e0d144b1ed2d14f10000000000000000000000000000000000000000000000000000000000000000e29af700e85b39996fa38226d2804b78cad746ffef4477360a61b47874bdecd640f9d32f5ff64a55baad3c545484d9ed28603a3ea835a83bd688b0ec1dcb36b6b8c22412e5b63115b75db8628b989bc598c475ca5f7683e8d351e7e789a1baff19041750567161ad52bf0d152bd76d7c6f313d0a0fd72d0089692c18f521155800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040aea62690b08eb6d680392c9a9b3db56a9b3cc44083b9da31fb88bcfc493407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000028000000000000000000000000000000000000000000000000e6c86796cd44b0bc6b7c0d4fdab33e2807e14b5fc4538b3750921169d97bcf4447c7d3ab2a7c25f74c1641e2885c1011d025cc536f5c9a2504713136c7877f480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003131c0f3e7be5c6e400f22404596e1874381e99d03de45ef8b97eee0a0fa93a4911550330343f14dddbbd6c0db83744f000000000000000000000000000000000000000000000000db07c83c5e6162c2387f3b76cd547672657f6a5df99df98efee7c15349320d83e086c5003ec43050a9b18d1c39dedc340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

// FetchRawSNPReport hex decodes fakeSNPReport.
func FetchRawSNPReport() ([]byte, error) {
return hex.DecodeString(fakeSNPReport)
}

// FetchSNPReport returns amdsev.Report object that corresponds to the decoded
// version of fakeSNPReport. Overrides the resulting report's HostData field
// with provided `hostData`.
func FetchSNPReport(hostData string) (amdsevsnp.Report, error) {
if hostData == "" {
hostData = "28603a3ea835a83bd688b0ec1dcb36b6b8c22412e5b63115b75db8628b989bc5"
}
hdBytes, err := hex.DecodeString(hostData)
if err != nil {
return amdsevsnp.Report{}, fmt.Errorf("failed to decode host data: %w", err)
}
r := amdsevsnp.Report{
Version: 1,
GuestSVN: 1,
Policy: 0x03001f,
FamilyID: "00000000000000000000000000000001",
ImageID: "00000000000000000000000000000001",
VMPL: 0,
SignatureAlgo: 1,
PlatformVersion: 0x2800000000000000,
PlatformInfo: 1,
AuthorKeyEn: 0,
ReportData: "7ab000a323b3c873f5b81bbe584e7c1a26bcf40dc27e00f8e0d144b1ed2d14f10000000000000000000000000000000000000000000000000000000000000000",
Measurement: "e29af700e85b39996fa38226d2804b78cad746ffef4477360a61b47874bdecd640f9d32f5ff64a55baad3c545484d9ed",
HostData: hdBytes[:],
IDKeyDigest: "98c475ca5f7683e8d351e7e789a1baff19041750567161ad52bf0d152bd76d7c6f313d0a0fd72d0089692c18f5211558",
AuthorKeyDigest: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
ReportID: "40aea62690b08eb6d680392c9a9b3db56a9b3cc44083b9da31fb88bcfc493407",
ReportIDMA: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
ReportTCB: 0x2800000000000000,
ChipID: "e6c86796cd44b0bc6b7c0d4fdab33e2807e14b5fc4538b3750921169d97bcf4447c7d3ab2a7c25f74c1641e2885c1011d025cc536f5c9a2504713136c7877f48",
CommittedSVN: "0000000000000000",
CommittedVersion: "0000000000000000",
LaunchSVN: "0000000000000000",
Signature: "3131c0f3e7be5c6e400f22404596e1874381e99d03de45ef8b97eee0a0fa93a4911550330343f14dddbbd6c0db83744f000000000000000000000000000000000000000000000000db07c83c5e6162c2387f3b76cd547672657f6a5df99df98efee7c15349320d83e086c5003ec43050a9b18d1c39dedc340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
}
return r, nil
}
Loading