Serious Security: Linux full-disk encryption bug fixed – patch now!

Lots of people “run Linux” without really knowing or caring – many home routers, navigational aids, webcams and other IoT devices are based on it; the majority of the world’s mobile phones run a Linux-derived variant called Android; and many, if not most, of the ready-to-go cloud services out there rely on Linux to host your content.

But plenty of users and sysadmins don’t just “use Linux”, they’re responsible for hundreds, thousands, perhaps even millions of other people’s desktops, laptops and servers on which Linux is running.

Those sysadmins are usually responsible not merely for ensuring that the systems under their jurisdiction are running reliably, but also for keeping them as safe and secure as they can.

In today’s world, that almost certainly means knowing, understanding, deploying and managing some sort of full-disk encryption system, and on Linux, that probably means using a system called LUKS (Linux Unified Key Setup) and a program called cryptsetup to look after it.

FDE for the win

Full-disk encryption, usually referred to simply as FDE, is a simple but effective idea: encrypt every sector just before it’s written to the disk, regardless of the software, user, file or directory that it belongs to; decrypt every sector just after it’s read back in.

FDE is rarely enough on its own, because there’s basically one password for everything, so you usually end up by layering further levels of file-specific, app-sepcific or user-specific password protection on top of it.

But FDE can considered mandatory these days, notably for laptops, for exactly the same reason: there is AT LEAST one password for everthing, so there’s nothing left behind that isn’t encrypted at all.

With FDE, you don’t have to worry about files you might have forgotten to encrypt; or those temporary copies you made from an encrypted folder into an unencrytped one while preparing for a handover; or those annoyingly plentiful intermediate files that are unavoidably generated by your favourite apps when you use menu options such as Export, Compile or Print.

With FDE, everything gets encrypted, including unused parts of the disk, deleted sectors, filenames, swapfile data, the apps you’re using, the operating system files you’ve installed, and even the disk space you’ve deliberately zeroed out to forcibly overwrite what was there before.

After all, if you leave nothing unencrypted and your laptop gets stolen, the data on the disk isn’t much use to the thieves, or to the cybercrooks they sell it to.

If you can show that you did, indeed, install FDE on the now-missing laptops, then you can put your hand on your heart and swear to your auditors, to your regulators, to your customers – and even to inquisitive journalists! – that they have little or nothing to fear if that stolen laptop ever shows up on the dark web.

FDE considered green

Better yet, if you want to retire old equipment – especially if it’s not working reliably – then FDE generally makes it much less controversial to send the old gear for generic reuse or recycling.

FDE means that if someone with ulterior motives buys up superannuated kit from your recycling company, extracts the old disk drives and somehow coaxes ithem back to life, they won’t easily be able to dump your old data for fun and profit.

Without FDE, old storage devices become a bit like nuclear waste: there are very few people you dare trust them to for “repurposing”, so you typically ended up with old safes crammed with “we aren’t sure what to do with these yet” disk drives, or with a laborious device destruction protocol that is nowhere near as environmentally friendly as it ought to be.

(Dropping old materiel into a blast furnace is fast and effective – law enforcement teams have been known do this, live on TV, after weapons amnesties aimed at reducing endemic violence – but blindly vapourising computer kit and its many eosteric metals and polymers is no longer an acceptable face of “secure erasure”.)

But what if there’s a bug?

The problem with FDE – and, just as importantly, the software tools that help you manage it reliably – is that it’s easy to do badly.

Did you use the right cryptographic algorithm? Did you generate the encryption keys reliably? Did you handle the issue of data integrity properly? Can you change passwords safely and quickly? How easy is it to lock yourself out by mistake? What if you want to adjust the encryption parameters as your corporate policies evolve?

Unfortunately, the cryptsetup program, widely used to manage Linux FDE in a way that addresses the questions above, turns out to have had a nasty bug, dubbed CVE-2021-4122, in a useful feature it offers called re-encryption.

A well-designed FDE solution doesn’t use your password directly as a raw, low-level encryption key, for several good reasons:

  • Changing the low-level key means decrypting and re-encrypting the entire disk. This may take several hours.
  • Multiple users need to share a single key. So you can’t retire one user’s access without locking out everyone else at the same time.
  • Users often choose weak passwords, or suffer password breaches. If you realise this just happened, the faster you can change the password, the better.

So, most FDE systems choose a master passphrase for the device – for LUKS, it’s usually 512 bits long and comes from the kernel’s high-quality random generator.

Each password holder, up to 8 of them by default, chooses a personal password that’s used to create a personally-scrambled version of the master key stored in what LUKS calls a keyslot, so that the master key itself never actually needs to be stored anywhere except in memory while the device is in use.

Simply put: you can’t derive the master key for the device unless and until you provide a valid user key; none of the user keys are stored anywhere on the device; and neither the user keys nor the master key are ever revealed or stored in their plaintext forms by default.

You can dump the master key for a LUKS device, but it’s hard to do by mistake, and you need to put in a valid user key to generate the master key data:

# cryptsetup luksDump /dev/sdb --dump-master-key WARNING!
========
The header dump with volume key is sensitive information
that allows access to encrypted partition without a passphrase.
This dump should be stored encrypted in a safe place. Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdb: ****************
LUKS header information for /dev/sdb
Cipher name: aes
Cipher mode: xts-plain64
Payload offset: 32768
UUID: 72f6e201-cbdc-496b-98bd-707ece662c9a
MK bits: 512 <-- MK is short for "master key"
MK dump: 7a 31 05 ba f3 68 b6 be e5 6c 6f 16 92 44 ea 35 0b 66 fe ce ae ec a9 ec 22 db ea c9 9e 15 4d 60 f8 d0 b9 cb b5 1f ab f4 8f d3 e9 c1 1f 05 37 73 7d 64 df 8b be 38 e4 49 29 d1 5d 95 cd a4 9b 04
#

Reencryption options

As mentioned above, you sometimes need to change the master encryption settings on a device, especially if you need to adjust some of the parameters you used to keep up with changing encryption recommendations, such as switching to a larger key size.

For this purpose, cryptsetup provides a handy, but complex-to-implement, option called reencrypt, which actually takes care of three different processes: decrypting, encrypting, and re-encrypting your data, even while the device is in use.

Re-encrypting can, of course, be implemented with nothing more than options called --decrypt and --encrypt, but to re-encrypt a device while it is being used would then require you to decrypt the whole thing first, and then encrypt again from pure plaintext later on

That would leave you exposed to danger for much longer than is strictly necessary: if the device took 12 hours to decrypt and another 12 hours to encrypt again from scratch, at least some of the data on the disk would be in plaintext form for a full day, and more than 50% of the data would be in plaintext form for at least 12 hours.

Streamlining re-encryption

So, cryptsetup allows you to streamline the re-encryption process by keeping some of the disk encrypted with the old key, and the rest of it encrypted with the new key, while carefully keeping track of how far it’s got in case the process breaks half way through, or the computer needs to be shut down before the process has finished.

When you start up again, and a duly authorised user enters a password to mount the device (the user’s password temporarily decrypts both the old master key and the new one, so the double-barrelled decrypt-recrypt process can continue), the re-encryption process continues from where it left off…

…and at the end, the old master key is wiped out, and the new one committed as the sole encryption key for the underlying data.

Unfortunately, code that had been carefully designed to handle re-encryption was reused to implement the less useful but sometimes necessary options for “fully decrypt to plaintext” (equivalent to re-encrypting with a null cipher in the encryption stage), and “fully encrypt from plaintext” (essentially re-encryption with a null cipher in the decryption part).

And when repurposed in this way, the careful checks used in reencrypt mode to make sure that no-one had tampered with the temporary data used to track how far the process had got, and thus to prevent the abuse of the re-encrypt procedure by someone with root access to the disk but no knowledge of the password…

…were not applied.

Assessing the security impact

As the description of the relevant bugfix puts it:

The problem was caused by reusing a mechanism designed for actual reencryption operation without reassessing the security impact for new encryption and decryption operations. While the reencryption requires calculating and verifying both key digests, no digest was needed to initiate decryption recovery if the destination is plaintext (no encryption key).

Simply put: someone with physical access to the disk, but who did not have the password to decrypt it themselves, could deceive the re-encryption tool into thinking that it was part-way through a decrypt-only procedure, and therefore trick the FDE software into decrypting part of the disk, and leaving it unencrypted.

As the bug-fix explains, the LUKS system itself cannot “protect against intentional modification [because someone with phsycal access to the disk could write to it without going through the LUKS code], but such modification must not cause a violation of data confidentiality.”

And that’s the risk here: that you could end up with a disk that seems to be encrypted; that still needs a valid password to mount; that behaves as if it’s encrypted; that might satisfy your auditors that it is encrypted…

…but that nevertheless contains (perhaps large and numerous) chunks that are not only stored in plaintext but also won’t get re-encrypted later on.

Even worse, perhaps, is the observation that:

The attack can also be reversed afterward (simulating crashed encryption from a plaintext) with possible modification of revealed plaintext.

What this means is that a malevolent user could silently decrypt parts of a disk, for example on a server, without the password, quietly modify the decrypted data while it was in plaintext form – thanks to the lack of integrity protection in plaintext mode – and then seamlessly and surreptitiously re-encrypt and “re-integrify” the data later on.

Loosely put, they could – in theory, at least – stitch you up for something quite naughty – fraudulent-looking entries in a spreadsheet, perhaps, or improper commands in your Bash history such as downloading a cryptominer – by inserting bogus “evidence” and then re-encrypting it under your password, even though they don’t actually know your password.

What to do?

  • Upgrade to cryptsetup 2.4.3 or later. If you run a Linux distro that provides regular updates, you may already have this version. (Use cryptsetup --version to find out.)
  • Learn how to detect when the reencrypt option is in use. You can use the luksDump function to see if partial decryption/enrcyption is in progress. (See below.)
  • Restrict physical access as carefully as you can. Sometimes, for example if you are using cloud services or co-located servers, you don’t have total control over who can get at what. But even in a world of trusted computing modules and tamper-proof cryptographic chips, there’s no need to give everyone access if you can avoid it.

CRYPTSETUP COMMANDS TO TRACK RE-ENCRYPTION

 --> First command tells cryptsetup to boost the master key length to 512 bits # cryptsetup reencrypt /dev/sdb --key-size 512
Enter passphrase for key slot 1: [. . .] --> While re-encrypting, you will see two extra keylots in use, one to access
--> the new master key (slot 0 here) and the other to keep track of how far
--> the decrypt-and-recrypt process has got (slot 2 here) # cryptsetup luksDump /dev/sdb
[. . .]
Keyslots: 0: luks2 (unbound) Key: 512 bits [. . .] Salt: f4 be b9 3f 15 bc 8f 97 43 2c f8 1f 31 e3 60 d1 [. . .] 1: luks2 Key: 256 bits [. . .] Salt: 75 33 81 96 ba f3 ec 8a dc ef 28 dc 68 a9 a7 44 [. . .] 2: reencrypt (unbound) Key: 8 bits Priority: ignored Mode: reencrypt Direction: forward [. . .] --> After the re-encryption is complete, keyslot 1 (for access to the
--> old master key) is removed, keyslot 2 (denoting the progress of the
--> procedure) is removed, and keyslot 0 takes over for access to the device # cryptsetup luksDump /dev/sdb
[. . .]
Keyslots: 0: luks2 Key: 512 bits [. . .] Salt: f4 be b9 3f 15 bc 8f 97 43 2c f8 1f 31 e3 60 d1 [. . .]
go top