|
|
Log in / Subscribe / Register

Signing programs for Linux

By Jake Edge
September 13, 2017

Open Source Summit

At his 2017 Open Source Summit North America talk, Matthew Garrett looked at the state of cryptographic signing and verification of programs for Linux. Allowing policies that would restrict Linux from executing programs that are not signed would provide a measure of security for those systems, but there is work to be done to get there. Garrett started by talking about "binaries", but programs come in other forms (e.g. scripts) so any solution must look beyond simply binary executables.

There are a few different reasons to sign programs. The first is to provide an indication of the provenance of a program; whoever controls the key actually did sign it at some point. So if something is signed by a Debian or Red Hat key, it is strong evidence that it came from those organizations (assuming the keys have been securely handled). A signed program might be given different privileges based on the trust you place in a particular organization, as well.

[Matthew Garrett]

Signing also provides a form of tamper resistance. It is not possible to modify a program without invalidating the signature. Package signing does not provide this assurance, however. It shows that the package was not tampered with up until it was installed on the system, after that, there is no guarantee that the contents have not changed.

There is another benefit to signing that is related to the ability to know the provenance of the code. If it is determined that a certain key has either been compromised or is signing untrustworthy programs, all trust in that key can be removed from the system. This provides a way to blacklist programs emanating from a malicious (or insecure) organization, he said.

There have been various efforts to add signatures to programs along the way, including a way to integrate signatures in ELF binaries. That particular solution does not handle all of the use cases, though. For one thing, not all programs are ELF binaries; scripts for Python and other languages are semantically equivalent to ELF binaries but are just text files on disk. Scripting languages give access to system calls and other security-sensitive facilities. There are also binaries run on Linux that are not ELF, including Windows binaries that are run under Wine and binaries for other Unix platforms. So ELF signatures are not an approach that solves the problem, Garrett said.

IMA and friends

The kernel's Integrity Measurement Architecture (IMA) is another approach. The initial implementation was "fairly straightforward", he said. It will calculate hash values for files and log them based on a configurable policy. It is not restricted to binaries and simply provides an audit trail of the hashes of files accessed.

The policies are fairly fine-grained, so IMA could hash all files executed by anyone, for example, or all files opened by the root user. If there is a malware outbreak detected on one machine, others can be checked to see if they executed something with the same hash. IMA hooks into filesystem access, so it only does the hashing the first time the file is accessed; if the file is changed, it gets rehashed when it is next accessed. But IMA itself is not signing and there is no enforcement mechanism, he said.

Signing is the process of hashing a file then encrypting the hash using some kind of key (typically the private key of a public/private key pair). In order to verify the signature, the file is hashed and the encrypted hash is decrypted using the public key. If the two hashes match, the signature is verified. IMA is a great starting point for signing programs, he said, but more is needed.

The IMA appraisal feature adds the ability to store the raw hash or a signature in the security.ima extended attribute (xattr) of a file. Most filesystems have support for xattrs and the security xattr namespace is managed by the kernel, which protects those attributes from unprivileged updates. IMA appraisal allows the creation of policies controlling what happens when hashes or signatures do not match. For example, if there is no signature or the hash in the signature does not match the hash of the file, execution can be blocked.

All of that is only useful if you have signatures associated with the files that get installed on your system. Right now, those are not really available as distributions are not shipping signatures for the files in their packages. He has been working with the Debian dpkg maintainer to add metadata to .deb files; that metadata could be used to store signatures.

Build time is an obvious place to add signatures but it doesn't have to be done then; the .deb file could be pulled apart and signed later. There are some distinct advantages to doing things that way; since build systems are pretty much required to run arbitrary code, it is best if they do not have access to the signing keys. Moving the signing to the mirroring system would remove that danger. IBM has some patches to add signature information to RPMs, but support for signing in the Debian or Fedora mirroring infrastructure has not yet been added.

That all means that we can "potentially have a future" where the files in the packages on your mirrors have signatures that could be written to the xattrs of the files as they are installed. The policy can be set so that lack of a signature means that the file cannot be executed, so there is no window for a race between installing the file and setting the xattr. Policy could be set locally (or by a distribution) to require all binaries to have signatures, or just those run by root.

In addition, IMA appraisal allows tying its policies to security labels as maintained by SELinux, AppArmor, or other Linux security modules (LSMs). So the system could be set up to require signature verification for files that have certain (high-security) labels. The appraisal can be ignored for most cases and only applied for security-critical programs and files.

It is important to note that Linux systems are rarely static; they are updated regularly (or should be), but there is more than just that. Many Linux systems, especially development machines, have locally built programs. Signing software that is locally built brings with it the danger of placing keys in harm's way.

A multi-level security scheme with multiple different security contexts might be one way to provide a useful development machine that still protects the security-critical parts of the system. Anything that wants access to the higher security contexts would require signature verification. Those in lower contexts would be blocked from accessing things like networking, D-Bus, and sensitive parts of the filesystem. Seccomp restrictions could be added as well. This would provide the best of both worlds by giving developers a functional environment while still protecting the most important and dangerous features.

The extended verification module (EVM) is meant to protect the IMA xattrs and other file attributes from offline tampering. A hash or signature of the xattr values, LSM labels, owner, group, and other metadata is stored for each file. EVM is not suitable for use by distributions, though, because one of the pieces of metadata it hashes is the inode number of the file, which is not something that is known by the distribution. EVM is geared toward systems that have temporary access to the key material; they can calculate and sign the EVM value, then lose access to the key.

Shortcomings

IMA appraisal has some shortcomings, however, Garrett said. There is no way to tie policy decisions to which key was used, so you can't set it up to do less appraisal for more-trusted keys and stronger appraisal for less-trusted keys. In addition, the action taken for appraisal failure is set at boot time, so it cannot be changed at runtime.

Beyond that, there are still problems for interpreted languages. The Python binary would likely be signed, for example, thus might be eligible to run in a higher security context. But code can just be piped to Python. That is why other operating systems are moving toward adding some awareness of security contexts into the language interpreter itself.

It turns out that Linux systems typically have many language interpreters installed, including some that may not be obvious at first glance. For example, Emacs and various media file interpreters can also execute code. Garrett has been thinking about ways to not have to modify all of these language interpreters.

One way might be to change how LSM security transitions happen. Currently, they happen when something is executed, but adding a way to taint a process based a file-open event could prevent piping code to the interpreters. The Linux pipefs could be changed to taint the processes using the pipe. For example, a command like the following:

    $ curl ... | bash
The pipe would taint the bash process so that it would not have access to higher security contexts. That still will not protect against interpreters that take command-line arguments (e.g. python -c), though.

In summary, Garrett said, IMA is an incredibly powerful tool, IMA appraisal goes even further, and IMA appraisal coupled with LSMs goes further still. It is not quite at the point of being deployable, but is getting close. It may even make sense for general-purpose distributions soon.

In the Q&A, James Morris pointed out that there are some complex issues regarding revoking access to resources that have already been opened, which would make Garrett's tainting idea difficult. Garrett acknowledged that, but said that after 15 years of discussing it, perhaps the kernel community should find a way to implement revoke(). Given that the process had the access from a higher security context prior to the taint, though, there may be situations where the lack of a way to revoke that access is still workable.

He was asked about a way to generalize handling language interpreters that can take code from the command line. Garrett said that each interpreter probably needs to be modified to provide a view into what code it is running. For example, the Python community is looking into that; he referred attendees to a recent LWN article about those efforts. Over time, all the different interpreters (Ruby, Lua, Perl, ...) will need to be modified to help support these features; it will take a lot of work over a long period of time, he said. There was some discussion of restricting command-line arguments to the interpreters for certain security contexts but, even if it is workable, it will take some more thinking to determine that.

Another audience member asked about how these mechanisms would work with multi-threaded programs. With a grin, Garrett responded: "wonderful question ... next question". He noted that there were some difficult problems to solve here and that the community should "not get too wrapped up in a perfect solution"; there may be good solutions that will suffice for some use cases. It is those solutions that should be pursued.

[I would like to thank the Linux Foundation for travel assistance to attend OSS in Los Angeles.]

Index entries for this article
SecuritySigning code
ConferenceOpen Source Summit North America/2017


to post comments

Signing programs for Linux

Posted Sep 13, 2017 17:23 UTC (Wed) by derobert (subscriber, #89569) [Link] (3 responses)

Signing packages should be sufficient, if those packages also contain checksums. E.g., on Debian you can chase checksum chains all the way from the signed Release file to an installed file on the filesystem, as long as the package includes debsums. Unfortunately not really securely as debsums hasn't switched hash functions in a long time and is still using MD5. There was some talk of changing it (see https://wiki.debian.org/Sha256sumsInPackages) but that mostly died out with the feeling being it should be done by dpkg instead. Which is on the dpkg roadmap (https://wiki.debian.org/Teams/Dpkg/RoadMap) but hasn't happened yet.

Also, signatures in xattrs have a few problems. NFS support for xattrs is still lacking (and I'm not sure any of the common networked filesystems are different). Also ext2/3/4 and btrfs all have a 4K limit on the total xattr size. A detached gpg signature I just made is 438 bytes, without the ASCII encoding. Current Debian stable's Release file signature (ASCII-encoded) is 2373 bytes.

Signing programs for Linux

Posted Sep 13, 2017 21:54 UTC (Wed) by Paf (subscriber, #91811) [Link]

Ext4 just got extended extended attribute support (ea_inode), but yeah, that's in the most recent kernel release only.

Signing programs for Linux

Posted Sep 17, 2017 4:54 UTC (Sun) by biergaizi (guest, #92498) [Link]

> The first is to provide an indication of the provenance of a program. Signing also provides a form of tamper resistance. It is not possible to modify a program without invalidating the signature.

Signing packages only provides indication, not tamper resistance.

The later is a valid use case, and can be parts of the "security-in-depth" design. For example, DirtyCoW allows attackers to modify any executable, if all executable is signed, the attack is much harder. Another example is Full-Disk Encryption, when cryptsetup was still using aes-cbc-essiv instead of aes-xts-plain64, it is possible to corrupt or tamper a file stored on encrypted filesystem, there was a PoC on implant a backdoor in system binaries, if signature is required, it can be stopped. It is also effective to protect the system from ordinary worms and viruses.

BTW, it may be sort of a double-edge sword because more vendors will use it to implement DRM easily...

Signing programs for Linux

Posted Sep 21, 2017 7:20 UTC (Thu) by njs (subscriber, #40338) [Link]

An ed25519 signature is just 64 bytes. I don't think signature size is a big deal if you use modern crypto and optimize for it.

Threads?

Posted Sep 13, 2017 17:36 UTC (Wed) by mrshiny (guest, #4266) [Link] (1 responses)

Forgive my ignorance: what do threads have to do with signing?

Threads?

Posted Sep 13, 2017 20:24 UTC (Wed) by k8to (guest, #15413) [Link]

I think, but don't know, that the concerns are around the tainting discussions.

Signing programs for Linux

Posted Sep 13, 2017 18:35 UTC (Wed) by jhhaller (guest, #56103) [Link] (4 responses)

Signing is also inadequate, as it allows "replaying" old, but buggy binaries which were signed. The Update Framework (TUF) provides a mechanism to ensure only the most recent version of a package is downloaded from a repository. This still doesn't handle the unpackaged binaries, but Docker's Notary project, built on TUF, serves this purpose for containers.

I expect some combination of approaches will ultimately need to be used. TUF requires making an Internet query to validate a package's new-ness, which is not performance effective. Combining validating packages with TUF, and only allowing EVM measures to be updated via validated package installation would help. Protection can go back as far as the BIOS update recommendations from NIST, through to using the TPM to measure the boot process. Some vendors have started signing peripheral firmware, like drives. Signed buggy code will still be buggy code, so an infectable system will remain vulnerable.

Signing programs for Linux

Posted Sep 14, 2017 2:43 UTC (Thu) by unixbhaskar (guest, #44758) [Link] (3 responses)

Yup, I do agree on this part!

"Signed buggy code will still be buggy code, so an infectable system will remain vulnerable"

Signing programs for Linux

Posted Sep 14, 2017 3:54 UTC (Thu) by k8to (guest, #15413) [Link] (2 responses)

I feel like this is sort of missing the point.

I don't think signing is intended to prevent systems from being compromised, but to prevent systems from being compromised by running software the owner did not authorize / permit.

Sure, if the owner of the system authorized or permitted buggy code, there are still ways the system can be compromised, but that remains true even if you lock down the installed versions path.

I feel like solving "no old buggy versions" is a worthwhile goal, but probably not one to attack at the kernel interface level.

Signing programs for Linux

Posted Sep 14, 2017 5:57 UTC (Thu) by jmspeex (guest, #51639) [Link]

This is not about forcing the user to upgrade the software. It's about preventing an attacker from downgrading version. Assuming that eventually all software has bugs, letting an attacker downgrade to a 10 year old version is just as bad as letting the same attacker add a backdoor to a binary.

Signing programs for Linux

Posted Sep 14, 2017 14:01 UTC (Thu) by jhhaller (guest, #56103) [Link]

I agree that the kernel isn't the place to ensure running the latest version, that's why I suggested that package system deal with maintaining the signatures, with the kernel only validating signatures. Then it's only a matter of restricting applying signatures to packaging systems.

Let's keep our bugs to the newly discovered variety.

Signing programs for Linux

Posted Sep 14, 2017 5:28 UTC (Thu) by Otus (subscriber, #67685) [Link]

> That still will not protect against interpreters that take command-line arguments (e.g. python -c), though.

You would also need to have all the installed packages and system libraries signed and verified to prevent tampering there.

With many programs configuration files must also be trusted for the whole execution to be. Even if they do not allow arbitrary code to be injected they often allow breaking choices like insecure cryptographic algorithms.

(IMO it is easier to put it all in a signed container if you need this.)

Signing programs for Linux

Posted Sep 14, 2017 7:00 UTC (Thu) by mjthayer (guest, #39183) [Link]

Many other systems have been thinking about - and doing - executable signing for quite a bit longer than GNU/Linux or generic Linux (or whatever) has, but I only see one reference to other operating systems in the report. Have any lessons or best practices been learnt here?

Signing programs for Linux

Posted Sep 14, 2017 7:13 UTC (Thu) by dgm (subscriber, #49227) [Link]

Origin verification, privilege assignment and integrity checking are not interchangeable, so they should be carried out separately. File signing can be OK for integrity checking, specially for removable storage, but so can be encrypting the contents.

In any case, I think it's a mistake to try to use it for privilege assignment or origin verification. In particular, origin verification should be done when a file first comes to the system, so signed packages is a way better method. And using it to decide privileges is a no-no, because of leaked keys and old versions, as others have said.

This seems so obvious that I'm afraid that I'm missing some important piece of the story.

Signing programs for Linux

Posted Sep 14, 2017 8:36 UTC (Thu) by lamby (subscriber, #42621) [Link] (2 responses)

Is the video for this talk available?

Signing programs for Linux

Posted Sep 22, 2017 11:47 UTC (Fri) by willy (subscriber, #9762) [Link]

Only the keynotes were recorded at LinuxCon (this was also true last year)

Signing programs for Linux

Posted Oct 18, 2017 22:50 UTC (Wed) by bengen (guest, #14957) [Link]

Matthew gave a similar talk at DebConf17 and there's video available:
https://debconf17.debconf.org/talks/174/

Signing programs for Linux

Posted Sep 14, 2017 20:48 UTC (Thu) by jreiser (subscriber, #11027) [Link] (1 responses)

It is not possible to modify a program without invalidating the signature. That statement is false for a non-trivial fraction of programs that are longer than the signature; just apply the pigeon-hole principle. What is true, is that today such modification (while keeping the same signature) is regarded as very impractical; but wait some years...

Signing programs for Linux

Posted Sep 29, 2017 5:33 UTC (Fri) by richard77 (guest, #117898) [Link]

I think that is included in the definition of hashing. It would be a bit impractical to include in every article the basic concepts used.


Copyright © 2017, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds