Live data from Hacker News

A capability-safe language would have minimized the Log4j vulnerability

justinpombrio.net

121–130 of 158 posts

Re: A capability-safe language would have minimized the Log4j vulnerability

#121
In theory, this always seems like it would be a good idea.

In practice, I think it would turn into a ball of mud because your capabilities would be viral and end up infecting all the way up the stack, similar to the way async/await works in dotnet or the IO monad does in Haskell.

Re: A capability-safe language would have minimized the Log4j vulnerability

#122

Here’s the alternate history where “Network” is passed as an argument to the constructor. The year 2006 rolls around and centralized logging is becoming pretty cool. Someone requests that log4j add support to logging to a UDP syslog server. The constructor now requires “Network” and now everyone still thinks it’s reasonable. IMO the elephant in the room is code execution of remotely loaded code. I want to be able to…

The way I put it was how come a remote process has authority to load arbitrary code into the local process?

Re: A capability-safe language would have minimized the Log4j vulnerability

#123
A fun excerpt from "Capabilities: Effects for Free"

Capability-safe languages prohibit the ambient authority [18] that is present in noncapability-safe languages. An implementation of a logger in Java, for example, does not need to be initialised with a log file capability, as it can simply import the appropriate file-access library and open the log file for appending by itself. But critically, a malicious implementation could also delete the log, read from another file, or exfiltrate logging information over the network. Other mechanisms such as sandboxing can be used to limit the damage of such malicious components, but recent work has found that Java’s sandbox (for instance) is difficult to use and therefore often misused [2, 12].

Emphasis added my own.

[1] https://www.cs.cmu.edu/~aldrich/papers/effects-icfem2018.pdf

Re: A capability-safe language would have minimized the Log4j vulnerability

#124
post #115

Earlier quoted context omitted.

Is it? I’m referring to real world coding to solve real world problems in order to get real world paychecks.

You're going to have a hard time getting a job writing E, or for that matter finding E libraries, because nobody uses E. Same story with Lobster, Clean, RScheme, Cobra, or a zillion other languages that don't have much adoption. But that is an entirely separate question from it being a cumbersome programming language, which is what the grandparent comment was alleging of all ocap languages—based on, apparently, total…

I don't disagree but we have to start somewhere. For example: formally specify [the clear parts of] HTTP 1.1 with declarative programming (which will generate proper code) and that would already be a huge jump.

My point is: at one point somebody has to contribute.

Re: A capability-safe language would have minimized the Log4j vulnerability

#126
post #117

I am working on a capability-safe language! I fully agree with this article, and the great thing about object capabilities is that they are just plain values, and require nothing special from the type system. This also means that object capabilities aren't "colored" like async/await, monads, or other effect systems.

Do you have more to share, like resources about capability-safe languages, or your ongoing work? > This also means that object capabilities aren't "colored" like async/await, monads, or other effect systems. That's interesting. How does that work? Is it by passing around a value from your main function to the functions that need it?

> Do you have more to share, like resources about capability-safe languages, or your ongoing work?

I can share an example from the main function of the self hosting Firefly compiler [1]:

    main(system: System): Unit {
        ...
        let fs = system.files()
        if(fs.exists(tempPath)) { deleteDirectory(fs, tempPath) }
        ...
    }

    deleteDirectory(fs: FileSystem, outputFile: String): Unit {
        fs.list(outputFile).each { file =>
            if(fs.isDirectory(file)) {
                deleteDirectory(fs, file)
            } else {
                fs.delete(file)
            }
        }
        fs.delete(outputFile)
    }
Main is passed `System`, which is a value with methods to access the network, the file system, etc. It passes on the `FileSystem` value to `deleteDirectory`, which only has methods to access the file system.

Since there's no other way for `deleteDirectory` to obtain capabilities than to recieve them as arguments, `deleteDirectory` only has access to the file system.

> That's interesting. How does that work? Is it by passing around a value from your main function to the functions that need it?

Exactly; such arguments can themselves be seen as "coloring", since they show up in the function signature. However, an important distinction is that you can capture capabilities in the fields of an object or in closures, and thus get rid of the coloring.

The Firefly language is quite far along - nearly feature complete, and translating itself. However, there's a lot of work left before it becomes a viable alternative to existing languages, not least in the tooling and documentation department.

[1] https://github.com/Ahnfelt/firefly-boot/tree/master/compiler

Re: A capability-safe language would have minimized the Log4j vulnerability

#127
Several good points, and so much to comment on. I will restrict myself to repeat that Java already has several mechanisms to enforce capabilities, and that this is mainly an exercise in API design.

However, the article fails to recognize that Log4j (and probably other libraries) have different capability requirements at different points in time and in code. At startup and when reloading configuration, only access to some severely restricted JNDI lookups should be allowed. Core message formatters and lookups should have minimal privileges. Appenders require access to network and filesystem APIs though!

The capability style presented by TA requires the ability to use of Dependency Injection to properly inject handles that permit access to restricted APIs. This is quite fine in the case of Log4j, which allows programmatic configuration, but it would force developers to give more cababilities than strictly required to more monolithic components!

Re: A capability-safe language would have minimized the Log4j vulnerability

#128

What you need is not a capability safe language, but rather a tool to make application jails and similar systems more accessible. Your os exists for a reason, let it handle the sandboxing for you, and not the language. Otherwise you fall into troubles later with different sandboxing vulnerabilities in different compilers. Have a codebase that compiles using deprecated features which are removed on language version 2.…

Capabilities model is not about "features" which might be deprecated, but more about "access to standard resources". Capabilities e.g. doesn't care that you are running version 3.1.73 of a certain dependency, it cares that you want to open a network connection to 123.76.34 or that you want /usr/bin/secret file.txt.

The version [of a dependency] starts to matter if it blocks upgrade to a version of the platform that would allow to control a specific new capability.

Re: A capability-safe language would have minimized the Log4j vulnerability

#129

No, it wouldn’t have, for the simple reason that no one is willing to go to the extra effort to use a capability-safe language, for the same reason we don’t all code in formally-verified languages - it’s just too much work. The claim in the article could be “The log4j vulnerability could have been prevented by hiring someone to punch any developer who tries to use JNDI in a logging library in the face” and would be e…

I don't think a well designed capability system would be so onerous as to be unworkable, people use other complex features in Rust and C++ and Haskell just fine. It's just that being capability-safe by itself is not enough to carry a niche language. Eventually these ideas will find their way into more mainstream languages, one way or another.

I disagree with your premise that a well-designed capability system is a complex feature. It's better described as an absence of certain complex features.

Re: A capability-safe language would have minimized the Log4j vulnerability

#130
post #87

Earlier quoted context omitted.

Operating systems are also written by programmers. An operating system written in a capability-safe language would not have such ambient authority problems.

Please let me re-state my objection to your assertion, in a different, and hopefully more constructive, manner. An Operating System is a program that multiplexes hardware resources and makes them safely usable by a number of applications. If the design of that system is flawed, how could a capability-safe language do anything to correct the problem? It is my assertion that the design of Linux, Windows, MacOS are all…

Yes, and in a capability-safe language it's much more difficult to implement those flawed designs. (In the same way memory safety makes a buffer overrun vulnerability much more difficult to implement)

A concrete example is the Network capability mentioned in the article. The syscall to create a new process does not need network access, so in a capability-safe language that part of the OS won't have that capability passed in, so the OS won't be able to create new processes with network access. The Network capability, if desired for this process, will need to be explicitly added later by other code, in the OS or in userspace.

Post reply on HN