From 982e8fbf8e0ec5bc938749750b8aef75abf10ba7 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 22 Sep 2021 13:40:20 +0200 Subject: fde,devicestate: add new fde.CheckFeatures() and use in DeviceManager --- kernel/fde/fde.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'kernel') diff --git a/kernel/fde/fde.go b/kernel/fde/fde.go index 65e96679f4..cfe0fc507d 100644 --- a/kernel/fde/fde.go +++ b/kernel/fde/fde.go @@ -116,3 +116,28 @@ func InitialSetup(runSetupHook RunSetupHookFunc, params *InitialSetupParams) (*I } return res, nil } + +// CheckFeatures returns the features of fde-setup hook. +func CheckFeatures(runSetupHook RunSetupHookFunc) ([]string, error) { + req := &SetupRequest{ + Op: "features", + } + output, err := runSetupHook(req) + if err != nil { + return nil, err + } + var res struct { + Features []string `json:"features"` + Error string `json:"error"` + } + if err := json.Unmarshal(output, &res); err != nil { + return nil, fmt.Errorf("cannot parse hook output %q: %v", output, err) + } + if res.Features == nil && res.Error == "" { + return nil, fmt.Errorf(`cannot use hook: neither "features" nor "error" returned`) + } + if res.Error != "" { + return nil, fmt.Errorf("cannot use hook: it returned error: %v", res.Error) + } + return res.Features, nil +} -- cgit v1.2.3 From 074ef7e85314a6bf21663ce2ff0409ac0218d610 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 13 Sep 2021 17:54:38 +0200 Subject: fde: add new device-setup support to fde-setup This adds support for inline cryto hardware like Qualcomm ICE to the fde-setup binary. A new `op:device-setup` is used for this. --- kernel/fde/fde.go | 38 ++++++++++++++++++++++++++++++++++++-- kernel/fde/fde_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/fde/fde.go b/kernel/fde/fde.go index cfe0fc507d..9a19883015 100644 --- a/kernel/fde/fde.go +++ b/kernel/fde/fde.go @@ -29,6 +29,8 @@ import ( "encoding/json" "fmt" "os/exec" + + "github.com/snapcore/snapd/osutil" ) // HasRevealKey return true if the current system has a "fde-reveal-key" @@ -70,16 +72,24 @@ func unmarshalInitialSetupResult(hookOutput []byte) (*InitialSetupResult, error) return &res, nil } +// TODO: unexport this because how the hook is driven is an implemenation +// deail. It creates quite a bit of churn unfortunately, see +// https://github.com/snapcore/snapd/compare/master...mvo5:ice/refactor-fde?expand=1 +// // SetupRequest carries the operation and parameters for the fde-setup hooks // made available to them via the snapctl fde-setup-request command. type SetupRequest struct { - // XXX: make "op" a type: "features", "initial-setup", "update" ? Op string `json:"op"` // This needs to be a []byte so that Go's standard library will base64 // encode it automatically for us - Key []byte `json:"key,omitempty"` + Key []byte `json:"key,omitempty"` + + // Only used when called with "initial-setup" KeyName string `json:"key-name,omitempty"` + + // Only used when called with "hw-inline-setup" + Device string `json:"device,omitempty"` } // A RunSetupHookFunc implements running the fde-setup kernel hook. @@ -141,3 +151,27 @@ func CheckFeatures(runSetupHook RunSetupHookFunc) ([]string, error) { } return res.Features, nil } + +// DeviceSetupParams contains the inputs for the fde-setup hook. +// The encryption key and the device (partition) are passed in. +type DeviceSetupParams struct { + Key []byte + Device string +} + +// DeviceSetup invokes the "device-setup" op running the fde-setup +// hook via runSetupHook. This is can be used to e.g. initializes +// inline crypto hardware. +func DeviceSetup(runSetupHook RunSetupHookFunc, params *DeviceSetupParams) error { + req := &SetupRequest{ + Op: "device-setup", + Key: params.Key, + Device: params.Device, + } + hookOutput, err := runSetupHook(req) + if err != nil { + return fmt.Errorf("device setup failed with: %v", osutil.OutputErr(hookOutput, err)) + } + + return nil +} diff --git a/kernel/fde/fde_test.go b/kernel/fde/fde_test.go index a84aa4dc94..50d5d1d871 100644 --- a/kernel/fde/fde_test.go +++ b/kernel/fde/fde_test.go @@ -525,3 +525,49 @@ func (s *fdeSuite) TestRevealErr(c *C) { // ensure no tmp files are left behind c.Check(osutil.FileExists(filepath.Join(dirs.GlobalRootDir, "/run/fde-reveal-key")), Equals, false) } + +func (s *fdeSuite) TestDeviceSetupHappy(c *C) { + mockKey := []byte{1, 2, 3, 4} + mockDevice := "/dev/sda2" + + runSetupHook := func(req *fde.SetupRequest) ([]byte, error) { + c.Check(req, DeepEquals, &fde.SetupRequest{ + Op: "device-setup", + Key: mockKey, + Device: mockDevice, + }) + // empty reply: no error + mockJSON := `{}` + return []byte(mockJSON), nil + } + + params := &fde.DeviceSetupParams{ + Key: mockKey, + Device: mockDevice, + } + err := fde.DeviceSetup(runSetupHook, params) + c.Assert(err, IsNil) +} + +func (s *fdeSuite) TestDeviceSetupError(c *C) { + mockKey := []byte{1, 2, 3, 4} + mockDevice := "/dev/sda2" + + runSetupHook := func(req *fde.SetupRequest) ([]byte, error) { + c.Check(req, DeepEquals, &fde.SetupRequest{ + Op: "device-setup", + Key: mockKey, + Device: mockDevice, + }) + // empty reply: no error + mockJSON := `something failed badly` + return []byte(mockJSON), fmt.Errorf("exit status 1") + } + + params := &fde.DeviceSetupParams{ + Key: mockKey, + Device: mockDevice, + } + err := fde.DeviceSetup(runSetupHook, params) + c.Check(err, ErrorMatches, "device setup failed with: something failed badly") +} -- cgit v1.2.3 From b7b5cf2f5cf86e517b4cf17fbaedff099e1395af Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 7 Oct 2021 09:43:03 +0200 Subject: fde: tweak/fix doc strings (thanks to Ian) --- kernel/fde/fde.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/fde/fde.go b/kernel/fde/fde.go index 9edd4f1246..de7b32438d 100644 --- a/kernel/fde/fde.go +++ b/kernel/fde/fde.go @@ -83,7 +83,7 @@ func unmarshalInitialSetupResult(hookOutput []byte) (*InitialSetupResult, error) } // TODO: unexport this because how the hook is driven is an implemenation -// deail. It creates quite a bit of churn unfortunately, see +// detail. It creates quite a bit of churn unfortunately, see // https://github.com/snapcore/snapd/compare/master...mvo5:ice/refactor-fde?expand=1 // // SetupRequest carries the operation and parameters for the fde-setup hooks @@ -98,7 +98,8 @@ type SetupRequest struct { // Only used when called with "initial-setup" KeyName string `json:"key-name,omitempty"` - // Only used when called with "hw-inline-setup" + // The part of the device kernel path for a "setup-device" call. + // Only used when called with "device-setup" Device string `json:"device,omitempty"` } @@ -170,7 +171,7 @@ type DeviceSetupParams struct { } // DeviceSetup invokes the "device-setup" op running the fde-setup -// hook via runSetupHook. This is can be used to e.g. initializes +// hook via runSetupHook. This can be used to e.g. initialize // inline crypto hardware. func DeviceSetup(runSetupHook RunSetupHookFunc, params *DeviceSetupParams) error { req := &SetupRequest{ -- cgit v1.2.3 From 96141d32a09c88f7f3624ec3777c2a0de3267cee Mon Sep 17 00:00:00 2001 From: Ian Johnson Date: Mon, 8 Nov 2021 16:19:43 -0600 Subject: kernel/fde: add DeviceUnlockKernelHookDeviceMapperHandler, use w/ disks pkg Add two new functions, IsEncryptedDeviceMapperName to identify if a device mapper node is with a device-unlock encrypted mapper name device, and DeviceUnlockKernelHookDeviceMapperHandler to combine the identification with the task of "un-mapping" the device mapper to the original source disk. Also register this with the disks package so users of the disks package will get this built-in when they also import the fde package. Signed-off-by: Ian Johnson --- kernel/fde/fde_test.go | 24 ++++++++++++++++++++++++ kernel/fde/mapper.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 kernel/fde/mapper.go (limited to 'kernel') diff --git a/kernel/fde/fde_test.go b/kernel/fde/fde_test.go index ae78f42095..db221b0036 100644 --- a/kernel/fde/fde_test.go +++ b/kernel/fde/fde_test.go @@ -598,3 +598,27 @@ func (s *fdeSuite) TestHasDeviceUnlock(c *C) { c.Check(fde.HasDeviceUnlock(), Equals, true) } + +func (s *fdeSuite) TestIsEncryptedDeviceMapperName(c *C) { + // matches + for _, t := range []string{ + "something-device-locked", + "foo23-device-locked", + "device-device-locked", + "WE-DON'T-CARE-WHAT-THE-PREFIX-IS-AND-YOU-CAN'T-MAKE-US-device-locked", + } { + c.Assert(fde.IsEncryptedDeviceMapperName(t), Equals, true) + } + + // doesn't match + for _, t := range []string{ + "", + "-device-locked", + "device-locked", + "-device-locked-foo", + "some-device", + "CRYPT-LUKS2-5a522809c87e4dfa81a88dc5667d1304-ubuntu-data-3776bab4-8bcc-46b7-9da2-6a84ce7f93b4", + } { + c.Assert(fde.IsEncryptedDeviceMapperName(t), Equals, false) + } +} diff --git a/kernel/fde/mapper.go b/kernel/fde/mapper.go new file mode 100644 index 0000000000..376ac330a4 --- /dev/null +++ b/kernel/fde/mapper.go @@ -0,0 +1,49 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2021 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package fde + +import ( + "path/filepath" + "strings" + + "github.com/snapcore/snapd/osutil/disks" +) + +// IsEncryptedDevice returns true when the provided device mapper name indicates +// that it is encrypted using FDE hooks. +func IsEncryptedDeviceMapperName(dmName string) bool { + // TODO: is there anything more we can use to limit the prefix of the + // dmName? + return dmName != "-device-locked" && strings.HasSuffix(dmName, "-device-locked") +} + +func DeviceUnlockKernelHookDeviceMapperHandler(dmUUID, dmName []byte) (dev string, ok bool) { + if !IsEncryptedDeviceMapperName(string(dmName)) { + return "", false + } + // this is a device encrypted using FDE hooks + + // the uuid of the mapper device is the same as the partuuid + return filepath.Join("/dev/disk/by-partuuid", string(dmUUID)), true +} + +func init() { + disks.RegisterDeviceMapperBackResolver("device-unlock-kernel-hook", DeviceUnlockKernelHookDeviceMapperHandler) +} -- cgit v1.2.3 From 00969d14032616ee8353d6f114083bc1722b3aae Mon Sep 17 00:00:00 2001 From: Ian Johnson Date: Tue, 16 Nov 2021 15:42:31 -0600 Subject: osutil/disks, kernel/fde: rename device mapper back resolver Thanks to Maciej for the suggestion. Signed-off-by: Ian Johnson --- kernel/fde/mapper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/fde/mapper.go b/kernel/fde/mapper.go index 376ac330a4..bd5aa849dd 100644 --- a/kernel/fde/mapper.go +++ b/kernel/fde/mapper.go @@ -45,5 +45,5 @@ func DeviceUnlockKernelHookDeviceMapperHandler(dmUUID, dmName []byte) (dev strin } func init() { - disks.RegisterDeviceMapperBackResolver("device-unlock-kernel-hook", DeviceUnlockKernelHookDeviceMapperHandler) + disks.RegisterDeviceMapperBackResolver("device-unlock-kernel-fde", DeviceUnlockKernelHookDeviceMapperHandler) } -- cgit v1.2.3 From 372f7f49872ae8fbf056d18b498075643c8f9d99 Mon Sep 17 00:00:00 2001 From: Ian Johnson Date: Mon, 22 Nov 2021 09:19:23 -0600 Subject: kernel/fde, osutil: rename functions, add doc-comments Thanks to Samuele for the suggestions. Signed-off-by: Ian Johnson --- kernel/fde/fde_test.go | 4 ++-- kernel/fde/mapper.go | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/fde/fde_test.go b/kernel/fde/fde_test.go index db221b0036..41e9491c4c 100644 --- a/kernel/fde/fde_test.go +++ b/kernel/fde/fde_test.go @@ -607,7 +607,7 @@ func (s *fdeSuite) TestIsEncryptedDeviceMapperName(c *C) { "device-device-locked", "WE-DON'T-CARE-WHAT-THE-PREFIX-IS-AND-YOU-CAN'T-MAKE-US-device-locked", } { - c.Assert(fde.IsEncryptedDeviceMapperName(t), Equals, true) + c.Assert(fde.IsHardwareEncryptedDeviceMapperName(t), Equals, true) } // doesn't match @@ -619,6 +619,6 @@ func (s *fdeSuite) TestIsEncryptedDeviceMapperName(c *C) { "some-device", "CRYPT-LUKS2-5a522809c87e4dfa81a88dc5667d1304-ubuntu-data-3776bab4-8bcc-46b7-9da2-6a84ce7f93b4", } { - c.Assert(fde.IsEncryptedDeviceMapperName(t), Equals, false) + c.Assert(fde.IsHardwareEncryptedDeviceMapperName(t), Equals, false) } } diff --git a/kernel/fde/mapper.go b/kernel/fde/mapper.go index bd5aa849dd..a1928a697b 100644 --- a/kernel/fde/mapper.go +++ b/kernel/fde/mapper.go @@ -28,14 +28,17 @@ import ( // IsEncryptedDevice returns true when the provided device mapper name indicates // that it is encrypted using FDE hooks. -func IsEncryptedDeviceMapperName(dmName string) bool { +func IsHardwareEncryptedDeviceMapperName(dmName string) bool { // TODO: is there anything more we can use to limit the prefix of the // dmName? return dmName != "-device-locked" && strings.HasSuffix(dmName, "-device-locked") } -func DeviceUnlockKernelHookDeviceMapperHandler(dmUUID, dmName []byte) (dev string, ok bool) { - if !IsEncryptedDeviceMapperName(string(dmName)) { +// DeviceUnlockKernelHookDeviceMapperBackResolver is a back resolver to be used +// with disks.RegisterDeviceMapperBackResolver for devices that implement full +// disk encryption via hardware devices with kernel snap hooks. +func DeviceUnlockKernelHookDeviceMapperBackResolver(dmUUID, dmName []byte) (dev string, ok bool) { + if !IsHardwareEncryptedDeviceMapperName(string(dmName)) { return "", false } // this is a device encrypted using FDE hooks @@ -45,5 +48,5 @@ func DeviceUnlockKernelHookDeviceMapperHandler(dmUUID, dmName []byte) (dev strin } func init() { - disks.RegisterDeviceMapperBackResolver("device-unlock-kernel-fde", DeviceUnlockKernelHookDeviceMapperHandler) + disks.RegisterDeviceMapperBackResolver("device-unlock-kernel-fde", DeviceUnlockKernelHookDeviceMapperBackResolver) } -- cgit v1.2.3