diff --git a/osutil/disks/disks.go b/osutil/disks/disks.go index 4f04f14870a9..92d924133411 100644 --- a/osutil/disks/disks.go +++ b/osutil/disks/disks.go @@ -132,6 +132,10 @@ type Disk interface { // the case for DOS disks, but not for GPT disks. GPT disks have a backup // header section at the end of the disk that is not usable for partitions. UsableSectorsEnd() (uint64, error) + + // Model is the model name of the disk as an identifier that can + // be recognized by a user. + Model() string } // Partition represents a partition on a Disk device. diff --git a/osutil/disks/disks_linux.go b/osutil/disks/disks_linux.go index dd9caaf671cd..81b111a15d01 100644 --- a/osutil/disks/disks_linux.go +++ b/osutil/disks/disks_linux.go @@ -212,6 +212,7 @@ func diskFromUDevProps(deviceIdentifier string, deviceIDType string, props map[s devname: devname, devpath: devpath, hasPartitions: len(paths) != 0, + model: props["ID_MODEL"], }, nil } @@ -327,6 +328,8 @@ type disk struct { // whether the disk device has partitions, and thus is of type "disk", or // whether the disk device is a volume that is not a physical disk hasPartitions bool + + model string } func (d *disk) KernelDeviceNode() string { @@ -341,6 +344,10 @@ func (d *disk) DiskID() string { return d.diskID } +func (d *disk) Model() string { + return d.model +} + func (d *disk) Partitions() ([]Partition, error) { if !d.hasPartitions { // for i.e. device mapper disks which don't have partitions @@ -588,6 +595,7 @@ func diskFromPartUDevProps(props map[string]string) (*disk, error) { d.schema = schema d.diskID = partTableID + d.model = realDiskProps["ID_MODEL"] // since the mountpoint device has a disk, the mountpoint source itself // must be a partition from a disk, thus the disk has partitions diff --git a/osutil/disks/disks_linux_test.go b/osutil/disks/disks_linux_test.go index 07f5ae6ce50f..8aeab9ec7482 100644 --- a/osutil/disks/disks_linux_test.go +++ b/osutil/disks/disks_linux_test.go @@ -150,6 +150,7 @@ func (s *diskSuite) TestDiskFromDeviceNameHappy(c *C) { "ID_PART_TABLE_UUID": "foo", "ID_PART_TABLE_TYPE": "gpt", "DEVPATH": sdaSysfsPath, + "ID_MODEL": "No Name SSD", }, nil }) defer restore() @@ -158,6 +159,7 @@ func (s *diskSuite) TestDiskFromDeviceNameHappy(c *C) { c.Assert(err, IsNil) c.Assert(d.Dev(), Equals, "1:2") c.Assert(d.DiskID(), Equals, "foo") + c.Assert(d.Model(), Equals, "No Name SSD") c.Assert(d.Schema(), Equals, "gpt") c.Assert(d.KernelDeviceNode(), Equals, "/dev/sda") c.Assert(d.KernelDevicePath(), Equals, filepath.Join(dirs.SysfsDir, sdaSysfsPath)) diff --git a/osutil/disks/mockdisk.go b/osutil/disks/mockdisk.go index 7c5f550381b3..bf734c79ec94 100644 --- a/osutil/disks/mockdisk.go +++ b/osutil/disks/mockdisk.go @@ -56,6 +56,7 @@ type MockDiskMapping struct { DevPath string ID string + IDModel string DiskSchema string SectorSizeBytes uint64 DiskUsableSectorEnd uint64 @@ -177,6 +178,10 @@ func (d *MockDiskMapping) DiskID() string { return d.ID } +func (d *MockDiskMapping) Model() string { + return d.IDModel +} + func (d *MockDiskMapping) Schema() string { return d.DiskSchema } diff --git a/secboot/export_sb_test.go b/secboot/export_sb_test.go index 51a13d0dc94e..2a065c7f96c1 100644 --- a/secboot/export_sb_test.go +++ b/secboot/export_sb_test.go @@ -595,3 +595,7 @@ func MockSbWithPassphraseTries(f func(n uint) sb.ActivateContextOption) (restore func MockSbWithPINTries(f func(n uint) sb.ActivateContextOption) (restore func()) { return testutil.Mock(&sbWithPINTries, f) } + +func MockSbWithAuthRequestorUserVisibleName(f func(name string) sb.ActivateOption) (restore func()) { + return testutil.Mock(&sbWithAuthRequestorUserVisibleName, f) +} diff --git a/secboot/secboot_sb.go b/secboot/secboot_sb.go index ee426e74b3b7..78235e06da54 100644 --- a/secboot/secboot_sb.go +++ b/secboot/secboot_sb.go @@ -72,6 +72,7 @@ var ( sbWithAuthRequestor = sb.WithAuthRequestor sbWithPassphraseTries = sb.WithPassphraseTries sbWithPINTries = sb.WithPINTries + sbWithAuthRequestorUserVisibleName = sb.WithAuthRequestorUserVisibleName ) func init() { @@ -241,7 +242,11 @@ func UnlockVolumeUsingSealedKeyIfEncrypted(activation ActivateContext, disk disk return res, err } - options = append(options, sbWithVolumeName(mapperName), sbWithLegacyKeyringKeyDescriptionPaths(partDevice, sourceDevice)) + options = append(options, + sbWithVolumeName(mapperName), + sbWithLegacyKeyringKeyDescriptionPaths(partDevice, sourceDevice), + sbWithAuthRequestorUserVisibleName(fmt.Sprintf("%s (%s)", disk.Model(), part.PartitionLabel)), + ) if opts.AllowRecoveryKey { options = append(options, sbWithRecoveryKeyTries(3)) } diff --git a/secboot/secboot_sb_test.go b/secboot/secboot_sb_test.go index d143473de7bd..887847f62290 100644 --- a/secboot/secboot_sb_test.go +++ b/secboot/secboot_sb_test.go @@ -533,8 +533,10 @@ func (s *secbootSuite) TestUnlockVolumeUsingSealedKeyIfEncrypted(c *C) { // defer restore() mockDiskWithEncDev := &disks.MockDiskMapping{ + IDModel: "MY SUPER DISK", Structure: []disks.Partition{ { + PartitionLabel: "name", FilesystemLabel: "name-enc", PartitionUUID: "enc-dev-partuuid", FilesystemUUID: "enc-dev-uuid", @@ -823,31 +825,39 @@ func (s *secbootSuite) TestUnlockVolumeUsingSealedKeyIfEncrypted(c *C) { return storage, nil })() + nameOption := &mockActivateOption{"name"} + defer secboot.MockSbWithAuthRequestorUserVisibleName(func(name string) sb.ActivateOption { + c.Check(name, Equals, "MY SUPER DISK (name)") + return nameOption + })() + activateContext := newMockActivateContext( func(ctx context.Context, container sb.StorageContainer, opts ...sb.ActivateOption) error { c.Check(container, Equals, storage) if tc.rkAllow { if tc.noKeyFile || tc.errorReadKeyFile { - c.Assert(opts, HasLen, 3) - c.Check(opts[2], Equals, recoveryOption) - } else { c.Assert(opts, HasLen, 4) c.Check(opts[3], Equals, recoveryOption) + } else { + c.Assert(opts, HasLen, 5) + c.Check(opts[4], Equals, recoveryOption) } } else { if tc.noKeyFile || tc.errorReadKeyFile { - c.Assert(opts, HasLen, 2) - } else { c.Assert(opts, HasLen, 3) + } else { + c.Assert(opts, HasLen, 4) } } if tc.noKeyFile || tc.errorReadKeyFile { c.Check(opts[0], Equals, volumeNameOption) c.Check(opts[1], Equals, legacyKeyringPaths) + c.Check(opts[2], Equals, nameOption) } else { c.Check(opts[0], Equals, externalKey) c.Check(opts[1], Equals, volumeNameOption) c.Check(opts[2], Equals, legacyKeyringPaths) + c.Check(opts[3], Equals, nameOption) } return tc.activateErr @@ -1960,7 +1970,7 @@ func (s *secbootSuite) TestUnlockVolumeUsingSealedKeyIfEncryptedFdeRevealKeyErr( func(ctx context.Context, container sb.StorageContainer, opts ...sb.ActivateOption) error { activated++ c.Check(container, Equals, storage) - c.Assert(opts, HasLen, 3) + c.Assert(opts, HasLen, 4) c.Check(opts[0], Equals, externalKey) // XXX: this is what the real // MockSbActivateVolumeWithKeyData will do @@ -2414,8 +2424,10 @@ func (s *secbootSuite) TestUnlockVolumeUsingSealedKeyIfEncryptedFdeRevealKeyV2(c defer restore() mockDiskWithEncDev := &disks.MockDiskMapping{ + IDModel: "MY SUPER DISK", Structure: []disks.Partition{ { + PartitionLabel: "device-name", FilesystemLabel: "device-name-enc", FilesystemUUID: "enc-dev-uuid", PartitionUUID: "enc-dev-partuuid", @@ -2452,16 +2464,23 @@ func (s *secbootSuite) TestUnlockVolumeUsingSealedKeyIfEncryptedFdeRevealKeyV2(c return legacyKeyringPaths })() + nameOption := &mockActivateOption{"name"} + defer secboot.MockSbWithAuthRequestorUserVisibleName(func(name string) sb.ActivateOption { + c.Check(name, Equals, "MY SUPER DISK (device-name)") + return nameOption + })() + activated := 0 storage := &mockStorageContainer{name: "storage"} activateContext := newMockActivateContext( func(ctx context.Context, container sb.StorageContainer, opts ...sb.ActivateOption) error { activated++ c.Check(container, Equals, storage) - c.Assert(opts, HasLen, 3) + c.Assert(opts, HasLen, 4) c.Check(opts[0], Equals, externalKey) c.Check(opts[1], Equals, volumeNameOption) c.Check(opts[2], Equals, legacyKeyringPaths) + c.Check(opts[3], Equals, nameOption) // XXX: this is what the real // MockSbActivateVolumeWithKeyData will do c.Assert(foundKeyData, NotNil) @@ -2836,7 +2855,7 @@ func (s *secbootSuite) TestUnlockVolumeUsingSealedKeyIfEncryptedFdeRevealKeyBadJ func(ctx context.Context, container sb.StorageContainer, opts ...sb.ActivateOption) error { activated++ c.Check(container, Equals, storage) - c.Assert(opts, HasLen, 3) + c.Assert(opts, HasLen, 4) c.Check(opts[0], Equals, externalKey) // XXX: this is what the real // MockSbActivateVolumeWithKeyData will do