m/n/c/l/crypt: select partitions more specifically
This changes partition selection to only consider block devices which
contain the ESP we booted from if known.
This prevents us from mounting spurious partitions sharing the same
type identifiers.
While at it, convert to our GPT library.
Change-Id: Ie9f5bd596f793439a467759d5066529f3912028b
Reviewed-on: https://review.monogon.dev/c/monogon/+/1641
Tested-by: Jenkins CI
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
diff --git a/go.mod b/go.mod
index a9ab662..7e1f67c 100644
--- a/go.mod
+++ b/go.mod
@@ -108,7 +108,6 @@
github.com/pierrec/lz4/v4 v4.1.14
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.10.1
- github.com/rekby/gpt v0.0.0-20200614112001-7da10aec5566
github.com/rmohr/bazeldnf v0.5.4
github.com/sbezverk/nfproxy v0.0.0-20210112155058-0d98b4a69f0c
github.com/spf13/cobra v1.6.1
diff --git a/go.sum b/go.sum
index 3125dbb..4af2081 100644
--- a/go.sum
+++ b/go.sum
@@ -1889,8 +1889,6 @@
github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rekby/gpt v0.0.0-20200614112001-7da10aec5566 h1:U4d0m0NdADC5sjaWXeZpDZ/TFvE866u1Js5yP3M3mho=
-github.com/rekby/gpt v0.0.0-20200614112001-7da10aec5566/go.mod h1:scrOqOnnHVKCHENvFw8k9ajCb88uqLQDA4BvuJNJ2ew=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
diff --git a/metropolis/node/core/localstorage/crypt/BUILD.bazel b/metropolis/node/core/localstorage/crypt/BUILD.bazel
index 36e17bb..84b289b 100644
--- a/metropolis/node/core/localstorage/crypt/BUILD.bazel
+++ b/metropolis/node/core/localstorage/crypt/BUILD.bazel
@@ -13,8 +13,11 @@
visibility = ["//metropolis/node/core/localstorage:__subpackages__"],
deps = [
"//metropolis/pkg/devicemapper",
+ "//metropolis/pkg/efivarfs",
+ "//metropolis/pkg/gpt",
+ "//metropolis/pkg/supervisor",
"//metropolis/pkg/sysfs",
- "@com_github_rekby_gpt//:gpt",
+ "@com_github_google_uuid//:uuid",
"@org_golang_x_sys//unix",
],
)
diff --git a/metropolis/node/core/localstorage/crypt/blockdev.go b/metropolis/node/core/localstorage/crypt/blockdev.go
index dde2fd9..8b572e8 100644
--- a/metropolis/node/core/localstorage/crypt/blockdev.go
+++ b/metropolis/node/core/localstorage/crypt/blockdev.go
@@ -22,24 +22,20 @@
"os"
"path/filepath"
"strconv"
+ "unsafe"
- "github.com/rekby/gpt"
+ "github.com/google/uuid"
"golang.org/x/sys/unix"
+ "source.monogon.dev/metropolis/pkg/efivarfs"
+ "source.monogon.dev/metropolis/pkg/gpt"
+ "source.monogon.dev/metropolis/pkg/supervisor"
"source.monogon.dev/metropolis/pkg/sysfs"
)
-var (
- // EFIPartitionType is the standardized partition type value for the EFI
- // ESP partition. The human readable GUID is
- // C12A7328-F81F-11D2-BA4B-00A0C93EC93B.
- EFIPartitionType = gpt.PartType{0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b}
-
- // NodeDataPartitionType is the partition type value for a Metropolis Node
- // data partition. The human-readable GUID is
- // 9eeec464-6885-414a-b278-4305c51f7966.
- NodeDataPartitionType = gpt.PartType{0x64, 0xc4, 0xee, 0x9e, 0x85, 0x68, 0x4a, 0x41, 0xb2, 0x78, 0x43, 0x05, 0xc5, 0x1f, 0x79, 0x66}
-)
+// NodeDataPartitionType is the partition type value for a Metropolis Node
+// data partition.
+var NodeDataPartitionType = uuid.MustParse("9eeec464-6885-414a-b278-4305c51f7966")
const (
ESPDevicePath = "/dev/esp"
@@ -50,6 +46,10 @@
// to ESPDevicePath and NodeDataCryptPath respectively. This doesn't fail if it
// doesn't find the partitions, only if something goes catastrophically wrong.
func MakeBlockDevices(ctx context.Context) error {
+ espUUID, err := efivarfs.ReadLoaderDevicePartUUID()
+ if err != nil {
+ supervisor.Logger(ctx).Warningf("No EFI variable for the loader device partition UUID present")
+ }
blockdevNames, err := os.ReadDir("/sys/class/block")
if err != nil {
return fmt.Errorf("failed to read sysfs block class: %w", err)
@@ -65,6 +65,8 @@
return fmt.Errorf("failed to convert uevent: %w", err)
}
devNodeName := fmt.Sprintf("/dev/%v", ueventData["DEVNAME"])
+ // TODO(lorenz): This extraction code is all a bit hairy, will get
+ // replaced by blockdev shortly.
blkdev, err := os.Open(devNodeName)
if err != nil {
return fmt.Errorf("failed to open block device %v: %w", devNodeName, err)
@@ -74,20 +76,46 @@
if err != nil {
continue // This is not a regular block device
}
+ var sizeBytes uint64
+ _, _, err = unix.Syscall(unix.SYS_IOCTL, blkdev.Fd(), unix.BLKGETSIZE64, uintptr(unsafe.Pointer(&sizeBytes)))
+ if err != unix.Errno(0) {
+ return fmt.Errorf("failed to get device size: %w", err)
+ }
blkdev.Seek(int64(blockSize), 0)
- table, err := gpt.ReadTable(blkdev, uint64(blockSize))
+ table, err := gpt.Read(blkdev, int64(blockSize), int64(sizeBytes)/int64(blockSize))
if err != nil {
// Probably just not a GPT-partitioned disk
continue
}
+ skipDisk := false
+ if espUUID != uuid.Nil {
+ // If we know where we booted from, ignore all disks which do
+ // not contain this partition.
+ skipDisk = true
+ for _, part := range table.Partitions {
+ if part.ID == espUUID {
+ skipDisk = false
+ break
+ }
+ }
+ }
+ if skipDisk {
+ continue
+ }
+ seenTypes := make(map[uuid.UUID]bool)
for partNumber, part := range table.Partitions {
- if part.Type == EFIPartitionType {
+ if seenTypes[part.Type] {
+ return fmt.Errorf("failed to create device node for %s (%s): node for this type already created/multiple partitions found", part.ID.String(), part.Type.String())
+ }
+ if part.Type == gpt.PartitionTypeEFISystem {
+ seenTypes[part.Type] = true
err := unix.Mknod(ESPDevicePath, 0600|unix.S_IFBLK, int(unix.Mkdev(uint32(majorDev), uint32(partNumber+1))))
if err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create device node for ESP partition: %w", err)
}
}
if part.Type == NodeDataPartitionType {
+ seenTypes[part.Type] = true
err := unix.Mknod(NodeDataCryptPath, 0600|unix.S_IFBLK, int(unix.Mkdev(uint32(majorDev), uint32(partNumber+1))))
if err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create device node for Metropolis node encrypted data partition: %w", err)
diff --git a/third_party/go/repositories.bzl b/third_party/go/repositories.bzl
index cfd9e2f..5540762 100644
--- a/third_party/go/repositories.bzl
+++ b/third_party/go/repositories.bzl
@@ -4326,12 +4326,6 @@
)
go_repository(
- name = "com_github_rekby_gpt",
- importpath = "github.com/rekby/gpt",
- sum = "h1:U4d0m0NdADC5sjaWXeZpDZ/TFvE866u1Js5yP3M3mho=",
- version = "v0.0.0-20200614112001-7da10aec5566",
- )
- go_repository(
name = "com_github_remyoudompheng_bigfft",
importpath = "github.com/remyoudompheng/bigfft",
sum = "h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=",