grsecurity 4.12 Updates
September 18, 2017
The purpose of today's post is to discuss some aspects of the extensive development performed for the latest release of grsecurity for version 4.12.13 of the Linux kernel. The focus of this release was improved container support, large performance improvements, and security enhancements to several existing features.
Over the past few years, even though the PaX UDEREF features's performance and security had been improved for x64 through the use of PCID, it's been increasingly desired to lower the performance of UDEREF even more when a grsecurity kernel is run on an SMAP-capable CPU. Thanks to several hardening improvements (made possible by RAP) we added on top of the upstream SMAP support, we felt comfortable switching to it as the security basis for UDEREF when available. This will happen automatically at runtime via asm alternatives support, while retaining the benefits of PaX's per-CPU PGDs. We'll soon be able to provide this improvement to our stable subscribers as well.
RANDKSTACK was previously known to have poor performance under virtualization, partially due to rdtsc being capable of causing a VM exit. Several approaches were benchmarked and evaluated for dealing with this issue in a secure way, and we eventually settled on an improvement for both native and virtualized systems that eliminates the performance issue. This change has been backported to our stable kernels.
A weakness in USERCOPY was closed based on an internal audit. The identified weakness permitted overflows in certain scenarios that still passed all USERCOPY verification. To date, this weakness is not resolved in the upstream variant/subset of USERCOPY.
Container incompatibilities with chroot-hardening features of grsecurity were all resolved. Previously, several of the chroot-hardening features would need to be disabled to support container environments, but this is no longer the case. One such change was to ignore the elevated subjective credentials added on behalf of the kernel to perform certain non-administrative operations on overlayfs. We have now verified Docker containers to work out of the box with the default high-security grsecurity settings. In addition to this, a requested feature to have container IDs included in all grsecurity logs has been added. All relevant fixes have been backported to our stable kernels, with the container ID change coming soon as an option to give log analyzers some time to adjust. Below is a screenshot demonstrating this support.
Various PaX features were updated to prepare for the upcoming 5-level page tables support, KASAN compatibility with certain features was resolved, VMAP_STACK was fixed to cooperate with PaX's per-CPU PGDs, and ASLR was enhanced to support the newly-added CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES option.
Our 4.13 port is nearing completion, so we offer some comments on Kees Cook's recent post on security improvements that made it to the upstream 4.13 kernel, since these improvements include features from grsecurity. We hope these comments can be helpful suggestions for upstream work.
PAX_REFCOUNT has existed since 2008. During that time, we've always provided a fast assembly-based implementation for supported architectures and have applied this protection automatically to all reference counter usage in the kernel. We are glad to see upstream developers have accepted that their initial decision to use architecture-independent C code for the refcount_t API would in practice result in users not enabling the security feature due to the performance impact it introduced. Criticisms of their original approach were raised by the PaX Team and Eric Biggers of Google, among others. Upstream now mimics the PaX implementation of fast per-architecture assembly-based checks. While for 4.13 this addition had to be disabled upstream due to a regression of theirs from the original PaX implementation, this was fixed for 4.14 when they more closely matched PaX's original code.
On the topic of REFCOUNT, one design goal of the upstream refcount_t API was to carefully audit all uses of reference counters and manually convert previous atomic_t users to the new refcount_t API. The idea was that the reduction in coverage would be offset by the hope that no false positives would be introduced (which in our experience could sometimes take months to exhibit themselves). Unfortunately, it doesn't appear yet that this manual approach has produced a better result than produced by our existing multi-year effort of marking uses as atomic_unchecked_t and recent work in the past few years of using GCC plugins to automatically identify non-reference counter uses of atomic_t. A recent fix for an issue evaded both our static analysis as well as upstream's manual auditing. Manual conversion of atomic_t uses to refcount_t isn't without its own unique perils though, as evidenced by this use-after-free vulnerability introduced by the upstream conversion.
FORTIFY_SOURCE support was added to various functions in the kernel in 4.13. The history of FORTIFY_SOURCE however goes back beyond what was mentioned in Kees' post. The first person I'm aware of to apply FORTIFY_SOURCE to the kernel was Arjan van de Ven back in 2005. My patch in 2009 had expanded on Arjan's work and covered more functions. Still, despite this extra work, why was it never merged in grsecurity? The reason was that I inspected the cases where __builtin_object_size() was able to determine the size of a particular object, even with extensive additions of __alloc_size attributes. I was disappointed to find only a 30% coverage of functions I intended to apply the protection to. Worse yet, based on an inspection of many of the locations it did protect, they were trivially correct cases or ones that would never be involved in exploitation. Later in 2010, Jon Oberheide reproduced my research and came to the same result.
Though Daniel Micay's work for 4.13 was novel to add bounds checks as well on the read side, to my knowledge no research has yet been published showing the percentage of cases where these checks are actually performed. Despite Kees' post providing a laundry list of information leaks caught by the FORTIFY_SOURCE addition, inspection of these fixes reveal that the majority of these are not actual security issues; some are arguably not even leaks at all, but rather fixing false positives caused by the FORTIFY_SOURCE checks. We're exploring GCC plugin-based approaches to bounds checks that will offer much higher coverage than FORTIFY_SOURCE and will provide updates in future posts when we have more to report.
The performance impact of SSP in the kernel is still not justified by its benefit, with the recent Bluetooth vulnerability perhaps being the first where it was effective (absent some other information leaking vulnerability) in a long while. Nevertheless, upstream has aimed to improve it for vulnerabilities involving string routines by modifying the stack canary to contain a NUL as its first byte. For those who enjoy brain teasers, my trivia question regarding this change remains unsolved, but answering the question will explain why we haven't accepted the change verbatim.
We are glad to see that a bug in in upstream's port of grsecurity RANDSTRUCT plugin was fixed. We had also independently modified the sem_array structure on March 26th of this year to similarly remove sem_base, but for the different purpose of dealing with an old heap spray technique by qobaiashi. The upstream modification to sem_array unfortunately doesn't fully eliminate this technique.
While an attempt was made to choose better default bases for ET_DYN binaries to help deal with Stack Clash in a way that was different from PaX's existing code, upstream developers discovered that it caused compatibility issues with Address Sanitizer, causing the change to be reverted back to the base addresses PaX uses.
Until next time,
-Brad