I hope no one tries to use the rust "safety" guarantees for security guards. They are designed to prevent bugs not intentional abuse. If perfect without bugs they theoretically might be usable for security guards, but it's not where priorities lies when it comes to bug fixes and design. And people mistaking rust safety + no unsafe lint for "security against evil code" could be long term quite an issue for rust in var…
I agree -- relying on Safe Rust's "guarantees" for security purposes is very likely to be problematic. To make the reasons concrete: for the last 4 years rustc has had a bug that allows writing transmute (arbitrary type conversion) without the use of unsafe: https://zyedidia.github.io/blog/posts/5-safe-transmute/ . This is one of the 77 current open unsoundness bugs on the Rust issue tracker. To make this tenable you…
eBPF Verification Is Untenable
31–40 of 116 posts
Re: eBPF Verification Is Untenable
#32Hm. Doesn’t look viable to me. I’m not against language-based security, proof-carrying code, and all that, but I have less than perfect confidence that the Rust compiler currently is or will soon be sound enough to be secure against actively hostile code—AFAIU the language designers haven’t even written down their core calculus, let alone proven it sound. Putting the entirety of the Rust compiler (including, at least…
OK then! Back to C it is I guess. More seriously, we're talking about the Linux kernel here: it's written in C, and there's some momentum to write new code in Rust. You're asking for the moon, but you may have to settle for a picture of it.
But what TFA talks about amounts to replacing the eBPF verifier with (a blessed userspace version of) the Rust typechecker—dragging the rest of the compiler along for the ride—and that just feels like a downgrade in almost every respect. It’s humongous, it requires strange contortions due to not fitting in the kernel, it implements a comparatively very complicated spec, that spec is not written down, etc. The eBPF machine is not perfect, especially (as the authors point out) when you account for the “helpers“, but it mostly avoids these downsides. It’s not the moon—it’s already there.
Re: eBPF Verification Is Untenable
#33I haven't been following the eBPF situation for a while, but... how did it come to this? I thought the point of BPF (sans 'e' anyway) was that it was pretty much secure by construction, or at minimum was simple enough to fully verify in polynomial time. So these eBPF vulnerabilities sound like a completely invented, unnecessary class of problems.
Re: eBPF Verification Is Untenable
#34Hm. Doesn’t look viable to me. I’m not against language-based security, proof-carrying code, and all that, but I have less than perfect confidence that the Rust compiler currently is or will soon be sound enough to be secure against actively hostile code—AFAIU the language designers haven’t even written down their core calculus, let alone proven it sound. Putting the entirety of the Rust compiler (including, at least…
OK then! Back to C it is I guess. More seriously, we're talking about the Linux kernel here: it's written in C, and there's some momentum to write new code in Rust. You're asking for the moon, but you may have to settle for a picture of it.
Re: eBPF Verification Is Untenable
#35Rustc supports eBPF bytecode as a target, and aya-rs avoids using clang/llvm. So you can use rust to write eBPF code in both user and kernel space.
This is a different beast from the usual rust though - lots of `unsafe`s.
Re: eBPF Verification Is Untenable
#36This is weird. 1. Instead of having the kernel verify the program about to be installed at installation time, they rely on a trusted compiler and having the kernel perform signature validation. This means that the kernel is relying on a userspace component to enforce kernel-level safety guarantees, adds another level of coupling (via key infrastructure) between the kernel and a particular version of the Rust compiler…
> 1. Instead of having the kernel verify the program about to be installed at installation time, they rely on a trusted compiler and having the kernel perform signature validation. This means that the kernel is relying on a userspace component to enforce kernel-level safety guarantees, adds another level of coupling (via key infrastructure) between the kernel and a particular version of the Rust compiler, and if some…
But none of that is intended or able to check the module (resp. driver) is not gimmeroot.ko (resp. gimmesystem.dll)—that’s left to humans inspecting the source (resp. thoughts and prayers[1]). On the other hand, the eBPF VM absolutely is intended to be able to load anything any unprivileged user throws at it and emerge unscathed.
It’s not precisely essential that a kernel have this capability, but if one is to have it, restricting the allowable code to a predetermined vendor-approved set defeats most of the point. (The authors propose that a userspace compiler running on the user’s computer be allowed to extend it, as I understood them.)
[1] https://www.zdnet.com/article/these-hackers-used-microsoft-s...
Re: eBPF Verification Is Untenable
#37Re: eBPF Verification Is Untenable
#38in security insensitive scenarios, they are both interesting tech.
Re: eBPF Verification Is Untenable
#39Earlier quoted context omitted.
Your point 1 is the elephant herd in the room. If I were a paranoid person, I would think it’s by design - build in a way to compromise a system retroactively.
That makes no sense
Re: eBPF Verification Is Untenable
#40The basic idea is simple. You have the verifier, and the TCB. The verifier has to reject invalid programs, so the TCB does not have its integrity compromised by the program. The verifier is small, so it can be audited. That's nice -- until you back out and realize the TCB is "the entire linux kernel and everything inside of it and all of the surface area API between it and the BPF Virtual Machine" and it dawns on you that at that point the principle of "system integrity being maintained" relies very little on the verifier and actually a whole lot on Linux being functionally correct. Which is where you started at in the first place. The goal of eBPF after all isn't just to burn CPU cycles and return an integer code. It has to interact with the system. Having the TCB functionally be "every line of code we're trying to protect" is the Windows 3.1 of integrity models.
Now, this might also be OK and quantifiable to some extent. Except for the other fact that the guiding design principle in Linux is to pretty much grow without bound, without end, rewrite code left and right, and the eBPF subsystem itself has been endlessly tacking on features left and right for what -- years now?
If you take away any of these three things (flawed design basis, ridiculously large TCB, endless and boundless growth) and modify or remove one of them, the picture looks much better. Solid basis? You can maybe handle the other two if you're careful and on top of things, big hand waive. Very small TCB? Great, you can put significantly more trust in the verifier, freeing you from the need to worry about every line of code. No endless growth? Then you have a target you can monitor and maybe improve on e.g. reduce trends downward over time. But the combination of all three of these things means that the end result is "greater than the sum of the parts" so to speak and it will always be a matter of pushing the boulder up the hill every day, all so it can fall back down again.
That said, eBPF is really useful. I get a ton of value out of it. The verifier does allow you to have greater trust in running things in the kernel. In this case, doing something is quite literally 1,000% better than doing nothing in this if you ask me, at least for most intents and purposes. So making it safer and more robust is worthwhile. But it was pretty easy to see this sort of stuff from a long way out, IMO.