Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Practically (and like is being suggested here in other comments), JNDI would probably be a separate component (maybe a separate process) with network access, and log4j would just send those user provided strings over an IPC channel, and you'd be in exactly the same place at the end of the day.


Sure, it could be, but in a capability system if the application is starting that JNDI component, granting it network access, and granting the logger access to it:

1) It's pretty dang explicit to the programmer that they're granting the logger network access, because they're the ones writing that logic.

2) Even if you've granted the logger network access, you probably haven't granted it complete access to your filesystem. Network access isn't the only sensitive thing on your system, and a logging library needs very little authority to operate (specific files/directories and its own config?). Getting code execution in the logger shouldn't be game over security-wise, because it shouldn't have that much authority to begin with.


What it would probably look like was they were granting an IPC channel to the JNDI component, just like they would for DNS or what have you. And then separately "ok, yeah, JNDI needs network access, that makes sense".

So you wouldn't see network access directly in the capability manifest for the logging component.

None of this protects you from "fuck it, load class file from random ldap server" that was apparently coded up in JNDI.


Let's not conflate network access to get the thing from LDAP and network access for the thing itself. In fact, it's exactly programming with capabilities that would keep this stuff separate, as no one would design the JNDI interface to wantonly pass all the same capabilities to the class.

Well-sandboxed arbitrary byte-code is remote code execution I am OK with!


> Let's not conflate network access to get the thing from LDAP and network access for the thing itself.

Why not? The attacker's goal was to run untrusted code on your server. They don't necessarily care if it's running in the JNDI process or the server component that's logging as the first step. It's a beachhead into a pretty trusted component, and exploits these days are long chains. I'm sure there are other components over those IPC channels that aren't expecting JNDI to be lying now which can be used to expand that beachhead.

> as no one would design the JNDI interface to wantonly pass all the same capabilities to the class.

Just as 'no one' would load random class files off of untrusted servers into a vm without the fine grained capabilities you're talking about?

> Well-sandboxed arbitrary byte-code is remote code execution I am OK with!

I agree with the spirit, but haven't found a sandbox that stayed "well-sandboxed" over time.


Excuse us true believers, but the idea is capabilities avoid the https://xkcd.com/2044/ trap by being just dynamic enough.

I would certainly agree not to trust any other sort of sandboxing. E.g. I don't trust Linux namespaces (as the linux devs themselve say you shouldn't) because the syscall interface is far too complex and subtle). But something like CloudABI or Fuschia or seL4 is dramatically narrower in scope.


I'm talking from experience here with capability systems on microkernels. Capability-based security is a tool, not a panacea. Exploit chains these days are very used to having to jump through IPC channels to components with different privileges to get everything they need.

Edit: As an aside, rather than looking towards namespaces for an attempt at the same structure, seccomp BPF is the primitive I've found that creates the closest thing to the capability system you're talking about. That way you can leave a process with only recvmsg/sendmsg on unix domain sockets, and maybe mmap for memfds shared across processes.


> Exploit chains these days are very used to having to jump through IPC channels to components with different privileges to get everything they need.

Thank you for bringing this up; it's an important point. Do you have a sense of what a practical solution might be?

One thing I can imagine is that there's a JNDI component, but to communicate with it over IPC, you need the JNDIComponent capability. This would allow a couple ways to prevent the log4j vulnerability:

1. You don't give the JNDIComponent to log4j.

2. You use capabilities inside JNDI to separate out the bits that use the network from those that don't, and only supply log4j with a JNDIComponentWithoutNetworkAccess.

This requires co-operation between capabilities in the OS and in the programming language, though, which is a big ask. Plus some foresight; much more than as described in my post.


> Well-sandboxed arbitrary byte-code is remote code execution I am OK with!

I used to be OK with that too, until Rowhammer showed that sandboxing is more fragile than one would expect. And then came Spectre...


Yeah it is scary and depressing, but I suppose I just couldn't live in this industry of those are the fatalistic last word.

Trying clean up all the accidental complexity that goes with the ambient authority, using capabilities, will free up "complexity budget" to ponder various timing attacks and whatnot. I think the problems are solvable if only we are willing to move the goal posts from our current obsession over back-compat uber alles that makes everything difficult.

As I understand it, the m1 is similarly better not because any fundamental insight, but because not worrying about various x86 accidental complexity just makes it easier to do things like deeper instruction fetching pipelines etc. (Of course TSMC just killing it doesn't hurt either.)


Ideally, in a perfect world, the capabilities would themselves be something that could travel over an IPC channel, and in fact would have to travel over an IPC channel. The whole point of pervasive capabilities is that there aren't trivial escape hatches that every programmer uses at the drop of a hat. We don't need a new capabilities-based system for that, because we already have that. That's what we all use, every day.

On the one hand, I acknowledge the general impracticality of such an approach, but on the other I'm increasingly less convinced every year that anything less will ever be secure. And I also accept the corresponding implication that if programmers never do come to accept this sort of thing, we will never have secure code.


It's not that impractical, I've seen systems setup that way with unix domain sockets where you can pass an fd along with a message. I'm trying to remember where (android?), but there's a bluetooth stack setup like this, where your manifest is registered by a trusted entity, that then you talk to over an unix domain socket to get another unix domain socket to the actual bluetooth stack on an IPC endpoint that was setup with the bluetooth stack with only your permission set.

It's just not a panacea. Even if you fracture the permissions, they still exist in many places and exploit chains are used to having to act as the same sort of distributed application as what you're suggesting to exercise those distributed rights.


> log4j would just send those user provided strings over an IPC channel

No it'd have to send the strings and a capability for network access. Which it wouldn't have unless you were specifically doing that, so it would be able to make network access.


It's JNDI, a network library namespace library sort of like DNS but using LDAP.

Going off what I've seen for DNS daemons in capability systems, the whole point is to not have a network capability on the client of the daemon at all, but only in the DNS daemon, who gets IPC channels setup by by some minter of capabilities in the TCB. That IPC layer lets you make JNDI requests, but because of the capability model is a non forgeable permission over the idea of DNS lookups both of the local cache and over the network if need be. The the DNS daemon is the only one with a network capability for a random UDP port to make requests.

So what you have in your fine grained caps is

    DNS daemon
      * IPC server port
      * UDP port

    client app
      * client port to DNS daemon
If someone coded that DNS daemon as 'you know what, new DNS record type called CAFEBABE that is an arbitrary, untrusted server name and path to load some untrusted .class file from', both the above capability system implementation wouldn't help, and we'd take the DNS daemon authors out and flog them for implementing that. If it was in the RFC we'd take the writers out and flog them too. That's the best defense I've found unfortunately.

And the big issue is that there's tons of these caps even now needed for a system, and it's hard to manage it all even when explicitly in a big table. At best it sort of looks like Terraform, at worst it looks like JCL or an autotools script. It's real easy for it to expand out of someone devops person's mental scope, where we all take potshots on the Internet for not following some hardening guide instead of other guides on a breach.


A capability-secure language would keep log4j from getting access to the IPC channel to the JNDI process, unless log4j's caller specifically passed log4j the JNDI IPC channel capability.




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

Search: