Hacker News new | past | comments | ask | show | jobs | submit login
Notes from the Intelpocalypse (lwn.net)
288 points by discreditable on Jan 4, 2018 | hide | past | favorite | 25 comments



For the owners of vast numbers of systems that cannot be updated, the consequences will be worse: they will remain vulnerable to a set of vulnerabilities with known exploits.

Fortunately, chances are that those systems are stable, isolated environments which won't be running any new and untrusted code either. That means they will just remain vulnerable in the same way that everyone knows their houses can always be broken into by a determined-enough attacker; to try to achieve 100% security, to close all the side-channels, may be impossible and have plenty of other negative effects.

Sometimes, just knowing is enough because it leads to more informed risk analysis and decisions. That saying about "known knowns, known unknowns, and unknown unknowns" comes to mind.


But if a system had known exploits that let you execute arbitrary code in user space, now there's a path to do way worse damage.

It's like it's a multiplicative effect.


I wonder if it would be possible to peg the kernel to one processor core (or a subset of the cores) and userspace to the remainder of the cores. As I understand it, all of the memory caches that are being exploited to leak information are per-core, so that would give a blanket guard against kernel->userspace leaks via cache timing.


Yes this is easy to do with cpu shields. But it means a system call might need to go onto another board... this would work only for the apps that ran mainly in user space and wouldn’t be very impacted anyway...


As memory serves that was exactly how the hypervisor on the PS3 Cell setup worked.


Syscall performance would suffer but otherwise this could work.


This is the first time I've seen this suggestion; it is something that could be done relatively easily for systems that otherwise have no updates/mitigations.

If performance is better some variant of this (auto-scaling dedicated cores) may even become the default solution rather than all the other workarounds! Bare metal hypervisors should get their own core(s) too.

Is anyone already doing this? (Qubes, etc.)


I remember seeing this suggestion earlier. If I'm not mistaken a commentor stated that a) this would come with a huge performance penalty b) there would be synchronization problems in multithreaded scenarios.

Don't take my word for it though, I might have understood it wrong. I imagine concurrent/parallel execution involving system calls could maybe suffer from synchronization issues if processes/threads run on different physical cores with separate caches?


This is the best succinct explanation of the vulnerabilities I have seen to date.


It is. I encourage everyone to buy a subscription to LWN (it's cheap) to support this kind of high-quality technical reporting.


LWN is always great for this.


This is a great writeup.

This article is labelled as subscriber-only content, yet I am not a subscriber and can see it fine by following this link. Is it as simple as having the right URL to get to LWN subscriber-only content, or is there some other reason it can be accessed by non-subscribers?


As subscriber you can get a link to share an article, and the posted link is one of those. Also, subscriber-only content is made public after 7 days.


I think someone that’s a subscriber has to make it available.


This post seems to indicate that there is no kernel-level workaround for variant 1, that contradicts AMD’s statement: https://www.amd.com/en/corporate/speculative-execution

LWN seems right on this one, that makes me question AMD’s honesty and knowledge of the issue.


At this point, both Intel and AMD press releases should be treated as highly, highly suspect. They are both jockeying to mitigate money loss or take advantage to make money. The truth is a secondary concern.

I'd believe CERT, project zero and the independent linux kernal devs if you want the truth.


I'm not 100% sure here, but I believe this is the specific kernel level fix that also addresses variant 1 https://lkml.org/lkml/2017/12/27/2


No KPTI does not address variant 1.


So is this article implying that only code executed on branch predictions is readable? What about normally executed code? What are the exact differences? How is normally executed code protected and how is branch predicted code not protected? Any experts care to chime in?


Not sure what you mean by normally executed code. Speculative execution happens in normal everyday conditional code such as if/switch statements, and most loops unless the compiler unrolls them.


By normal I mean code that wasn't predicted. Predicted code execution is "abnormal" because it might not contribute to the final result.

My question is why is predicted code exploitable and why is unpredicted code not exploitable? Both are executed, both have values written to registers, what's going on?

Apologies for the noobness of this question.


To use a really stupid analogy, imagine a cook in an Mafia-involved restaurant, and you're a cop (you're the adversary). There's a whiteboard in the boss' office with a number you want to know.

So you come there every day and say, "Hey, if the lights at (some address) are on, I want a cheese pizza, otherwise I want pasta.". In the beginning he sends his boy to check the light at that address, and the boy takes 20 minutes to go and check, and all that time he has to wait before he can make you the pizza. After a while the boy always says "The lights are on", so after a while the cook would still send the boy, but he would anticipate the answer "the lights are on" and he would start a making pizza. Once in a while (maybe once every 6 months) the boy would return saying the lights are off, so after 20 minutes of making the pizza, he would throw away the pizza and make you pasta.

After doing this a lot, you say, "Hey, if the lights at (some address) are on, I want a pizza with the topping from the box numbered according to the number written on your boss' whiteboard. Otherwise, I want pasta.". You know the lights will be off, but he starts making pizza with some topping you can't tell, but you notice he got a box from the fridge to put it next to his pizza-making table. The boy returns, he throws away the pizza and makes you pasta. Then you ask him, "Hey, I have another order, can I get a pizza with a topping from box 1?". If he goes to the fridge to get that box, then you know the box he picked up earlier (while he was guessing that the boy would say the lights are on) was not box 1, so you ask for another pizza with topping from box 2, etc. But if he doesn't go the fridge, you know he picked up that box previously (because he predicted the boy will tell him the lights will be on), and that's how you figure out what number is written on the boss' whiteboard: when the cook doesn't go to the fridge, it's because the box with that number is already on his table.

The whiteboard is the secret memory area, taking the box from the fridge is reading from some RAM address to cache (if it's already in cache, no need to read from RAM), and I hope the speculative execution is clear.

This analogy describes (very roughly) one of the exploits in Spectre.


Imagine some code running in some walled-off privileged space (like the kernel) that looks something like this:

  if(i < length) {
    value = data[i]
    doStuff(lookupTable[value])
  }
Let's say you can run this code with an arbitrary value for `i` (maybe it's the parameter to a system call). From a high-level view, this code is perfectly safe. If `i` is out of bounds, nothing happens. If it's in bounds, the system does something with the data at i, presumably something you're allowed to do.

But what really happens on a modern CPU when `i` is out of bounds? It's possible that the value for `length` is not available and has to be loaded from memory, which can take several hundred CPU cycles in the worst case. It's also possible that the CPU will make a guess that the `if` branch will be taken. If that happens, then execution looks something like this:

  try to compare i < length
  can't, because length is not yet available
  guess the branch will be taken, begin speculatively executing it:

  initiate the loading of length
  load data[i]
  load lookupTable[value]
  ...possibly some more stuff...

  eventually, the load of length completes
  oops, turns out i >= length
  roll back all of the speculative stuff above
Normally none of this is visible. But, the memory loads have side effects. Namely, they modify the CPU's caches. By attempting to load different locations in memory and looking at how long it takes, you can figure out which locations got cached during that speculative execution phase. Since one of those locations was determined by an out-of-bounds load of data[i], that means you can use this to figure out the data stored at an arbitrary location in this privileged space.

It requires speculative execution of a branch that ends up not being taken, because if the speculative execution was correct then you haven't gained access to anything you're not supposed to know, and if there was no speculative execution then you never load anything out of bounds.

This is simplified and probably wrong in some aspects, but that's the rough idea.


IIRC, the GCE security white paper mentioned alarms triggered by ROWHAMMER, another hardware design defect. Is it possible to reliably detect any of this year's new attacks?


See the comments. FSMark with mitigation showed a 50% performance loss. So that immediately makes me wonder about any file system intensive operation, like databases, getting hit far worse than the 5-30% hit that's been floated thus far.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: