LWN.net Logo

KS2012: Module signing

By Jake Edge
September 6, 2012
2012 Kernel Summit

From several accounts, day one of this year's Kernel Summit was largely argument-free. There were plenty of discussions, even minor disagreements, but nothing approaching some of the battles of yore. Day three looked like it might provide an exception to that pattern with a discussion of two different patch sets that are both targeted at cryptographically signing kernel modules. In the end, though, the pattern continued, with an interesting, but tame, session.

Kernel modules are inserted into the running kernel, so a rogue module could be used to compromise the kernel in ways that are hard to detect. One way to prevent that from happening is to require that kernel modules be cryptographically signed using keys that are explicitly allowed by the administrator. Before loading the module, the kernel can check the signature and refuse to load any that can't be verified. Those modules could come from a distribution or be built with a custom kernel. Since modules can be loaded based on a user action (e.g. attaching a device or using a new network protocol) or come from a third-party (e.g. binary kernel modules), ensuring that only approved modules can be loaded is a commonly requested feature.

Rusty Russell, who maintains the kernel module subsystem, called the meeting to try to determine how to proceed on module signing. David Howells has one patch set that is based on what has been in RHEL for some time, while Dmitry Kasatkin posted another that uses the digital signature support added to the kernel for integrity management. Howells's patches have been around, in various forms, since 2004, while Kasatkin's are relatively new.

Russell prefaced the discussion with an admonishment that he was not interested in discussing the "politics, ethics, or morality" of module signing. He invited anyone who did want to debate those topics to a meeting at 8pm, which was shortly after he had to leave for his plane. The reason we will be signing modules, he said, is because Linus Torvalds wants to be able to sign his modules.

Kasatkin's approach would put the module signature in the extended attributes (xattrs) of the module file, Russell began, but Kasatkin said that choice was only a convenience. His patches are now independent of the integrity measurement architecture (IMA) and the extended verification module (EVM), both of which use xattrs. He originally used xattrs because of the IMA/EVM origin of the signature code he is using, and he did not want to change the module contents. Since then, he noted a response from Russell to Howells's approach and has changed his patches to add the module signature to the end of the file.

That led Russell into a bit of a historical journey. The original patches from Howells put the signature into an ELF section in the module file. But, because there was interest in having the same signature on both stripped and unstripped module files, there was a need to skip over some parts of the module file when calculating the hash that goes into the signature.

The amount of code needed to parse ELF was "concerning", Russell said. Currently, there are some simple sanity checks in the module-loading code, without any checks for malicious code because the belief was that you had to be root to load a module. While that is still true, the advent of things like secure boot and IMA/EVM has made checking for malicious code a priority. But Russell wants to ensure that the code doing that checking is as simple as possible to verify, which was not true when putting module signatures into ELF sections.

Greg Kroah-Hartman pointed out that you have to do ELF parsing to load the module anyway. There is a difference, though. If the module is being checked for maliciousness, that parsing happens after the signature is checked. Any parsing that is done before that verification is potentially handling untrusted input.

Russell would rather see the signature appended to the module file in some form. It could be a fixed-length signature block, as suggested by Torvalds, or there could be some kind of "magic string" followed by a signature. That would allow for multiple signatures on a module. Another suggestion was to change the load_module() system call so that the signature was passed in, which would "punt" the problem to user space "that I don't maintain anymore", Russell said.

Russell's suggestion was to just do a simple backward search from the end of the module file to find the magic string, but Howells was not happy with that approach for performance reasons. Instead, Howells added a 5-digit ASCII number for the length of the signature, which Russell found a bit inelegant. Looking for the magic string "doesn't take that long", he said, and module loading is not that performance-critical.

There were murmurs of discontent in the room about that last statement. There are those who are very sensitive about module loading times because it impacts boot speed. But, Russell said that he could live with ASCII numbers, as long as there was no need to parse ELF sections in the verification code. He does like the fact that modules can be signed in the shell, which is the reason behind the ASCII length value.

There are Red Hat customers asking for SHA-512 digests signed with 4K RSA keys, Howells said, but that may change down the road. That could make picking a size for a fixed-length signature block difficult. But, as Ted Ts'o pointed out, doing a search for the magic string is in the noise in comparison to doing RSA with 4K keys. The kernel crypto subsystem can use hardware acceleration to make that faster, Howells said. But, Russell was not convinced that the performance impact of searching for the magic string was significant and would like to see some numbers.

James Bottomley asked where the keys for signing would come from. Howells responded that the kernel build process can create a key. The public part would go into the kernel for verification purposes, while the private part would be used for signing. After the signing is done, that ephemeral private key could be discarded. There is also the option to specify a key pair to use.

Torvalds said that it was "stupid" to have stripped modules with the same signature as the unstripped versions. The build process should just generate signatures for both. Having logic to skip over various pieces of the module just adds a new attack point. Another alternative is to only generate signatures for the stripped modules as the others are only used for debugging and aren't loaded anyway, so they can be unsigned, he said. Russell agreed, suggesting that the build process could just call out to something to do the signing.

For binary modules, such as the NVIDIA graphics drivers, users would have to add the NVIDIA public key to the kernel ring, Peter Jones said.

Kees Cook brought up an issue that is, currently at least, specific to Chrome OS. In Chrome OS, there is a trusted root partition, so knowing the origin of a module would allow those systems to make decisions about whether or not to load them. Right now, the interface doesn't provide that information, so Cook suggested changing the load_module() system call (or adding a new one) that passed a file descriptor for the module file. Russell agreed that an additional interface was probably in order to solve that problem.

In the end, Russell concluded that there was a reasonable amount of agreement about how to approach module signing. He planned to look at the two patch sets, try to find the commonality between the two, and "apply something". In fact, he made a proposal, based partly on Howells's approach, on September 4. It appends the signature to the module file after a magic string as Russell has been advocating. As he said when wrapping up the discussion, his patch can provide a starting point to solving this longstanding problem.


(Log in to post comments)

KS2012: Module signing

Posted Sep 7, 2012 5:58 UTC (Fri) by alonz (subscriber, #815) [Link]

For binary modules, such as the NVIDIA graphics drivers, users would have to add the NVIDIA public key to the kernel ring, Peter Jones said.

And has anyone proposed a secure method to do this magic?

Just permitting the user (or even root) to add arbitrary public keys to the kernel key ring would basically compromise the entire mechanism – it allows the user to load any code (as the key can be one he has just generated on the spot to sign his malware).

Of course, the issue only arises in the full secure-boot scenario, so maybe there we would just block the adding of additional public keys (and thus totally block binary modules).

KS2012: Module signing

Posted Sep 7, 2012 8:32 UTC (Fri) by justincormack (subscriber, #70439) [Link]

You can add the keys at kernel build time I guess. Will not help if you want to add a new module vendor. Presumably a signed module could also add new keys, allowing a chain of trust though.

KS2012: Module signing

Posted Sep 8, 2012 12:35 UTC (Sat) by hmh (subscriber, #3838) [Link]

I sure hope you can constrain keys to modules. One should be able to tell the kernel that the nVidia key can only sign the nVidia module, and to refuse anything else it signed...

I am using nVidia only as an example.

KS2012: Module signing

Posted Sep 11, 2012 13:21 UTC (Tue) by njwhite (subscriber, #51848) [Link]

> One should be able to tell the kernel that the nVidia key can only sign the nVidia module, and to refuse anything else it signed...

Couldn't a compromised / hostile nVidia just creat a module that was called nvidia.ko, but did *bad thing*? Presumably one can't specify the allowed interfaces a module may use in advance.

Or am I misunderstanding you?

KS2012: Module signing

Posted Sep 14, 2012 23:19 UTC (Fri) by dashesy (subscriber, #74652) [Link]

nVidia already signs its kernels for other OS, so what is the harm in asking them also sign the Linux version.

KS2012: Module signing

Posted Sep 7, 2012 9:52 UTC (Fri) by juliank (subscriber, #45896) [Link]

Given that the nvidia drivers won't work in secure boot as Matthew Garret's patch set disables the relevant access in secure boot environments, there's not much point in thinking about this, right? Because if you don't have secure boot, you don't really need to have signed modules.

KS2012: Module signing

Posted Sep 7, 2012 10:14 UTC (Fri) by etienne (subscriber, #25256) [Link]

I am not sure to understand why interpreting the content of an ELF file looks so difficult.
I did so in my boot-loader, and it was far to be difficult - I even handled 32 or 64 bits ELFs without too much coding (I am limited in both code and data space in a real mode boot-loader).
I have to say I did not use standards ELF libraries, just re-coded the stuff based on the fields present in the files.
Obviously my code is not made for this kind of problem, but ELF sections is very simple stuff to redo by hand.
Most of the ELF code in that boot-loader is for 32/64 bits relocation, I assume module verification is done before relocation so it is not needed.
Once you get the different sections of the ELF, you can just sign the relevant parts (i.e. not the symbols) and you do not have a problem with stripped modules.

KS2012: Module signing

Posted Sep 7, 2012 13:37 UTC (Fri) by jake (editor, #205) [Link]

> I am not sure to understand why interpreting the content of an ELF
> file looks so difficult.

I don't know that anyone thought it was difficult, exactly, just that it added more code to a path where a bug could be disastrous -- which means that there is more code that needs a *lot* of scrutiny. A malicious module with hand-crafted ELF could then potentially subvert the module verification code.

After all, the module code *does* already have to do some ELF interpretation, but Rusty (at least) wanted to keep that code path to *after* the module's signature was verified.

jake

KS2012: Module signing

Posted Sep 11, 2012 8:14 UTC (Tue) by gdt (guest, #6284) [Link]

"I am not sure to understand why interpreting the content of an ELF file looks so difficult."

It's difficult if you cannot trust that the incoming file is reasonable. Remember, the attacker doesn't care if the ELF parses to something meaningful, as their goal is only to break your parser.

If you did want to use an ELF format then you'd write a new restricted function parser just to find the signatures. That would hopefully be something you could verify easily.

Using a container also makes it harder to add signatures (for example, a corporation could very well not trust all the modules which Well Known Linux Vendor signs and may add the corporation's own signing key to only the modules which it wants loaded). This implies that the parser has to have some of the ELF fields contribute to the checksum and others not contribute (eg, timestamps). Simpler -- and thus better in this security sensitive code -- to treat the file as text and to append the signatures outside of the ELF format.

KS2012: Module signing

Posted Sep 11, 2012 9:20 UTC (Tue) by etienne (subscriber, #25256) [Link]

> It's difficult if you cannot trust that the incoming file is reasonable.

We are talking of an header with one field indicating the offset of an array of quadruplet { offset-in-file, memory-address, size, flags }.
What is reasonable is acceptable values for what the kernel module loader uses, easily checked by your own unbreakable function.
What is generic (and re-useable) is to create another section to put a signature of everything described loadable (in flags).

If you sign the whole file (ignoring it is an ELF file), you may end up having problems of signature order (you will end up having to sign an already signed module at some point), or having to run two different PC with exactly the same distribution but different signatures.

KS2012: Module signing

Posted Sep 14, 2012 21:52 UTC (Fri) by Lennie (subscriber, #49641) [Link]

This is probably a stupid question, but if you want to be careful about parsing, why not have a file something like this ?:

- current module
- signature
- fixed-size length of signature
- fixed-size magic string

In that case you go to the end of the file (maybe refuse to load modules larger than size Z ?), get the last X bytes, check if it is the magic string. Then take the Y bytes before it and use that as a length (obviously checking some boundry and that the size isn't bigger than the file). And get the signature that way. Everything else is just the module.

Wouldn't that be very little code with very few things to check ?

Copyright © 2012, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds