diff --git a/internal/guest/storage/devicemapper/devicemapper.go b/internal/guest/storage/devicemapper/devicemapper.go index aecdb43c70..01d712d37a 100644 --- a/internal/guest/storage/devicemapper/devicemapper.go +++ b/internal/guest/storage/devicemapper/devicemapper.go @@ -43,7 +43,7 @@ const ( _DM_SUSPEND_FLAG = 1 << 1 _DM_PERSISTENT_DEV_FLAG = 1 << 3 - BlockSize = 512 + blockSize = 512 ) const ( @@ -186,11 +186,11 @@ func LinearTarget(sectorStart, lengthBlocks int64, path string, deviceStart int6 } } -// PMemLinearTarget constructs a LinearTarget for PMem device with 0 sector start and length/device start +// zeroSectorLinearTarget creates a Target for devices with 0 sector start and length/device start // expected to be in bytes rather than blocks -func PMemLinearTarget(lengthBytes int64, path string, deviceStartBytes int64) Target { - lengthInBlocks := lengthBytes / BlockSize - startInBlocks := deviceStartBytes / BlockSize +func zeroSectorLinearTarget(lengthBytes int64, path string, deviceStartBytes int64) Target { + lengthInBlocks := lengthBytes / blockSize + startInBlocks := deviceStartBytes / blockSize return LinearTarget(0, lengthInBlocks, path, startInBlocks) } diff --git a/internal/guest/storage/devicemapper/targets.go b/internal/guest/storage/devicemapper/targets.go new file mode 100644 index 0000000000..798f5795b2 --- /dev/null +++ b/internal/guest/storage/devicemapper/targets.go @@ -0,0 +1,80 @@ +// +build linux + +package devicemapper + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + "go.opencensus.io/trace" + + "github.com/Microsoft/hcsshim/internal/guest/prot" + "github.com/Microsoft/hcsshim/internal/oc" +) + +// CreateZeroSectorLinearTarget creates dm-linear target for a device at `devPath` and `mappingInfo`, returns +// virtual block device path. +func CreateZeroSectorLinearTarget(ctx context.Context, devPath, devName string, mappingInfo *prot.DeviceMappingInfo) (_ string, err error) { + _, span := trace.StartSpan(ctx, "devicemapper::CreateZeroSectorLinearTarget") + defer span.End() + defer func() { oc.SetSpanStatus(span, err) }() + + linearTarget := zeroSectorLinearTarget(mappingInfo.DeviceSizeInBytes, devPath, mappingInfo.DeviceOffsetInBytes) + + span.AddAttributes( + trace.StringAttribute("devicePath", devPath), + trace.Int64Attribute("deviceStart", mappingInfo.DeviceOffsetInBytes), + trace.Int64Attribute("sectorSize", mappingInfo.DeviceSizeInBytes), + trace.StringAttribute("linearTable", fmt.Sprintf("%s: '%d %d %s'", devName, linearTarget.SectorStart, linearTarget.LengthInBlocks, linearTarget.Params))) + + devMapperPath, err := CreateDevice(devName, CreateReadOnly, []Target{linearTarget}) + if err != nil { + return "", errors.Wrapf(err, "failed to create dm-linear target, device=%s, offset=%d", devPath, mappingInfo.DeviceOffsetInBytes) + } + + return devMapperPath, nil +} + +// CreateVerityTarget creates a dm-verity target for a given device and returns created virtual block device path. +// +// Example verity target table: +// 0 417792 verity 1 /dev/sdb /dev/sdc 4096 4096 52224 1 sha256 2aa4f7b7b6...f4952060e8 762307f4bc8...d2a6b7595d8.. +// | | | | | | | | | | | | | +// start| | | data_dev | data_block | #blocks | hash_alg root_digest salt +// size | version hash_dev | hash_offset +// target hash_block +func CreateVerityTarget(ctx context.Context, devPath, devName string, verityInfo *prot.DeviceVerityInfo) (_ string, err error) { + _, span := trace.StartSpan(ctx, "devicemapper::CreateVerityTarget") + defer span.End() + defer func() { oc.SetSpanStatus(span, err) }() + + dmBlocks := verityInfo.Ext4SizeInBytes / blockSize + dataBlocks := verityInfo.Ext4SizeInBytes / int64(verityInfo.BlockSize) + hashOffsetBlocks := dataBlocks + if verityInfo.SuperBlock { + hashOffsetBlocks++ + } + hashes := fmt.Sprintf("%s %s %s", verityInfo.Algorithm, verityInfo.RootDigest, verityInfo.Salt) + blkInfo := fmt.Sprintf("%d %d %d %d", verityInfo.BlockSize, verityInfo.BlockSize, dataBlocks, hashOffsetBlocks) + devices := fmt.Sprintf("%s %s", devPath, devPath) + + verityTarget := Target{ + SectorStart: 0, + LengthInBlocks: dmBlocks, + Type: "verity", + Params: fmt.Sprintf("%d %s %s %s", verityInfo.Version, devices, blkInfo, hashes), + } + + span.AddAttributes( + trace.StringAttribute("devicePath", devPath), + trace.Int64Attribute("sectorSize", dmBlocks), + trace.StringAttribute("verityTable", verityTarget.Params)) + + mapperPath, err := CreateDevice(devName, CreateReadOnly, []Target{verityTarget}) + if err != nil { + return "", errors.Wrapf(err, "failed to create dm-verity target. device=%s", devPath) + } + + return mapperPath, nil +} diff --git a/internal/guest/storage/pmem/pmem.go b/internal/guest/storage/pmem/pmem.go index e4374d61ed..9923a71787 100644 --- a/internal/guest/storage/pmem/pmem.go +++ b/internal/guest/storage/pmem/pmem.go @@ -85,14 +85,12 @@ func Mount(ctx context.Context, device uint32, target string, mappingInfo *prot. return errors.Wrapf(err, "won't mount pmem device %d onto %s", device, target) } - // dm linear target has to be created first. when verity info is also present, the linear target becomes the data + // dm-linear target has to be created first. When verity info is also present, the linear target becomes the data // device instead of the original VPMem. if mappingInfo != nil { dmLinearName := fmt.Sprintf(linearDeviceFmt, device, mappingInfo.DeviceOffsetInBytes, mappingInfo.DeviceSizeInBytes) - if dmLinearPath, err := createDMLinearTarget(mCtx, devicePath, dmLinearName, target, mappingInfo); err != nil { + if devicePath, err = dm.CreateZeroSectorLinearTarget(mCtx, devicePath, dmLinearName, mappingInfo); err != nil { return err - } else { - devicePath = dmLinearPath } defer func() { if err != nil { @@ -105,10 +103,8 @@ func Mount(ctx context.Context, device uint32, target string, mappingInfo *prot. if verityInfo != nil { dmVerityName := fmt.Sprintf(verityDeviceFmt, device, verityInfo.RootDigest) - if dmVerityPath, err := createDMVerityTarget(mCtx, devicePath, dmVerityName, target, verityInfo); err != nil { + if devicePath, err = dm.CreateVerityTarget(mCtx, devicePath, dmVerityName, verityInfo); err != nil { return err - } else { - devicePath = dmVerityPath } defer func() { if err != nil { @@ -122,73 +118,6 @@ func Mount(ctx context.Context, device uint32, target string, mappingInfo *prot. return mountInternal(mCtx, devicePath, target) } -// createDMLinearTarget creates dm-linear target from a given `device` slot location and `mappingInfo` -func createDMLinearTarget(ctx context.Context, devPath, devName string, target string, mappingInfo *prot.DeviceMappingInfo) (_ string, err error) { - _, span := trace.StartSpan(ctx, "pmem::createDMLinearTarget") - defer span.End() - defer func() { oc.SetSpanStatus(span, err) }() - - linearTarget := dm.PMemLinearTarget(mappingInfo.DeviceSizeInBytes, devPath, mappingInfo.DeviceOffsetInBytes) - - span.AddAttributes( - trace.StringAttribute("devicePath", devPath), - trace.Int64Attribute("deviceStart", mappingInfo.DeviceOffsetInBytes), - trace.Int64Attribute("sectorSize", mappingInfo.DeviceSizeInBytes), - trace.StringAttribute("target", target), - trace.StringAttribute("linearTable", fmt.Sprintf("%s: '%d %d %s'", devName, linearTarget.SectorStart, linearTarget.LengthInBlocks, linearTarget.Params))) - - devMapperPath, err := dm.CreateDevice(devName, dm.CreateReadOnly, []dm.Target{linearTarget}) - if err != nil { - return "", errors.Wrapf(err, "failed to create dm-linear target: pmem device: %s, offset: %d", devPath, mappingInfo.DeviceOffsetInBytes) - } - - return devMapperPath, nil -} - -// createDMVerityTarget creates a dm-verity target for a given device and mounts that target instead of the device itself -// -// verity target table -// 0 417792 verity 1 /dev/sdb /dev/sdc 4096 4096 52224 1 sha256 2aa4f7b7b6...f4952060e8 762307f4bc8...d2a6b7595d8.. -// | | | | | | | | | | | | | -// start| | | data_dev | data_block | #blocks | hash_alg root_digest salt -// size | version hash_dev | hash_offset -// target hash_block -func createDMVerityTarget(ctx context.Context, devPath, devName, target string, verityInfo *prot.DeviceVerityInfo) (_ string, err error) { - _, span := trace.StartSpan(ctx, "pmem::createDMVerityTarget") - defer span.End() - defer func() { oc.SetSpanStatus(span, err) }() - - dmBlocks := verityInfo.Ext4SizeInBytes / dm.BlockSize - dataBlocks := verityInfo.Ext4SizeInBytes / int64(verityInfo.BlockSize) - hashOffsetBlocks := dataBlocks - if verityInfo.SuperBlock { - hashOffsetBlocks++ - } - hashes := fmt.Sprintf("%s %s %s", verityInfo.Algorithm, verityInfo.RootDigest, verityInfo.Salt) - blkInfo := fmt.Sprintf("%d %d %d %d", verityInfo.BlockSize, verityInfo.BlockSize, dataBlocks, hashOffsetBlocks) - devices := fmt.Sprintf("%s %s", devPath, devPath) - - verityTarget := dm.Target{ - SectorStart: 0, - LengthInBlocks: dmBlocks, - Type: "verity", - Params: fmt.Sprintf("%d %s %s %s", verityInfo.Version, devices, blkInfo, hashes), - } - - span.AddAttributes( - trace.StringAttribute("devicePath", devPath), - trace.StringAttribute("target", target), - trace.Int64Attribute("sectorSize", dmBlocks), - trace.StringAttribute("verityTable", verityTarget.Params)) - - mapperPath, err := dm.CreateDevice(devName, dm.CreateReadOnly, []dm.Target{verityTarget}) - if err != nil { - return "", errors.Wrapf(err, "failed to create dm-verity target: pmem device: %s", devPath) - } - - return mapperPath, nil -} - // Unmount unmounts `target` and removes corresponding linear and verity targets when needed func Unmount(ctx context.Context, devNumber uint32, target string, mappingInfo *prot.DeviceMappingInfo, verityInfo *prot.DeviceVerityInfo, securityPolicy securitypolicy.SecurityPolicyEnforcer) (err error) { _, span := trace.StartSpan(ctx, "pmem::Unmount")