6 ms·
The memory protection strategies this paper argues for are fine. If we can recompile legacy software to gain better protection against stack and heap exploits t
by gizmo 2y ago
The memory protection strategies this paper argues for are fine. If we can recompile legacy software to gain better protection against stack and heap exploits that's a clear win.
As the paper points out memory safety is not a great concern on phones because applications are sandboxed. And that's correct. If an application is stuck in a sandbox it doesn't matter what that process does within its own process space. Smartphones taught us what we already knew: process isolation works.
Then the paper observes that memory safety is still a significant problem on the server. But instead of pointing out the root cause -- the absence of sandboxing -- the authors argue that applications should instead be rewritten in go or rust! This is absurd. The kernel already provides strong memory protection guarantees for each process. The kernel also provides hard guarantees for access to devices and the file system. But server software doesn't take advantage of any of these guarantees. When a server process intermixes data of multiple customers and privilege levels then any tiny programming mistake (regardless of memory safety) can result in privilege escalation or catastrophic data leaks. What use is memory safety when your go program returns the wrong user's data because of an off-by-one error? You don't need a root exploit if your process already has "root access" to the database server.
If we want to be serious about writing secure software on the server we have to start taking advantage of the process isolation the kernel provides. The kernel can enforce that a web request from user A cannot return data from user B because the process simply cannot open any files that belong to the wrong user. This completely eliminates all memory safety concerns. But today software on the server emulates what the kernel already does with threading, scheduling, and memory protection, except poorly and in userspace and without any hardware guarantees. Effectively all code runs as root in ring 0. And we're surprised that security continues to plague our industry?
- IshKebab 2y agoGood job sandbox escapes and local root exploits never exist!
- gizmo 2y ago1. The point is you don't need root when the unprivileged process already has access to all data. There is nothing more to be gained. 2. Good luck breaking out of your AWS instance into the hypervisor.
- VWWHFSfQ 2y ago> 2. Good luck breaking out of your AWS instance into the hypervisor. It doesn't take luck. Just skill, resources, and motivation. Like we already saw happen to the iOS "sandbox".
- IshKebab 2y ago> Good luck breaking out of your AWS instance into the hypervisor. https://www.itnews.com.au/news/xen-patches-critical-guest-privilege-escalation-bug-431869 https://www.itnews.com.au/news/xen-patches-critical-guest-pr...
- VWWHFSfQ 2y ago> memory safety is not a great concern on phones because applications are sandboxed. And that's correct. If an application is stuck in a sandbox it doesn't matter what that process does within its own process space. Smartphones taught us what we already knew: process isolation works. I thought we learned that this doesn't work after the iOS 0-click exploit chain running "sandboxed" app code in the kernel.
- jchw 2y ago> Then the paper observes that memory safety is still a significant problem on the server. But instead of pointing out the root cause -- the absence of sandboxing -- the authors argue that applications should instead be rewritten in go or rust! This is absurd. The kernel already provides strong memory protection guarantees for each process. The kernel also provides hard guarantees for access to devices and the file system. But server software doesn't take advantage of any of these guarantees. When a server process intermixes data of multiple customers and privilege levels then any tiny programming mistake (regardless of memory safety) can result in privilege escalation or catastrophic data leaks. What use is memory safety when your go program returns the wrong user's data because of an off-by-one error? You don't need a root exploit if your process already has "root access" to the database server. Yes, because servers are inherently multi-tenant, you can't inherently avoid the risks. Process isolation can't help you, even if you had the resources to fork off for every single request. If you have a database pool in your process, you can go and access other people's data. There is never going to be a case where having an RCE to a server isn't a serious issue. Also, neither process isolation nor memory safety can guarantee you don't simply return the wrong data for a given customer, so that point really neither here nor there. (I'd also argue that memory safety clearly matters on mobile platforms still anyway. Many of the exploit chains that break kernel protections still rely on exploiting memory bugs in userland first before they can climb their way up. There's also other risks to this. Getting an RCE into someone's Signal process is an extremely dangerous event for the user.)
- gizmo 2y agoDatabases also have access controls! Which developers don't use. If you have 10.000 tenants on the same server you can simply have 10.000 database users. And that simple precaution will provide nearly perfect protection against cross-tenant data leaks.
- jchw 2y agoThe database was merely an example, there are other shared resources that are going to run into the same problem, like caches. Still, it's weird to imply that database users are meant to map to application users without any kind of justification other than "you can do it" but OK, let's assume that we can. Let's consider Postgres, which will have absolutely no problem creating 10,000 users (not sure about 100,000 or 1,000,000, but we can put that aside anyhow.) You basically have two potential options here: - The most logical option is to continue to use database pooling as you currently do, and authenticate as a single user. Then, when handling a user request, you can impersonate a specific database user. Only problem is, if you do this, the protection you get is entirely discretionary: the connection is still absolutely authenticated to a user that can do more, and all you have to do is "reset role" and go on your way. So you can do this, but it doesn't help you with server exploits. - The other way to handle this is by having each request get a separate database connection which is actually authenticated to a specific user. That will work and provide the database level guarantees. However, for obvious reasons, you definitely can't share a global database pool with this approach. That's a problem, because each Postgres connection will cost 5-10 MiB or so. If you had 10,000 active users, you would spend 50-100 GiB on just per-connection resources on your database server box. This solution scales horribly even when the scale isn't that crazy. And this is all assuming you can actually get the guarantees you need just using the database layer. To that I say, good luck. You'll basically need to do most of your logic in the database instead of the application layer and make use of features like row-level security. You can do this, but it's an extremely limiting architecture, not the least of which because databases are hard to scale except vertically. If you run into any scenario where you outgrow a single database cluster, everything here goes out the window. Needless to say, nobody does this, and they're totally right. Having a database assist in things like authorization and visibility is not a terrible idea or anything, but all of this taken together is just not very persuasive. And besides. Postgres itself, along with basically all of the other major databases, are also not necessarily memory-safe. Having external parties have access to your database connection pretty much puts you back at square one for defenses against potential unknown memory safety bugs, making this entire exercise a bit pointless...
- deepsun 2y ago> doesn't matter what that process does within its own process space Re. phones -- you assume that a process hacks another process. But a there might be vulnerability within the process itself, corrupting its own memory. Sandboxing doesn't help.
- gizmo 2y agoWhat matters is that a random app cannot access sensitive data like your passwords, sessions, email. On iOS you can run anything from the app store and it's fine. On Windows any .exe you run can cause havoc.
- pornel 2y agoThe kernel knows about system-local users, but not the remote ones. Servers may need to access data of multiple users at once, so it's not as simple as some setuid+chroot CGI for every cookie received. Kernels like Linux are not designed for that. Maybe it would be more feasible with some capability-based kernel, but you'd inherently have a lot of logic around user accounts, privileges, and queries. You end up involving the kernel in what is row-level database security. That adds a lot of complexity to the kernel, which also makes the isolation itself have more of the attack surface. OTOH you can write your logic in a memory-safe language today. The VM/runtime/guaranteed-safe-subset is your "kernel" that protects the process from getting hijacked — an off-by-one error can't cause arbitrary code execution. The VM/runtime itself can still have vulnerabilities, but that just becomes analogous to kernel vulnerabilities.
- MisterTea 2y ago> That adds a lot of complexity to the kernel, which also makes the isolation itself have more of the attack surface. Not if you remove auth from the kernel: https://doc.cat-v.org/plan_9/4th_edition/papers/auth https://doc.cat-v.org/plan_9/4th_edition/papers/auth The Plan 9 kernel is very small and portable which demonstrates that you don't need complexity to do distributed auth properly. The current OS hegemony is incredibly dated design wise because their kernels were all designed to run on a single machine. > OTOH you can write your logic in a memory-safe language today. Memory safety is not security.
- pornel 2y ago> Not if you remove auth from the kernel The factoctum looks very much like a microservice or a database with stored procedures handling access control, but of course plan9 makes it a file system instead of some RPC. It's a sensible design, but if IPC is the solution, then you don't even need plan9 for it. > Memory safety is not security. I didn't say it was. However, it is an isolation barrier for the memory-safe code. It's roughly equivalent to process isolation, but in userland. Instead of an MMU you have bounds checks in software. Kernels implement process isolation cheaply with the help of hardware, but that isn't the only way to achieve the same effect. It can be emulated in software. When the code is memory safe, it can't be made to execute arbitrary logic that isn't in the program's code. If the program attempts some out-of-bounds access, it will be caught with userland checks instead of a page fault, but in either case it won't end up with an illegal memory access.