diff --git a/internal/uvm/vpmem.go b/internal/uvm/vpmem.go index 6c099bc840..d3cb8ee97f 100644 --- a/internal/uvm/vpmem.go +++ b/internal/uvm/vpmem.go @@ -41,18 +41,27 @@ func newDefaultVPMemInfo(hostPath, uvmPath string) *vPMemInfoDefault { } } +// fileSystemSize retrieves ext4 fs SuperBlock and returns the file system size and block size +func fileSystemSize(vhdPath string) (int64, int, error) { + sb, err := tar2ext4.ReadExt4SuperBlock(vhdPath) + if err != nil { + return 0, 0, errors.Wrap(err, "failed to read ext4 super block") + } + blockSize := 1024 * (1 << sb.LogBlockSize) + fsSize := int64(blockSize) * int64(sb.BlocksCountLow) + return fsSize, blockSize, nil +} + // readVeritySuperBlock reads ext4 super block for a given VHD to then further read the dm-verity super block // and root hash func readVeritySuperBlock(ctx context.Context, layerPath string) (*guestrequest.DeviceVerityInfo, error) { - ext4sb, err := tar2ext4.ReadExt4SuperBlock(layerPath) + // dm-verity information is expected to be appended, the size of ext4 data will be the offset + // of the dm-verity super block, followed by merkle hash tree + ext4SizeInBytes, ext4BlockSize, err := fileSystemSize(layerPath) if err != nil { - return nil, errors.Wrap(err, "failed to read ext4 super block") + return nil, err } - // Calculate the size of ext4 file system based on the information from ext4 super block, since - // the dm-verity information is expected to be appended, the size of ext4 data will be the offset - // of the dm-verity super block, followed by merkle hash tree - ext4BlockSize := 1024 * (1 << ext4sb.LogBlockSize) - ext4SizeInBytes := int64(ext4BlockSize) * int64(ext4sb.BlocksCountLow) + dmvsb, err := dmverity.ReadDMVerityInfo(layerPath, ext4SizeInBytes) if err != nil { return nil, errors.Wrap(err, "failed to read dm-verity super block") diff --git a/internal/uvm/vpmem_mapped.go b/internal/uvm/vpmem_mapped.go index 3faeff94db..15e68d6a13 100644 --- a/internal/uvm/vpmem_mapped.go +++ b/internal/uvm/vpmem_mapped.go @@ -3,11 +3,11 @@ package uvm import ( "context" "fmt" + "os" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/Microsoft/hcsshim/ext4/tar2ext4" "github.com/Microsoft/hcsshim/internal/guestrequest" "github.com/Microsoft/hcsshim/internal/hcs/resourcepaths" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" @@ -64,33 +64,36 @@ func pageAlign(t uint64) uint64 { return (t/PageSize + 1) * PageSize } -// fileSystemSize retrieves ext4 fs SuperBlock and calculates the size of the actual file system -func fileSystemSize(vhdPath string) (uint64, error) { - sb, err := tar2ext4.ReadExt4SuperBlock(vhdPath) - if err != nil { - return 0, err - } - blockSize := uint64(1024 * (1 << sb.LogBlockSize)) - fsSize := blockSize * uint64(sb.BlocksCountLow) - return pageAlign(fsSize), nil -} - // newMappedVPMemModifyRequest creates an hcsschema.ModifySettingsRequest to modify VPMem devices/mappings // for the multi-mapping setup func newMappedVPMemModifyRequest(ctx context.Context, rType string, deviceNumber uint32, md *mappedDeviceInfo, uvm *UtilityVM) (*hcsschema.ModifySettingRequest, error) { + guestSettings := guestrequest.LCOWMappedVPMemDevice{ + DeviceNumber: deviceNumber, + MountPath: md.uvmPath, + MappingInfo: &guestrequest.LCOWMappedLayer{ + DeviceOffsetInBytes: md.mappedRegion.Offset(), + DeviceSizeInBytes: md.sizeInBytes, + }, + } + + if verity, err := readVeritySuperBlock(ctx, md.hostPath); err != nil { + log.G(ctx).WithError(err).WithField("hostPath", md.hostPath).Debug("unable to read dm-verity information from VHD") + } else { + if verity != nil { + log.G(ctx).WithFields(logrus.Fields{ + "hostPath": md.hostPath, + "rootDigest": verity.RootDigest, + }).Debug("adding multi-mapped VPMem with dm-verity") + guestSettings.VerityInfo = verity + } + } + request := &hcsschema.ModifySettingRequest{ RequestType: rType, GuestRequest: guestrequest.GuestRequest{ ResourceType: guestrequest.ResourceTypeVPMemDevice, RequestType: rType, - Settings: guestrequest.LCOWMappedVPMemDevice{ - DeviceNumber: deviceNumber, - MountPath: md.uvmPath, - MappingInfo: &guestrequest.LCOWMappedLayer{ - DeviceOffsetInBytes: md.mappedRegion.Offset(), - DeviceSizeInBytes: md.sizeInBytes, - }, - }, + Settings: guestSettings, }, } @@ -234,10 +237,15 @@ func (uvm *UtilityVM) addVPMemMappedDevice(ctx context.Context, hostPath string) return dev.uvmPath, nil } - devSize, err := fileSystemSize(hostPath) + st, err := os.Stat(hostPath) if err != nil { return "", err } + // NOTE: On the guest side devSize is used to create a device mapper linear target, which is then used to create + // device mapper verity target. Since the dm-verity hash device is appended after ext4 data, we need the full size + // on disk (minus VHD footer), otherwise the resulting linear target will have hash device truncated and verity + // target creation will fail as a result. + devSize := pageAlign(uint64(st.Size())) deviceNumber, memReg, err := uvm.allocateNextVPMemMappedDeviceLocation(ctx, devSize) if err != nil { return "", err diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem.go b/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem.go index 6c099bc840..d3cb8ee97f 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem.go @@ -41,18 +41,27 @@ func newDefaultVPMemInfo(hostPath, uvmPath string) *vPMemInfoDefault { } } +// fileSystemSize retrieves ext4 fs SuperBlock and returns the file system size and block size +func fileSystemSize(vhdPath string) (int64, int, error) { + sb, err := tar2ext4.ReadExt4SuperBlock(vhdPath) + if err != nil { + return 0, 0, errors.Wrap(err, "failed to read ext4 super block") + } + blockSize := 1024 * (1 << sb.LogBlockSize) + fsSize := int64(blockSize) * int64(sb.BlocksCountLow) + return fsSize, blockSize, nil +} + // readVeritySuperBlock reads ext4 super block for a given VHD to then further read the dm-verity super block // and root hash func readVeritySuperBlock(ctx context.Context, layerPath string) (*guestrequest.DeviceVerityInfo, error) { - ext4sb, err := tar2ext4.ReadExt4SuperBlock(layerPath) + // dm-verity information is expected to be appended, the size of ext4 data will be the offset + // of the dm-verity super block, followed by merkle hash tree + ext4SizeInBytes, ext4BlockSize, err := fileSystemSize(layerPath) if err != nil { - return nil, errors.Wrap(err, "failed to read ext4 super block") + return nil, err } - // Calculate the size of ext4 file system based on the information from ext4 super block, since - // the dm-verity information is expected to be appended, the size of ext4 data will be the offset - // of the dm-verity super block, followed by merkle hash tree - ext4BlockSize := 1024 * (1 << ext4sb.LogBlockSize) - ext4SizeInBytes := int64(ext4BlockSize) * int64(ext4sb.BlocksCountLow) + dmvsb, err := dmverity.ReadDMVerityInfo(layerPath, ext4SizeInBytes) if err != nil { return nil, errors.Wrap(err, "failed to read dm-verity super block") diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem_mapped.go b/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem_mapped.go index 3faeff94db..15e68d6a13 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem_mapped.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/uvm/vpmem_mapped.go @@ -3,11 +3,11 @@ package uvm import ( "context" "fmt" + "os" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/Microsoft/hcsshim/ext4/tar2ext4" "github.com/Microsoft/hcsshim/internal/guestrequest" "github.com/Microsoft/hcsshim/internal/hcs/resourcepaths" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" @@ -64,33 +64,36 @@ func pageAlign(t uint64) uint64 { return (t/PageSize + 1) * PageSize } -// fileSystemSize retrieves ext4 fs SuperBlock and calculates the size of the actual file system -func fileSystemSize(vhdPath string) (uint64, error) { - sb, err := tar2ext4.ReadExt4SuperBlock(vhdPath) - if err != nil { - return 0, err - } - blockSize := uint64(1024 * (1 << sb.LogBlockSize)) - fsSize := blockSize * uint64(sb.BlocksCountLow) - return pageAlign(fsSize), nil -} - // newMappedVPMemModifyRequest creates an hcsschema.ModifySettingsRequest to modify VPMem devices/mappings // for the multi-mapping setup func newMappedVPMemModifyRequest(ctx context.Context, rType string, deviceNumber uint32, md *mappedDeviceInfo, uvm *UtilityVM) (*hcsschema.ModifySettingRequest, error) { + guestSettings := guestrequest.LCOWMappedVPMemDevice{ + DeviceNumber: deviceNumber, + MountPath: md.uvmPath, + MappingInfo: &guestrequest.LCOWMappedLayer{ + DeviceOffsetInBytes: md.mappedRegion.Offset(), + DeviceSizeInBytes: md.sizeInBytes, + }, + } + + if verity, err := readVeritySuperBlock(ctx, md.hostPath); err != nil { + log.G(ctx).WithError(err).WithField("hostPath", md.hostPath).Debug("unable to read dm-verity information from VHD") + } else { + if verity != nil { + log.G(ctx).WithFields(logrus.Fields{ + "hostPath": md.hostPath, + "rootDigest": verity.RootDigest, + }).Debug("adding multi-mapped VPMem with dm-verity") + guestSettings.VerityInfo = verity + } + } + request := &hcsschema.ModifySettingRequest{ RequestType: rType, GuestRequest: guestrequest.GuestRequest{ ResourceType: guestrequest.ResourceTypeVPMemDevice, RequestType: rType, - Settings: guestrequest.LCOWMappedVPMemDevice{ - DeviceNumber: deviceNumber, - MountPath: md.uvmPath, - MappingInfo: &guestrequest.LCOWMappedLayer{ - DeviceOffsetInBytes: md.mappedRegion.Offset(), - DeviceSizeInBytes: md.sizeInBytes, - }, - }, + Settings: guestSettings, }, } @@ -234,10 +237,15 @@ func (uvm *UtilityVM) addVPMemMappedDevice(ctx context.Context, hostPath string) return dev.uvmPath, nil } - devSize, err := fileSystemSize(hostPath) + st, err := os.Stat(hostPath) if err != nil { return "", err } + // NOTE: On the guest side devSize is used to create a device mapper linear target, which is then used to create + // device mapper verity target. Since the dm-verity hash device is appended after ext4 data, we need the full size + // on disk (minus VHD footer), otherwise the resulting linear target will have hash device truncated and verity + // target creation will fail as a result. + devSize := pageAlign(uint64(st.Size())) deviceNumber, memReg, err := uvm.allocateNextVPMemMappedDeviceLocation(ctx, devSize) if err != nil { return "", err