mbox series

[v9,0/9] x86: Show in sysfs if a memory node is able to do encryption

Message ID 20220704135833.1496303-1-martin.fernandez@eclypsium.com (mailing list archive)
Headers show
Series x86: Show in sysfs if a memory node is able to do encryption | expand

Message

Martin Fernandez July 4, 2022, 1:58 p.m. UTC
Show for each node if every memory descriptor in that node has the
EFI_MEMORY_CPU_CRYPTO attribute.

fwupd project plans to use it as part of a check to see if the users
have properly configured memory hardware encryption
capabilities. fwupd's people have seen cases where it seems like there
is memory encryption because all the hardware is capable of doing it,
but on a closer look there is not, either because of system firmware
or because some component requires updating to enable the feature.

The MKTME/TME spec says that it will only encrypt those memory regions
which are flagged with the EFI_MEMORY_CPU_CRYPTO attribute.

If all nodes are capable of encryption and if the system have tme/sme
on we can pretty confidently say that the device is actively
encrypting all its memory.

It's planned to make this check part of an specification that can be
passed to people purchasing hardware

These checks will run at every boot. The specification is called Host
Security ID: https://fwupd.github.io/libfwupdplugin/hsi.html.

We choosed to do it a per-node basis because although an ABI that
shows that the whole system memory is capable of encryption would be
useful for the fwupd use case, doing it in a per-node basis would make
the path easier to give the capability to the user to target
allocations from applications to NUMA nodes which have encryption
capabilities in the future.


Changes since v8:

Add unit tests to e820_range_* functions


Changes since v7:

Less kerneldocs

Less verbosity in the e820 code


Changes since v6:

Fixes in __e820__handle_range_update

Const correctness in e820.c

Correct alignment in memblock.h

Rework memblock_overlaps_region


Changes since v5:

Refactor e820__range_{update, remove, set_crypto_capable} in order to
avoid code duplication.

Warn the user when a node has both encryptable and non-encryptable
regions.

Check that e820_table has enough size to store both current e820_table
and EFI memmap.


Changes since v4:

Add enum to represent the cryptographic capabilities in e820:
e820_crypto_capabilities.

Revert __e820__range_update, only adding the new argument for
__e820__range_add about crypto capabilities.

Add a function __e820__range_update_crypto similar to
__e820__range_update but to only update this new field.


Changes since v3:

Update date in Doc/ABI file.

More information about the fwupd usecase and the rationale behind
doing it in a per-NUMA-node.


Changes since v2:

e820__range_mark_crypto -> e820__range_mark_crypto_capable.

In e820__range_remove: Create a region with crypto capabilities
instead of creating one without it and then mark it.


Changes since v1:

Modify __e820__range_update to update the crypto capabilities of a
range; now this function will change the crypto capability of a range
if it's called with the same old_type and new_type. Rework
efi_mark_e820_regions_as_crypto_capable based on this.

Update do_add_efi_memmap to mark the regions as it creates them.

Change the type of crypto_capable in e820_entry from bool to u8.

Fix e820__update_table changes.

Remove memblock_add_crypto_capable. Now you have to add the region and
mark it then.

Better place for crypto_capable in pglist_data.

Martin Fernandez (9):
  mm/memblock: Tag memblocks with crypto capabilities
  mm/mmzone: Tag pg_data_t with crypto capabilities
  x86/e820: Add infrastructure to refactor e820__range_{update,remove}
  x86/e820: Refactor __e820__range_update
  x86/e820: Refactor e820__range_remove
  x86/e820: Tag e820_entry with crypto capabilities
  x86/e820: Add unit tests for e820_range_* functions
  x86/efi: Mark e820_entries as crypto capable from EFI memmap
  drivers/node: Show in sysfs node's crypto capabilities

 Documentation/ABI/testing/sysfs-devices-node |  10 +
 arch/x86/Kconfig.debug                       |  10 +
 arch/x86/include/asm/e820/api.h              |   1 +
 arch/x86/include/asm/e820/types.h            |  12 +-
 arch/x86/kernel/e820.c                       | 393 ++++++++++++++-----
 arch/x86/kernel/e820_test.c                  | 249 ++++++++++++
 arch/x86/platform/efi/efi.c                  |  37 ++
 drivers/base/node.c                          |  10 +
 include/linux/memblock.h                     |   5 +
 include/linux/mmzone.h                       |   3 +
 mm/memblock.c                                |  62 +++
 mm/page_alloc.c                              |   1 +
 12 files changed, 695 insertions(+), 98 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-node
 create mode 100644 arch/x86/kernel/e820_test.c

Comments

Borislav Petkov Oct. 13, 2022, 7:48 p.m. UTC | #1
On Mon, Jul 04, 2022 at 10:58:24AM -0300, Martin Fernandez wrote:
> If all nodes are capable of encryption and if the system have tme/sme
> on we can pretty confidently say that the device is actively
> encrypting all its memory.

Wait, what?

If all memory is crypto capable and I boot with mem_encrypt=off, then
the device is certainly not encrypting any memory.

dhansen says TME cannot be controlled this way and if you turn it off in
the BIOS, EFI_MEMORY_CPU_CRYPTO attr should not be set either. But that
marking won't work on AMD.

You really need to be able to check whether memory encryption is also
enabled.

And I believe I've said this before but even if encryption is on, it is
never "all its memory": the machine can decide to decrypt a page or a
bunch of them for whatever reason. And then they're plaintext.

> It's planned to make this check part of an specification that can be
> passed to people purchasing hardware

How is that supposed to work?

People would boot a Linux on that hardware and fwupd would tell them
whether it can encrypt memory or not?

But if that were the only use case, why can't EFI simply say that in its
fancy GUI?

Because all the kernel seems to be doing here is parrot further
EFI_MEMORY_CPU_CRYPTO.

And that attribute gets set by EFI so it goes and picks apart whether
the underlying hw can encrypt memory. So EFI could report it too.

Hmmm?
Martin Fernandez Oct. 13, 2022, 9 p.m. UTC | #2
On 10/13/22, Borislav Petkov <bp@alien8.de> wrote:
> On Mon, Jul 04, 2022 at 10:58:24AM -0300, Martin Fernandez wrote:
>> If all nodes are capable of encryption and if the system have tme/sme
>> on we can pretty confidently say that the device is actively
>> encrypting all its memory.
>
> Wait, what?
>
> If all memory is crypto capable and I boot with mem_encrypt=off, then
> the device is certainly not encrypting any memory.
>
> dhansen says TME cannot be controlled this way and if you turn it off in
> the BIOS, EFI_MEMORY_CPU_CRYPTO attr should not be set either.

That's bad, because it would be nice if that attribute only depended
on the hardware and not on some setting.

The plan of this patch was, as you mentioned just to report
EFI_MEMORY_CPU_CRYPTO in a per node level.

Now, I think I will need to check for tme/sme and only if those are
active then show the file in sysfs, otherwise not show it at all,
because it would be misleading. Any other idea?

> But that
> marking won't work on AMD.

You mean that EFI_MEMORY_CPU_CRYPTO means nothing on an AMD system?
Dave Hansen Oct. 14, 2022, 12:24 a.m. UTC | #3
On 10/13/22 12:48, Borislav Petkov wrote:
>> It's planned to make this check part of an specification that can be
>> passed to people purchasing hardware
> How is that supposed to work?
> 
> People would boot a Linux on that hardware and fwupd would tell them
> whether it can encrypt memory or not?
> 
> But if that were the only use case, why can't EFI simply say that in its
> fancy GUI?
> 
> Because all the kernel seems to be doing here is parrot further
> EFI_MEMORY_CPU_CRYPTO.
> 
> And that attribute gets set by EFI so it goes and picks apart whether
> the underlying hw can encrypt memory. So EFI could report it too.

I think the kernel _would_ just be parroting the firmware's info *if*
this stuff was all static at boot.  It pretty much _is_ static on
today's systems.  You generally can't hotplug memory (encrypted or not)
on any of these fancy memory encryption systems.  On the Intel side, I'm
thinking mostly of Ice Lake systems.

But, that is very much changing once CXL comes on the scene.  A system
might boot with only DRAM attached right to the CPU and all of it is
encryption-capable.  Then, some wise guys plugs in a CXL card that
doesn't support encryption.

That makes the "is everything encrypted" answer dynamic and is
essentially unanswerable at boot, other than to give a one-off answer.
Borislav Petkov Oct. 27, 2022, 8:57 a.m. UTC | #4
On Thu, Oct 13, 2022 at 06:00:58PM -0300, Martin Fernandez wrote:
> That's bad, because it would be nice if that attribute only depended
> on the hardware and not on some setting.

Why would that be bad?

You want to be able to disable encryption for whatever reason sometimes.

> The plan of this patch was, as you mentioned just to report
> EFI_MEMORY_CPU_CRYPTO in a per node level.
> 
> Now, I think I will need to check for tme/sme and only if those are
> active then show the file in sysfs, otherwise not show it at all,
> because it would be misleading. Any other idea?

Well, I still think this is not going to work in all cases. SME/TME can
be enabled but the kernel can go - and for whatever reason - map a bunch
of memory unencrypted.

So I don't know what the goal of this fwupd checking whether users have
configured memory encryption properly is. It might end up giving that
false sense of security...

> You mean that EFI_MEMORY_CPU_CRYPTO means nothing on an AMD system?

I mean, you still can disable memory encryption.
Dave Hansen Oct. 27, 2022, 3:21 p.m. UTC | #5
On 10/27/22 01:57, Borislav Petkov wrote:
> Well, I still think this is not going to work in all cases. SME/TME can
> be enabled but the kernel can go - and for whatever reason - map a bunch
> of memory unencrypted.

For TME on Intel systems, there's no way to make it unencrypted.  The
memory controller is doing all the encryption behind the back of the OS
and even devices that are doing DMA.  Nothing outside of the memory
controller really knows or cares that encryption is happening.
Borislav Petkov Oct. 27, 2022, 3:33 p.m. UTC | #6
On Thu, Oct 27, 2022 at 08:21:02AM -0700, Dave Hansen wrote:
> On 10/27/22 01:57, Borislav Petkov wrote:
> > Well, I still think this is not going to work in all cases. SME/TME can
> > be enabled but the kernel can go - and for whatever reason - map a bunch
> > of memory unencrypted.
> 
> For TME on Intel systems, there's no way to make it unencrypted.  The
> memory controller is doing all the encryption behind the back of the OS
> and even devices that are doing DMA.  Nothing outside of the memory
> controller really knows or cares that encryption is happening.

Ok, Tom just confirmed that AMD's TSME thing also encrypts all memory.

So I guess the code should check for TME or TSME. If those are set, then
you can assume that all memory is encrypted.