Skip to content

Commit

Permalink
PoC - Modify Verity Enabled Base Image.
Browse files Browse the repository at this point in the history
  • Loading branch information
liulanze committed Dec 19, 2024
1 parent f831498 commit 86e12b3
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 34 deletions.
4 changes: 3 additions & 1 deletion toolkit/tools/imagecustomizerapi/mountidentifiertype.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ const (
// MountIdentifierTypePartLabel mounts this partition via the GPT PARTLABEL
MountIdentifierTypePartLabel MountIdentifierType = "part-label"

MountIdentifierTypeDevMapper MountIdentifierType = "/dev/mapper/root"

// MountIdentifierTypeDefault uses the default type, which is PARTUUID.
MountIdentifierTypeDefault MountIdentifierType = ""
)

func (m MountIdentifierType) IsValid() error {
switch m {
case MountIdentifierTypeUuid, MountIdentifierTypePartUuid, MountIdentifierTypePartLabel, MountIdentifierTypeDefault:
case MountIdentifierTypeUuid, MountIdentifierTypePartUuid, MountIdentifierTypePartLabel, MountIdentifierTypeDevMapper, MountIdentifierTypeDefault:
// All good.
return nil

Expand Down
4 changes: 2 additions & 2 deletions toolkit/tools/pkg/imagecustomizerlib/customizeos.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

func doOsCustomizations(buildDir string, baseConfigPath string, config *imagecustomizerapi.Config,
imageConnection *ImageConnection, rpmsSources []string, useBaseImageRpmRepos bool, partitionsCustomized bool,
imageUuid string) error {
imageUuid string, isVerityEnabled bool) error {
var err error

imageChroot := imageConnection.Chroot()
Expand Down Expand Up @@ -80,7 +80,7 @@ func doOsCustomizations(buildDir string, baseConfigPath string, config *imagecus
return err
}

verityUpdated, err := enableVerityPartition(config.Storage.Verity, imageChroot)
verityUpdated, err := enableVerityPartition(config.Storage.Verity, imageChroot, isVerityEnabled)
if err != nil {
return err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func fixPartitionUuidsInFstabFile(partitions []diskutils.PartitionInfo, newUuids
// Find the partition.
// Note: The 'partitions' list was collected before all the changes were made. So, the fstab entires will still
// match the values in the `partitions` list.
mountIdType, _, partitionIndex, err := findSourcePartitionHelper(fstabEntry.Source, partitions)
mountIdType, _, partitionIndex, err := findSourcePartitionHelper(fstabEntry.Source, partitions, buildDir)
if err != nil {
return err
}
Expand Down
18 changes: 10 additions & 8 deletions toolkit/tools/pkg/imagecustomizerlib/customizeverity.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/microsoft/azurelinux/toolkit/tools/internal/safechroot"
)

func enableVerityPartition(verity []imagecustomizerapi.Verity, imageChroot *safechroot.Chroot,
func enableVerityPartition(verity []imagecustomizerapi.Verity, imageChroot *safechroot.Chroot, isVerityEnabled bool,
) (bool, error) {
var err error

Expand All @@ -29,12 +29,14 @@ func enableVerityPartition(verity []imagecustomizerapi.Verity, imageChroot *safe
return false, fmt.Errorf("failed to validate package dependencies for verity:\n%w", err)
}

// Integrate systemd veritysetup dracut module into initramfs img.
systemdVerityDracutModule := "systemd-veritysetup"
dmVerityDracutDriver := "dm-verity"
err = addDracutModuleAndDriver(systemdVerityDracutModule, dmVerityDracutDriver, imageChroot)
if err != nil {
return false, fmt.Errorf("failed to add dracut modules for verity:\n%w", err)
if !isVerityEnabled {
// Integrate systemd veritysetup dracut module into initramfs img.
systemdVerityDracutModule := "systemd-veritysetup"
dmVerityDracutDriver := "dm-verity"
err = addDracutModuleAndDriver(systemdVerityDracutModule, dmVerityDracutDriver, imageChroot)
if err != nil {
return false, fmt.Errorf("failed to add dracut modules for verity:\n%w", err)
}
}

err = updateFstabForVerity(verity, imageChroot)
Expand Down Expand Up @@ -222,7 +224,7 @@ func systemdFormatPartitionId(configDeviceId string, mountIdType imagecustomizer
) (string, error) {
partUuid := partIdToPartUuid[configDeviceId]

partition, _, err := findPartition(imagecustomizerapi.MountIdentifierTypePartUuid, partUuid, partitions)
partition, _, err := findPartition(imagecustomizerapi.MountIdentifierTypePartUuid, partUuid, partitions, "")
if err != nil {
return "", err
}
Expand Down
21 changes: 11 additions & 10 deletions toolkit/tools/pkg/imagecustomizerlib/imagecustomizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,8 @@ func customizeOSContents(ic *ImageCustomizerParameters) error {
// The presence of this type indicates that dm-verity has been enabled on the base image. If dm-verity is not enabled,
// the verity hash device should not be assigned this type. We do not support customization on verity enabled base
// images at this time because such modifications would compromise the integrity and security mechanisms enforced by dm-verity.
err := checkDmVerityEnabled(ic.rawImageFile)

isVerityEnabled, err := checkDmVerityEnabled(ic.rawImageFile)
if err != nil {
return err
}
Expand All @@ -370,7 +371,7 @@ func customizeOSContents(ic *ImageCustomizerParameters) error {

// Customize the raw image file.
err = customizeImageHelper(ic.buildDirAbs, ic.configPath, ic.config, ic.rawImageFile, ic.rpmsSources,
ic.useBaseImageRpmRepos, partitionsCustomized, imageUuidStr)
ic.useBaseImageRpmRepos, partitionsCustomized, imageUuidStr, isVerityEnabled)
if err != nil {
return err
}
Expand Down Expand Up @@ -681,7 +682,7 @@ func validatePackageLists(baseConfigPath string, config *imagecustomizerapi.OS,

func customizeImageHelper(buildDir string, baseConfigPath string, config *imagecustomizerapi.Config,
rawImageFile string, rpmsSources []string, useBaseImageRpmRepos bool, partitionsCustomized bool,
imageUuidStr string,
imageUuidStr string, isVerityEnabled bool,
) error {
logger.Log.Debugf("Customizing OS")

Expand All @@ -700,7 +701,7 @@ func customizeImageHelper(buildDir string, baseConfigPath string, config *imagec

// Do the actual customizations.
err = doOsCustomizations(buildDir, baseConfigPath, config, imageConnection, rpmsSources,
useBaseImageRpmRepos, partitionsCustomized, imageUuidStr)
useBaseImageRpmRepos, partitionsCustomized, imageUuidStr, isVerityEnabled)

// Out of disk space errors can be difficult to diagnose.
// So, warn about any partitions with low free space.
Expand Down Expand Up @@ -866,34 +867,34 @@ func customizeVerityImageHelper(buildDir string, baseConfigPath string, config *
return nil
}

func checkDmVerityEnabled(rawImageFile string) error {
func checkDmVerityEnabled(rawImageFile string) (bool, error) {
logger.Log.Debugf("Check if dm-verity is enabled in base image")

loopback, err := safeloopback.NewLoopback(rawImageFile)
if err != nil {
return fmt.Errorf("failed to check if dm-verity is enabled in base image:\n%w", err)
return false, fmt.Errorf("failed to check if dm-verity is enabled in base image:\n%w", err)
}
defer loopback.Close()

diskPartitions, err := diskutils.GetDiskPartitions(loopback.DevicePath())
if err != nil {
return err
return false, err
}

for i := range diskPartitions {
diskPartition := diskPartitions[i]

if diskPartition.FileSystemType == "DM_verity_hash" {
return fmt.Errorf("cannot customize base image that has dm-verity enabled")
return true, nil // dm-verity is enabled
}
}

err = loopback.CleanClose()
if err != nil {
return fmt.Errorf("failed to check if dm-verity is enabled in base image:\n%w", err)
return false, fmt.Errorf("failed to check if dm-verity is enabled in base image:\n%w", err)
}

return nil
return false, nil // dm-verity is not enabled
}

func warnOnLowFreeSpace(buildDir string, imageConnection *ImageConnection) {
Expand Down
2 changes: 1 addition & 1 deletion toolkit/tools/pkg/imagecustomizerlib/imageutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func createImageBoilerplate(imageConnection *ImageConnection, filename string, b
}

// Read back the fstab file.
mountPoints, err := findMountsFromFstabFile(tmpFstabFile, diskPartitions)
mountPoints, err := findMountsFromFstabFile(tmpFstabFile, diskPartitions, buildDir)
if err != nil {
return nil, "", err
}
Expand Down
72 changes: 61 additions & 11 deletions toolkit/tools/pkg/imagecustomizerlib/partitionutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func findSystemBootPartition(diskPartitions []diskutils.PartitionInfo) (*diskuti
}

func findBootPartitionFromEsp(efiSystemPartition *diskutils.PartitionInfo, diskPartitions []diskutils.PartitionInfo, buildDir string) (*diskutils.PartitionInfo, error) {
tmpDir := filepath.Join(buildDir, tmpParitionDirName)
tmpDir := filepath.Join(buildDir, tmpParitionDirName+"-esp")

// Mount the EFI System Partition.
efiSystemPartitionMount, err := safemount.NewMount(efiSystemPartition.Path, tmpDir, efiSystemPartition.FileSystemType, 0, "", true)
Expand Down Expand Up @@ -202,7 +202,7 @@ func findMountsFromRootfs(rootfsPartition *diskutils.PartitionInfo, diskPartitio
// Read the fstab file.
fstabPath := filepath.Join(tmpDir, "/etc/fstab")

mountPoints, err := findMountsFromFstabFile(fstabPath, diskPartitions)
mountPoints, err := findMountsFromFstabFile(fstabPath, diskPartitions, buildDir)
if err != nil {
return nil, err
}
Expand All @@ -216,31 +216,31 @@ func findMountsFromRootfs(rootfsPartition *diskutils.PartitionInfo, diskPartitio
return mountPoints, nil
}

func findMountsFromFstabFile(fstabPath string, diskPartitions []diskutils.PartitionInfo,
func findMountsFromFstabFile(fstabPath string, diskPartitions []diskutils.PartitionInfo, buildDir string,
) ([]*safechroot.MountPoint, error) {
// Read the fstab file.
fstabEntries, err := diskutils.ReadFstabFile(fstabPath)
if err != nil {
return nil, err
}

mountPoints, err := fstabEntriesToMountPoints(fstabEntries, diskPartitions)
mountPoints, err := fstabEntriesToMountPoints(fstabEntries, diskPartitions, buildDir)
if err != nil {
return nil, fmt.Errorf("failed to find mount info for fstab file entries:\n%w", err)
}

return mountPoints, nil
}

func fstabEntriesToMountPoints(fstabEntries []diskutils.FstabEntry, diskPartitions []diskutils.PartitionInfo,
func fstabEntriesToMountPoints(fstabEntries []diskutils.FstabEntry, diskPartitions []diskutils.PartitionInfo, buildDir string,
) ([]*safechroot.MountPoint, error) {
filteredFstabEntries := filterOutSpecialPartitions(fstabEntries)

// Convert fstab entries into mount points.
var mountPoints []*safechroot.MountPoint
var foundRoot bool
for _, fstabEntry := range filteredFstabEntries {
source, err := findSourcePartition(fstabEntry.Source, diskPartitions)
source, err := findSourcePartition(fstabEntry.Source, diskPartitions, buildDir)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -293,8 +293,8 @@ func isSpecialPartition(fstabEntry diskutils.FstabEntry) bool {
}
}

func findSourcePartition(source string, partitions []diskutils.PartitionInfo) (string, error) {
_, partition, _, err := findSourcePartitionHelper(source, partitions)
func findSourcePartition(source string, partitions []diskutils.PartitionInfo, buildDir string) (string, error) {
_, partition, _, err := findSourcePartitionHelper(source, partitions, buildDir)
if err != nil {
return "", err
}
Expand All @@ -303,14 +303,14 @@ func findSourcePartition(source string, partitions []diskutils.PartitionInfo) (s
}

func findSourcePartitionHelper(source string,
partitions []diskutils.PartitionInfo,
partitions []diskutils.PartitionInfo, buildDir string,
) (imagecustomizerapi.MountIdentifierType, diskutils.PartitionInfo, int, error) {
mountIdType, mountId, err := parseSourcePartition(source)
if err != nil {
return imagecustomizerapi.MountIdentifierTypeDefault, diskutils.PartitionInfo{}, 0, err
}

partition, partitionIndex, err := findPartition(mountIdType, mountId, partitions)
partition, partitionIndex, err := findPartition(mountIdType, mountId, partitions, buildDir)
if err != nil {
return imagecustomizerapi.MountIdentifierTypeDefault, diskutils.PartitionInfo{}, 0, err
}
Expand All @@ -319,7 +319,7 @@ func findSourcePartitionHelper(source string,
}

func findPartition(mountIdType imagecustomizerapi.MountIdentifierType, mountId string,
partitions []diskutils.PartitionInfo,
partitions []diskutils.PartitionInfo, buildDir string,
) (diskutils.PartitionInfo, int, error) {
matchedPartitionIndexes := []int(nil)
for i, partition := range partitions {
Expand All @@ -331,6 +331,52 @@ func findPartition(mountIdType imagecustomizerapi.MountIdentifierType, mountId s
matches = partition.PartUuid == mountId
case imagecustomizerapi.MountIdentifierTypePartLabel:
matches = partition.PartLabel == mountId
case imagecustomizerapi.MountIdentifierTypeDevMapper:
espPartition, err := findSystemBootPartition(partitions)
if err != nil {
return diskutils.PartitionInfo{}, 0, err
}

bootPartition, err := findBootPartitionFromEsp(espPartition, partitions, buildDir)
if err != nil {
return diskutils.PartitionInfo{}, 0, err
}

tmpDirBoot := filepath.Join(buildDir, "tmp-boot-partition")

// Temporarily mount the boot partition so that the grub config file can be read.
bootPartitionMount, err := safemount.NewMount(bootPartition.Path, tmpDirBoot, bootPartition.FileSystemType, 0, "", true)
if err != nil {
return diskutils.PartitionInfo{}, 0, fmt.Errorf("failed to mount boot partition (%s):\n%w", bootPartition.Path, err)
}
defer bootPartitionMount.Close()

// Read the grub config file.
grubCfgPath := filepath.Join(tmpDirBoot, "/grub2/grub.cfg")

kernelToArgs, err := extractKernelToArgsFromGrub(grubCfgPath)
if err != nil {
return diskutils.PartitionInfo{}, 0, fmt.Errorf("failed to extract kernel arguments from grub.cfg: %w", err)
}

err = bootPartitionMount.CleanClose()
if err != nil {
return diskutils.PartitionInfo{}, 0, fmt.Errorf("failed to close bootPartitionMount: %w", err)
}

for _, args := range kernelToArgs {
argsParts := strings.Split(args, " ")
for _, part := range argsParts {
if strings.HasPrefix(part, "systemd.verity_root_data=PARTUUID=") {
extractedMountId := strings.TrimPrefix(part, "systemd.verity_root_data=PARTUUID=")
matches = partition.PartUuid == extractedMountId
break
}
}
if matches {
break
}
}
}
if matches {
matchedPartitionIndexes = append(matchedPartitionIndexes, i)
Expand Down Expand Up @@ -368,6 +414,10 @@ func parseSourcePartition(source string) (imagecustomizerapi.MountIdentifierType
return imagecustomizerapi.MountIdentifierTypePartLabel, partLabel, nil
}

if strings.HasPrefix(source, "/dev/mapper") {
return imagecustomizerapi.MountIdentifierTypeDevMapper, source, nil
}

err := fmt.Errorf("unknown fstab source type (%s)", source)
return imagecustomizerapi.MountIdentifierTypeDefault, "", err
}
Expand Down

0 comments on commit 86e12b3

Please sign in to comment.