Meltdown and Spectre mitigations — a February update
Variant 1
Perhaps the biggest piece of unfinished business in January was a proper response to Spectre variant 1 — the bounds-check bypass vulnerability. Variant 1 is likely to be difficult to fix at the hardware level, and so may be with us for a long time. Unfortunately, it is also difficult to address at the software level.
The seemingly final form of the patches for variant 1 has changed the interface yet again. Consider a simple code fragment that might be vulnerable to speculation that bypasses a bounds check:
if (index < ARRAY_SIZE) return array[index];
The way to protect this kind of reference to ensure that no out-of-bounds references to array occur would be:
if (index >= ARRAY_SIZE) return 0; /* Or whatever error value makes sense */ else { index = array_index_nospec(index, ARRAY_SIZE); return array[index]; }
The protective macro array_index_nospec() no longer actually accesses the array; instead, it just manipulates the index value in a way that blocks speculation. It uses the masking technique described in the mid-January article, avoiding the rather more expensive barrier operations entirely. For cases where the operation that needs to be protected is more complex than a simple array access, there is another macro called barrier_nospec() that does use a barrier to block all speculative activity. It is rather more expensive to use than array_index_nospec(), on the x86 architecture at least, but sometimes there is no alternative.
Actual uses of these new macros are relatively scarce at the moment. The get_user() function in the kernel is one area of concern, since it can be used to attempt an access to an arbitrary address in the kernel; since get_user() has the necessary bounds check to ensure that the given address points into user space, adding a call to array_index_nospec() (more correctly, an optimized assembly version of it for x86) is enough to prevent problems. The __get_user() variant, though, lacks those checks and is invoked in well over 1,000 call sites in the kernel. Protecting __get_user() requires tossing in a barrier_nospec() invocation.
Another area of concern is the system-call table, which is indexed using an integer value (the system-call number) from user space. A call to array_index_nospec() is used to prevent out-of-bounds access to that table. Protections have also been added for file-descriptor lookup, in the KVM code, and in the low-level wireless networking code. Nobody believes that all of the potentially exploitable places have been found, though.
Meanwhile, there is an arm64 patch set in
circulation with mitigations similar to the x86 patches.
It has fewer mitigations currently It doesn't repeat the
non-architecture-specific mitigations found in the x86 tree, but does add
protections to the futex()
system call that are not currently present (and maybe not needed) for x86.
Finding the remaining locations where variant-1 protection is needed is likely to require fairly advanced static-analysis tools. The work done so far has relied on the proprietary Coverity tool, and has had to contend with a high false-positive rate. Everybody involved would like to see a free tool that could do this work, but nobody is apparently working on such a thing. That is certain to slow the rate at which vulnerable code is found and increase the rate at which new vulnerabilities are introduced.
Arjan van de Ven has suggested that what really needs to happen is a centralization of many of the security checks that are currently dispersed throughout the kernel. He recommends the creation of a utility function described as:
copy_from_user_struct(*dst, *src, type, validation_function);
Where the validation_function() would be automatically generated from the UAPI headers that describe the interface to the kernel. Widespread use of a function like this would free most developers from the need to worry about Spectre variant-1 vulnerabilities; it might also improve the (not always great) state of argument validation in general.
Variant 2
Spectre variant 2 (branch prediction buffer poisoning) has been mostly mitigated by way of the "retpoline" mechanism that was merged for the 4.15 kernel release. With the GCC 7.3 release, a retpoline-capable compiler is finally available. There are, however, a number of loose ends that are slowly being dealt with.
There is still a fair amount of uncertainty around the question of when retpolines provide sufficient protection. The "indirect branch prediction barrier" (IBPB) operation provided by Intel in recent microcode updates will protect against poisoning, but its use is expensive, so there is a desire to avoid it whenever possible. There are cases, though, such as switching into and out of a virtualized guest, where IBPB is needed.
There is also the inconvenient fact that Intel released a number of microcode versions with implementations of IBPB that, to put it politely, did not function as well as users would have liked. Dealing with that last problem requires avoiding IBPB entirely on the affected microcode versions. There was some discussion over whether the kernel should blacklist known-bad versions or use a whitelist of known-good alternatives; the latter approach was somewhat driven by worries that Intel was never going to get things right. In the end, though, the blacklist approach won out, on the theory that the problems have, in the end, been fixed.
Similar concerns relate to the "indirect branch restricted speculation"
(IBRS) barrier-like operation that, by some accounts, is needed to get full
protection on Intel Skylake-generation processors. That, too, has had
issues with some microcode versions. Those too, with luck, have been
fixed; if not, David Woodhouse warned:
"then I think Mr Shouty is going to come for another visit.
"
There is still some resistance to using IBRS at all, though. It also is an expensive operation, and nobody has demonstrated an exploit on Skylake processors when it is not used. Meanwhile, Ingo Molnar has proposed a different approach: use the ftrace machinery to keep track of the number of entries in the return-stack buffer (RSB) and force the use of a retpoline when it gets too deep. It is not yet clear that this idea can be implemented in a practical way; Thomas Gleixner has played with it but he ran into some complications and set it aside for now.
One concern about variant 2 is that it might lend itself to attacks by one user-space process (or thread) against another. JavaScript code running in a browser appears to be the most likely vector for such an attack, but it's not the only one. This patch, for example, is an attempt to protect high-value processes by issuing an IBPB barrier prior to switching into a process that has marked itself as being non-dumpable. The idea is to provide some protection for programs like GnuPG while avoiding the overhead of IBPB on every context switch.
Other odds and ends
Protection against Meltdown ("variant 3") was mostly in place when the embargo fell in January; its basic form has not changed much since then. There are numerous bugs to fix, of course, and that work has been ongoing. The arm64 architecture gained kernel page-table isolation during the 4.16 merge window. There has also been some work on the x86 side to avoid using kernel page-table isolation on systems that do not need it — AMD processors and ancient Intel processors, for example. The whitelist of safe processors is slowly growing.
Systems with Meltdown and Spectre mitigations also have a new sysfs directory (/sys/devices/system/cpu/vulnerabilities) listing known CPU vulnerabilities and their mitigation status. On your editor's laptop, they currently read:
meltdown: Mitigation: PTI spectre_v1: Vulnerable spectre_v2: Mitigation: Full generic retpoline
There have been some concerns that these files, which are world-readable, provide useful information to attackers and should be restricted. On the other hand, Alan Cox responded, that this information is already readily available and it can be useful to utilities like just-in-time compilers, which might change their output when certain vulnerabilities are present. As of this writing, no patches changing the protections on those files have been merged.
Other than that, though, everything
described here has been merged for 4.16 and is quickly headed toward the
stable kernel updates as well. There are a number of smaller issues not
described here that were also addressed for 4.16; see this pull request for the full list. Clearly,
even if things have slowed a bit to allow the developers involved to get
some sleep, a lot is still happening to deal with the fallout from Meltdown
and Spectre.
Index entries for this article | |
---|---|
Kernel | Security/Meltdown and Spectre |
Security | Linux kernel |
Security | Meltdown and Spectre |
Posted Feb 6, 2018 0:04 UTC (Tue)
by Frogging101 (guest, #113180)
[Link]
I laughed. Thanks for that :D
Posted Feb 6, 2018 1:03 UTC (Tue)
by karkhaz (subscriber, #99844)
[Link] (4 responses)
1. It seems to me that the Clang Static Analyzer would be an excellent tool to do this, if only it could parse the kernel. There has been excellent work on compiling the kernel with Clang/LLVM (as described in a talk at the last LLVM Developers' Meeting [1] and here on LWN [2]), but I'm not aware of efforts to do analysis on the kernel (would love to hear if anybody is working on this!).
In particular, the Clang Static Analyzer preserves the AST of the language, whereas many comparably powerful tools first convert the program into some lower-level intermediate representation. The IR is usually better for implementing proper static analyses, but for ``pattern-matching'' cases like this one, you really do want the original AST.
I'm not sure if GCC has softened their position on allowing the AST to be exported to help static analysis tools, text editor autocompletion, and other use cases; but if they have not, then here is one more argument that they really should. We're compiling the kernel with GCC, and it would be really excellent to dump the kernel's AST for cases like this.
2. I contribute to a static analyzer which does convert program code into IR. However, the particular use case in the article does seem to be fairly easy to recover from IR. Is it really just: "flag the locations where the access of an array is guarded by a bounds check for that access"? I would be interested in exactly what pattern is needed (the article does not elaborate), and what trouble Coverity has had (Coverity isn't very good, but this seems quite simple, so I wonder about the nature of the false positives they're reporting and whether I could do any better). Does anybody have pointers to discussion about this or other relevant information?
[1] https://www.youtube.com/watch?v=6l4DtR5exwo
Posted Feb 6, 2018 15:30 UTC (Tue)
by Koral (guest, #115236)
[Link]
Posted Feb 6, 2018 18:57 UTC (Tue)
by amaranth (subscriber, #57456)
[Link]
Posted Feb 9, 2018 9:19 UTC (Fri)
by jezuch (subscriber, #52988)
[Link]
Posted Feb 16, 2018 11:53 UTC (Fri)
by oldtomas (guest, #72579)
[Link]
It has, since a while ago (version 4.5, somewhere 2011):
People are using that for static analysis:
And for those who want to play comfortably, there's a kind of "meta-plugin" which you can program in some kind of Lisp (and which ironically is named MELT):
Posted Feb 6, 2018 1:38 UTC (Tue)
by jcm (subscriber, #18262)
[Link]
Posted Feb 6, 2018 1:38 UTC (Tue)
by roc (subscriber, #30627)
[Link] (1 responses)
I guess in common cases the array is either statically known to be non-empty or the data pointer for an empty array would be null, but it may be a potential footgun. I can't find any discussion of this.
Posted Feb 6, 2018 4:02 UTC (Tue)
by willy (subscriber, #9762)
[Link]
Posted Feb 6, 2018 7:04 UTC (Tue)
by mjthayer (guest, #39183)
[Link] (6 responses)
Posted Feb 6, 2018 14:16 UTC (Tue)
by corbet (editor, #1)
[Link] (5 responses)
Posted Feb 6, 2018 16:07 UTC (Tue)
by Paf (subscriber, #91811)
[Link] (4 responses)
That seems to run counter to something I read - in one of the many Meltdown/Spectre articles here - suggesting that KPTI is a "big hammer" that will deal with many potential speculative execution derived security holes. This seems to imply that the speaker (I believe it was a kernel developer) thinks it's likely KPTI will be needed in the future, even once Meltdown is fixed (as of course it should be in future hardware).
Any thoughts?
Posted Feb 6, 2018 16:13 UTC (Tue)
by corbet (editor, #1)
[Link] (3 responses)
Posted Feb 6, 2018 16:53 UTC (Tue)
by corsac (subscriber, #49696)
[Link] (2 responses)
And past processors without SMEP are unlikely to have PCID, so the cost of KPTI is huge there.
Posted Feb 7, 2018 15:19 UTC (Wed)
by MarcB (subscriber, #101804)
[Link] (1 responses)
I am wondering, if it would be possible to lower the cost significantly. There are architectures - like SPARC - where separate address spaces are mandatory, after all. Did they accept the performance penalty or have they put thought - and silicone - into optimizing this? (Likely: both).
From a layman's view, separate address spaces seem like the "cleaner" solution.
Posted Feb 7, 2018 15:21 UTC (Wed)
by MarcB (subscriber, #101804)
[Link]
Posted Feb 19, 2018 20:26 UTC (Mon)
by garloff (subscriber, #319)
[Link]
Good one, David
Meltdown and Spectre mitigations — a February update
[2] https://lwn.net/Articles/734071/
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
https://old.lwn.net/Articles/457543/
https://old.lwn.net/Articles/370717/
Grsecurity is actually using that in the Linux kernel context:
https://old.lwn.net/Articles/691102/
http://gcc-melt.org/
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
I suppose there might be a danger if you have struct { int count; void *entries[]; } and kmalloc four bytes to store the int ...
Meltdown and Spectre mitigations — a February update
I am not aware of such work. The focus is still very much on dealing with corner cases and ensuring that everybody is protected. In truth, I'd be surprised to see work on expanding the amount of the kernel exposed when running in user mode. The gain would be small (I believe), the security risks would be real, and any benefits would be fleeting since future processors will not, one hopes, have this vulnerability in the first place.
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
KPTI does have the advantage of providing SMEP emulation for free on x86, so that might be a reason to keep it around. I'd still be surprised to see anybody working to move kernel-space memory back into the user-space page tables, though. The ratio of risk to performance gain seems way too high.
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
Meltdown and Spectre mitigations — a February update
https://imagefactory.otc.t-systems.com/Blog-Review/SpecEx...
The difference b/w IBRS and Retpolines is HUGE.