Hi,
simeonz wrote:
Haven't posted for a while, but will indulge in blurting out for some reason.
Brendan wrote:
Any thoughts/ideas or suggested improvements appreciated!
With large pages, or with predictable physical allocator sequence, an application process could probe different page rows in RAM to determine which RAM device was used during the last API.
Also I am not sure if it is exploitable easily, but it would not be easy to hide the I/O latency that can be used to infer whether two objects that the kernel had to access from a couple of preceding API calls reside in the same storage unit, thus one of them hit the cache, or resides in a different location.
For "row select" timing in the RAM chips themselves, it'd be ruined by CPU fetching the first instruction from user-space. Doing WBINVD (invalidating all the caches) between kernel API calls would make it impossible to infer anything from preceding kernel API calls. The timing mitigation/s I mentioned should (I hope) cover the problem of using 2 kernel API functions at the same time (where one is used to infer something about the other).
simeonz wrote:
Generally, I assume you can get into trouble with all devices, as long as they or their drivers optimize requests using a shared discipline or their latency is influenced by the history of their operation. The whole problem is, as long as optimization (in CPU, a device driver, etc) correlate performance variations to privileged information, and the operation completion is delivered without deferment, and the application has access to timing information, something, no matter how small, does leak out.
For device drivers; a micro-kernel using the IOMMU (to restrict what devices can/can't access) goes a long way to prevent device drivers from using devices to use figure out what kernel did/didn't fetch into cache. Assuming that the kernel handles timers itself (e.g. and doesn't have a "HPET driver' in user-space); I'm not sure if a device driver can use a device to get better time measurements (e.g. to bypass the timing mitigation/s I mentioned).
simeonz wrote:
With micro-kernels, since synchronous APIs are less intrinsic to the programming model, if the client has some kind of completion event queue on which to block, it could be intentionally reordered. And if it has only one event, it could be randomly stalled, because performance will be probably not so strongly impacted. Also, timing data may be restricted, provided as opaque object to unprivileged processes, that could than be passed to other privileged services, such as visualization and timer APIs.
Yes.
simeonz wrote:
The question is, how to facilitate legitimate uses, such as frame timing, while prohibiting the process from inferring the encapsulated time by performing an activity with known fixed duration.
Most legitimate uses don't need nanosecond precision - e.g. frame timing can be done with timing that's many orders of magnitude worse (microsecond precision). Note that if you add too much "random jitter" to timing then an attacker will just use other approaches (e.g. a different CPU doing "lock inc [shared_counter]"), so there's no real benefit from having more than several hundred cycles of "random jitter", which means that you'd still be providing "tenths of microseconds" for legitimate uses.
simeonz wrote:
Which opens the general question, what restrictions can be made on a system service without surrendering its primary function. Vaguely reminds me of the sci-fi concept of
homomorphic encryption - information to process, but not to inspect.
Edit: After some consideration, I realized that malicious applications could try to use one core to time another, relative to a fixed activity. Also, applications could send execution traces to a server, which is responsible for timing. If the timing is inaccurate, with enough volume it will be averaged with high confidence to sufficient precision. So, I am not sure what the solution is, generally speaking. Then again, I probably drift on a tangent here, as this thread may be aiming at much more specific issues.
Edit 2: On the other hand, such deliberate actions imply hostile code being executed, not an initial exploit, so it depends on the assumptions for the software ecosystem and the progress level of the attack.
You'd still need to either make a small number of "accurate enough" measurements (which would be ruined by random delays before returning from kernel to user-space) or need to make a large number of measurements (which the kernel could hopefully detect). If you can't do either of these things then you can't gather the data to send to a remote server to analyse.
Note that network access would be disabled by default (a processes can't send/receive packets unless admin explicitly enabled network access for that executable).
simeonz wrote:
Solar wrote:
Anyway... the crux of these side-channel attacks is that the activities undergone by exploiting code cannot be distinguished from perfectly benevolent usage with any degree of certainty
I agree with this. Still, the question is can you limit the access to "types" of system resources and activities that are essential to the software's operation. Even if the restrictions are self-imposed by the application or manually imposed by security administrator.
Solar wrote:
If you do identify a process as malicious, crash and burn it.
Even if the software and all objects are trusted (and possibly come from the same original source as the OS), they are a different degree of a virus due to exploitability. The tendency is to limit the content to "trustworthy" online stores anyway, in the hope that they can blacklist malicious sources, enforce non-repudiation, "guarantee" the delivery integrity, etc. If the OS provides a sensible security model for self-restriction that the trusted application can employ (per-application, per-thread, per-process, through separation of concerns, impersonation, elevation, etc), and if this model is both efficient and effective (which seems like a pipe dream), the exploit will be ideally limited to the extent of the foothold that the attacker already has. Some loss of privacy and authenticity will be thus unavoidable by the very nature of software and the people interacting with it.
I'd say that if a process is intentionally malicious it should crash and burn; and if a process is unintentionally exploitable then it should crash and burn. For both cases maybe the system should try to inform the developer that their code was a problem, so that if it was unintentional the developer gets notified and can fix the problem sooner.
Note that I'm planning executables that are digitally signed by the developer (where the developer has to register for a key to be added to a white list), where how trusted an executable is depends on how trusted the developer is. If an executable is intentionally malicious or exploitable it would effect/decrease how much the system trusts the developer and all executables created by that developer. Ideally this would be tied into a (semi-automated) "world-wide blacklist/white list" maintained as part of the OS project (and probably involve a messy appeals process where people complain because the system stopped trusting them).
simeonz wrote:
On a side note, I doubt that this current security paradigm, which relies on object identity so much, can be applied to prospective adaptive (i.e. AI) software, which at least in some places may replace conventional hard-coded applications.
I don't think it makes any difference if a piece of software is created by a human or created by a machine - if the software is malicious or exploitable then it dies regardless of what created it.
Cheers,
Brendan