Unexporting kallsyms_lookup_name()
Did you know...?One of the basic rules of kernel-module development is that modules can only access symbols (functions and data structures) that have been explicitly exported. Even then, many symbols are restricted so that only modules with a GPL-compatible license can access them. It turns out, though, that there is a readily available workaround that makes it easy for a module to access any symbol it wants. That workaround seems likely to be removed soon despite some possible inconvenience for some out-of-tree users; the reason why that is happening turns out to be relatively interesting.LWN.net is a subscriber-supported publication; we rely on subscribers to keep the entire operation going. Please help out by buying a subscription and keeping LWN on the net.
The backdoor in question is kallsyms_lookup_name(), which will return the address associated with any symbol in the kernel's symbol table. Modular code that wants to access a symbol ordinarily denied to it can use kallsyms_lookup_name() to get the address of its target, then dereference it in the usual ways. This function itself is exported with the GPL-only restriction, which theoretically limits its use to free software. But if a proprietary module somewhere were to falsely claim a free license to get at GPL-only symbols, it would not be the first time.
Will Deacon has posted a patch series that removes the export for kallsyms_lookup_name() (and kallsyms_on_each_symbol(), which is also open to abuse). There were some immediate positive responses; few developers are favorably inclined toward module authors trying to get around the export system, after all. There were, however, a couple of concerns expressed.
One of those is that there is, it seems, a class of out-of-tree users of
kallsyms_lookup_name() that is generally considered to be
legitimate: live-patching systems for the kernel. Irritatingly, kernel
bugs often
stubbornly refuse to restrict themselves to exported functions, so a live
patch must be able to locate (and patch out) any function in the kernel;
kallsyms_lookup_name() is a convenient way to do that. After some
discussion Joe Lawrence let
it be known that the kpatch system has all of
its needed infrastructure
in the mainline kernel, and so has no further need for
kallsyms_lookup_name(). The Ksplice system, though, evidently
still uses it. As Miroslav Benes observed,
though: "no one cares about ksplice in upstream now
". So it
would appear that live patching will not be an obstacle to the merging of
this patch.
A different sort of concern was raised by Masami Hiramatsu, who noted that there are a number of other ways to find the address associated with a kernel symbol. User space could place some kprobes to extract that information, or a kernel module could, if time and CPU use is not a concern, use snprintf() with the "%pF" format (which prints the function associated with a given address) to search for the address of interest. He worried that the change would make life harder for casual developers while not really getting in the way of anybody who is determined to abuse the module mechanism.
In response, Deacon posted an interesting message about what is driving this particular change. Kernel developers are happy to make changes just to make life difficult for developers they see as abusing the system, but that is not quite what is happening here. Instead, it is addressing a support issue at Google.
Back in 2018, LWN reported on work being done to bring the Android kernel closer to the mainline. One of the steps in that direction is moving the kernel itself into the Android generic system image (GSI), an Android build that must boot and run on a device for that device to be considered compliant with the Android requirements. Putting the kernel into the GSI means that hardware vendors can no longer modify it; they will be limited to what they can do by adding kernel modules to the GSI.
Restricting vendors to supplying kernel modules greatly limits the kind of
changes they can make; there will be no more Android devices that replace
the CPU scheduler with some vendor's special version, for example. But
that only holds
if modules are restricted to the exported-symbol interface; if they start
to reach into arbitrary parts of the kernel, all bets are off. Deacon
doesn't say so, but it seems clear that some vendors are, at a minimum,
thinking about doing exactly that. The business-friendly explanation for
removing this capability is: "Monitoring and managing the ABI surface is not feasible
if it effectively includes all data and functions via
kallsyms_lookup_name()
".
After seeing this explanation, Hiramatsu agreed that the patch makes sense and offered a Reviewed-by tag. So this concern, too, seems unlikely to prevent this patch set from being merged.
It's worth repeating that discouraging module developers from bypassing the
export mechanism is generally seen as more than sufficient motivation to
merge a change like this. But it is also interesting to see a large
company supporting that kind of change as well. By more closely tying the
Android kernel to the mainline, Google would appear to be better aligning
its own interests with the long-term interests of the development community
— on this point, at least. That, hopefully, will lead to better kernels on
our devices that also happen to be a lot closer to mainline kernels.
Index entries for this article | |
---|---|
Kernel | Modules/Exported symbols |
Posted Feb 29, 2020 20:21 UTC (Sat)
by ncm (guest, #165)
[Link] (9 responses)
(A certain alternative pronunciation of its name perhaps telegraphs its purpose.)
We may be heartened by the previously demonstrated inability of large organizations to create a viable new kernel from scratch--OS/360 excepted.
Posted Feb 29, 2020 21:12 UTC (Sat)
by mfuzzey (subscriber, #57966)
[Link]
Maybe Google does want to move Android to Fuchsia but they don't need to change anything in Linux to do that.
Posted Feb 29, 2020 22:00 UTC (Sat)
by Lionel_Debroux (subscriber, #30014)
[Link]
Posted Mar 1, 2020 17:58 UTC (Sun)
by NYKevin (subscriber, #129325)
[Link] (5 responses)
Posted Mar 1, 2020 18:17 UTC (Sun)
by rahulsundaram (subscriber, #21946)
[Link]
Upstream is at the moment. Given that it is permissive licensed and mobile vendors like to slap on a ton of patches for differentiation, how it will be distributed in practice is murky and the outlook isn't great given the track record even with current Android
Posted Mar 1, 2020 20:39 UTC (Sun)
by stephen.pollei (subscriber, #125364)
[Link] (2 responses)
Posted Jun 22, 2021 17:45 UTC (Tue)
by scientes (guest, #83068)
[Link]
Posted Mar 9, 2020 14:57 UTC (Mon)
by scientes (guest, #83068)
[Link]
FTFY
Posted Mar 2, 2020 11:26 UTC (Mon)
by Sesse (subscriber, #53779)
[Link] (1 responses)
Posted Mar 3, 2020 2:52 UTC (Tue)
by pabs (subscriber, #43278)
[Link]
https://wiki.gentoo.org/wiki/Elivepatch
There is also another one (KernelCare I think) that IIRC has its own non-mainline patching mechanism.
Posted Dec 2, 2020 18:44 UTC (Wed)
by zizzu (guest, #143434)
[Link]
Posted Sep 2, 2021 18:33 UTC (Thu)
by VojtaK (guest, #154079)
[Link]
First I downloaded a fresh new package amdgpu-pro-21.10-1247438-ubuntu-20.04 from AMD. Well its not for Debian, but Debian is brand new so I was thinking I could run it there. Not really easy!
First they decided to support ubuntu-20.04 with kernel 5.8 and Debian 11 is shipped with 5.10. When my attempts to build their amdgpu module failed multiple times, I decided to downgrade and compile 5.9x, 5.8x kernels on my own.
I also would like to mention that 5.7x kernel was the last one, where "mmap_sem" was not called "mmap_lock" in mm_types.h https://lore.kernel.org/linux-mm/20200422001422.232330-11...
So I had to change inside amdgpu-dkms_5.9.20.104-1247438_all.deb find . -type f | xargs sed -i "s/mmap_sem/mmap_lock/g"
And to be able to retain the distribution kernel I also needed to add BUILD_EXCLUSIVE_KERNEL="^(5\.[0-9]\.)" to usr/src/amdgpu-5.9.20.104-1247438/dkms.conf
Well everything installed, module compiled, but it was not working. In my dmesg there was cryptic message
Let's have a look to that source
memset(&kp, 0, sizeof(kp));
This is a code from AMD! Exploiting another way to get to that function. Maybe you shall remove it altogether because the only thing you achieved that a big player who bundles his closed source firmware into the kernel use this exploit and I spent a 48 hours of my work figuring out that it does not work in my use case producing that BUG!
So finally I am forced either to downgrade to <3.7 kernel or to add EXPORT_SYMBOL_GPL(kallsyms_lookup_name); to kallsyms.c and hope that they parse well that macro to define HAVE_KALLSYMS_LOOKUP_NAME to have it running in 3.9 kernel. Because in 3.10 its broken also from another reason.
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
Fuchsia is open source.
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
The fuchsia license looks a lot like the 3-Clause BSD License. For some reason, reminds me of BSD - The Dark Horse of Open Source.
fuchsia license looks like BSD 3-clause
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
Unexporting kallsyms_lookup_name()
kernel BUG at /var/lib/dkms/amdgpu/5.9.20.104-1247438/build/amd/amdkcl/kcl_common.c:44!
void amdkcl_symbol_init(void)
{
#ifndef HAVE_KALLSYMS_LOOKUP_NAME
struct kprobe kp;
int r;
kp.symbol_name = "kallsyms_lookup_name";
r = register_kprobe(&kp);
if (!r) {
_kcl_kallsyms_lookup_name = (void *)kp.addr;
unregister_kprobe(&kp);
} else {
pr_err("fail to get kallsyms_lookup_name, abort...\n");
BUG();
}
#else
_kcl_kallsyms_lookup_name = kallsyms_lookup_name;
#endif
}