Ready to give LWN a try?With a subscription to LWN, you can stay current with what is happening in the Linux and free-software community and take advantage of subscriber-only site features. We are pleased to offer you a free trial subscription , no credit card required, so that you can see for yourself. Please, join us!
February 22, 2024
Exploits of the kernel (as with any other program) often rely on jumping into specific code in unexpected ways. Numerous techniques have been developed to prevent this from happening; control-flow integrity mechanisms, for example, exist to prevent execution from being diverted from the intended paths. Other techniques, though, try to make it difficult for an attacker to know where to redirect the control flow to, even if they find a bug that would allow that sort of compromise. KASLR is one of those techniques, built on the observation that, if an attacker does not know where the kernel has been placed in its address space, they cannot redirect control flow to a known location.
The idea behind KASLR is simple enough: at boot time, the actual location for the kernel in memory is chosen randomly. The offset chosen for each boot is different, so an attacker does not know, at the outset, where the kernel lives on any given target machine. If the kernel takes pains not to tell the attacker about its location, it creates an added barrier to successfully exploiting any vulnerability that might exist.
KASLR was first added to the kernel (for the x86 architecture) during the 3.14 development cycle in 2013. Randomizing the kernel's layout, though, has turned out to be the easy part of the job; the harder part is preventing the kernel from leaking information about its location and making the whole effort useless. There was, for example, a lot of kernel code that would happily encode kernel pointer values in printk() calls. After a fair amount of work, that problem was mostly resolved by fixing kernel code to use special formatting directives for pointers and refusing to output actual pointer values to the log unless kptr_restrict is set accordingly. Various other /proc and sysfs files were also redacted as needed. Over time, learning about the kernel's location on any given system has become harder; whether it is hard enough to effectively slow down a capable attacker is still a matter of dispute.
The problem is that there are a lot of information channels between the
kernel and user space, and any one of them might turn out to be leaking
information that reveals the kernel's location. Consider, for example, the
relatively obscure sysfs file /sys/kernel/notes. This file is documented
rather tersely as containing "the binary representation of the running
vmlinux's .notes section
". That section, part of the ELF file
containing the kernel image, contains useful information about the
image itself; any kernel code can add data to this section using the ELFNOTE()
macro. Anything placed there can be read from
/sys/kernel/notes, albeit in a binary format that goes rather
against the usual "one value per file" sysfs rule.
The most common use for this file is to store a version of the kernel's version number, but there is at least one other. Guixiong Wei recently noticed that this file contained potentially sensitive information, including the location of the startup_xen symbol; that information is enough for an attacker to defeat KASLR. That is particularly problematic because this file is world-readable, so that information is made available to an unprivileged attacker. Wei posted a patch restricting readability to the root account, closing the hole somewhat. As of this writing, that patch has not found its way to the mainline, though that can be expected to happen in the near future.
Kees Cook, who got much of the KASLR work into the kernel (built on work by others that had been underway for a while), confirmed that the result was a KASLR exposure that had been in place since 2007, long before KASLR itself was added. He welcomed the permissions change, but also asked whether addresses in /sys/kernel/notes needed boot-time relocation at all; the answer from Xen developer Jürgen Groß was that Xen, at least, does not need that relocation to happen. In other words, the address that appears in /sys/kernel/notes does not need to be adjusted to reflect the randomized offset chosen at boot time. So we may see further changes to this sysfs file in the future, though it is always hard to know that such changes can be made without breaking some user-space program somewhere.
As this episode suggests, finding kernel code that leaks addresses to user space is a bit of a game of whack-a-mole, except in this case one of the moles has managed to remain standing for 11 years after its presence was made unwelcome. There is a tool that is meant to help in the detection of moles in need of whacking called leaking_addresses.pl; it looks at the system log and walks through /proc and /sys in search of kernel addresses that have escaped to user space. It missed /sys/kernel/notes, though, because it's looking for addresses expressed as human-readable strings; /sys/kernel/notes is a binary file, which is rather less amenable to the grep-like approach used by this tool. Addresses encoded into ASCII are relatively easy to recognize; in binary form, instead, they just look like data.
Most data, though, does not contain a value corresponding to the address of a kernel symbol. To find the exceptions (and catch addresses leaked in binary form), Cook has posted a patch to leaking_addresses.pl. It can read a file of kernel symbols, such as /proc/kallsyms, and look to see if the the addresses associated with those symbols appear in a binary file like /sys/kernel/notes. With this change, leaking_addresses.pl would have found this longstanding kernel-address disclosure; it should help to prevent others from being introduced in the future as well.
These changes will keep /sys/kernel/notes from wrecking KASLR on
systems going forward. It seems almost certain that there are other moles
in need of whacking, though. For most of the kernel's history, developers
had no particular reason to conceal internal addresses; even now,
preserving KASLR is not one of the top concerns for most developers. KASLR
is a useful defense when combined with other techniques but, in a world
where any developer in an inattentive moment can compromise it, KASLR
cannot stand alone.
| Index entries for this article | |
|---|---|
| Kernel | Security/Address-space layout randomization |
| Security | Linux kernel/Address-space layout randomization |
The LWN site is currently under high scraper load, so comment display has been suppressed for anonymous users. If you are a human, you may read the comments by clicking the button below:
Note: you can avoid this step in the future by logging into your LWN account.