[HN Gopher] Can we get the benefits of transitive dependencies w...
       ___________________________________________________________________
        
       Can we get the benefits of transitive dependencies without
       undermining security?
        
       Author : ltratt
       Score  : 47 points
       Date   : 2025-01-28 20:28 UTC (2 hours ago)
        
 (HTM) web link (tratt.net)
 (TXT) w3m dump (tratt.net)
        
       | jerf wrote:
       | If anything is going to put capabilities into the programmer
       | ecosystem, I think it's this problem.
       | 
       | The neat thing about this particular problem is that you can do
       | some really coarse things and get some immediate benefit.
       | Capabilities in their original form, and perhaps their truest
       | form, carry down the call stack, so that code can do things like
       | "restrict everything that I call can only append to files in this
       | specific subtree" in the most sophisticated implementations. But
       | you could do something more coarse with libraries and just do
       | things like "These libraries can not access the network", and get
       | big wins on some simple assertions. If you're a library for
       | turning jpegs into their pixels, you don't need network access,
       | and with only a bit more work, you shouldn't even need filesystem
       | access (get passed in files if you need them, but no ability to
       | spontaneously create files).
       | 
       | This would not be a complete solution, or perhaps even an
       | adequate solution, but it would be a great bang-for-the-buck
       | solution, and a great way to step into that world and immediately
       | get benefits without requiring the entire world to immediately
       | rewrite everything to use granular capabilities everywhere.
        
         | marcosdumay wrote:
         | Just to say, but You are describing an effect type system. (Or,
         | to the "types are static" people, possibly a dynamic effect
         | system.)
         | 
         | Capabilities taken literally are more of a network thing (it's
         | how you prove you have access to a computer that doesn't trust
         | you). On a language, you don't need the capabilities
         | themselves.
        
           | wyago wrote:
           | Effect typing can achieve capability security statically, but
           | I've also frequently seen capabilities used to describe
           | dynamic capability systems via various methods involving
           | passing capabilities down as reified objects of some sort.
           | 
           | This of course also depends on some related static guarantees
           | that a function can't access ambient capabilities not passed
           | directly in their arguments, but this is a much simpler
           | static guarantee than effect typing and doesn't require
           | specific analysis over normal parameter types.
        
           | jonahx wrote:
           | > Capabilities taken literally are more of a network thing
           | (it's how you prove you have access to a computer that
           | doesn't trust you). On a language, you don't need the
           | capabilities themselves.
           | 
           | You may be thinking of the term in a different context. In
           | this context, they are a general security concept and
           | definitely apply to more than the network, including
           | languages:
           | 
           | https://en.wikipedia.org/wiki/Capability-based_security
           | 
           | http://habitatchronicles.com/2017/05/what-are-capabilities/
           | (this is a great article)
           | 
           | https://www.ponylang.io/
           | 
           | etc...
        
             | bluGill wrote:
             | > On a language, you don't need the capabilities
             | themselves.
             | 
             | Why not? Sometimes I want that. Just today I was looking at
             | some code and realized that it was being used by groups
             | that shouldn't. The code needs to be there and is great for
             | the correct users, but someone is going around our
             | architecture and we didn't notice it.
        
               | jonahx wrote:
               | You are replying to the wrong post. I was quoting the GP.
        
           | ajb wrote:
           | Capabilities are more general than that. They have been
           | around for a long time; one academic design implemented them
           | in hardware in 1970[1]. they can be used in as fine grained a
           | way as 'you are allowed to access this array in memory and
           | nothing else'- which is the sort of thing that needs to be
           | built into languages to be maximally useful.
           | 
           | [1] https://en.wikipedia.org/wiki/CAP_computer
        
             | convolvatron wrote:
             | I disagree about your last point. I looked at a product
             | design once which allowed one to associate a profile with
             | each third party library. accesses across library
             | boundaries were implementing using classic call gates from
             | segmented architectures which could change memory
             | visibility and syscall filtering.
             | 
             | so while I agree that language integration is really
             | useful, I think you can get a lot out of appropriate
             | support in the runtime, most notably the library loader.
        
           | justinpombrio wrote:
           | You can do a lot with capabilities at the language level, if
           | the language supports it. It doesn't require effect types:
           | it's extremely boring from a type system perspective, which
           | is an advantage.
           | 
           | Imagine these changes to a language, making it "capability
           | safe":
           | 
           | - There is a `Network` object, and it's the _only_ way to
           | access the network. Likewise, there 's a `Filesystem` object,
           | and it's the _only_ way to access the file system.
           | 
           | - Code cannot construct a `Network` or `Filesystem` object.
           | Like, you just can't, there's no constructor.
           | 
           | - The `main()` function is passed a `Network` object and a
           | `Filesystem` object.
           | 
           | Consider the consequences of this. The log4j vulnerability
           | involved a logging library doing network access. In a
           | capability safe language, this could only happen if you
           | passed a `Network` object to the logger, either in its
           | constructor or in one of its methods. So the vulnerability is
           | still possible. But! Now you can't be surprised that your
           | logger was accessing the network because you _gave it the
           | network_. And a logger asking for network access is
           | sufficiently sketchy that log4j almost certainly would have
           | made network access _optional_ for the few users that wanted
           | that feature, which would have prevented the vulnerability
           | for everyone else!
           | 
           | I talked about there being a single monolithic `Filesystem`
           | object. That _is_ what would be passed into `main()`, but you
           | should also be able to make finer grained capabilities out of
           | it. For example, you should be able to use the `Filesystem`
           | object to construct an object that has read /write access to
           | a directory and its subdirectories. So if a function takes
           | one of these as an argument, you know its not mucking around
           | outside of the directory you gave it.
           | 
           | Capability safety _within_ a language is stronger than the
           | sort of capability safety you can get at the process level or
           | at the level of multiple machines. But we want those too!
        
             | gnafkcud wrote:
             | this was the original approach for Java, and the main idea
             | behind being able to ship untrusted apps directly to the
             | user and run them in the browser
             | 
             | tomcat also gave different privilege levels to different
             | parts of the classpath
             | 
             | nice idea, but didn't seem to work in practice
        
               | justinpombrio wrote:
               | That's what I'm calling capabilities at the application
               | level (where you say "this .jar can't access the
               | network"), rather than at the language level (where you
               | say "this function wasn't given access to the network as
               | an argument"). I don't think any widely known language
               | has tried capabilities at the language level. (The
               | language not widely known that does it is E.)
               | 
               | The real power will come when you can mix them. In one
               | direction, that looks like `main()` not getting passed a
               | `Network` object because the ".jar" wasn't granted
               | network access. In the other direction, that looks like
               | the system C library you invoked failing to access the
               | network because when you invoked it from Java you failed
               | to provide a `Network` object, so it was automatically
               | sandboxed to not be able to access the network.
        
         | jonahx wrote:
         | Capabilities are the only way.
         | 
         | It is insane to me that in 2025 there is no easy way for me to
         | run a program that, say, "can't touch the filesystem or
         | network". As you say, even a few simple, very coarse grained
         | categories of capabilities would be sufficient for 95% of
         | cases.
        
           | IncreasePosts wrote:
           | bubblewrap?
        
             | jonahx wrote:
             | Nothing in the container space would qualify as "easy" for
             | me. I am talking about native OS features. Also linux only
             | (afaik)...
             | 
             | Or even, for that matter, some sane capabilities for
             | browser extensions.
        
           | taeric wrote:
           | I'm curious what all you want to run that you don't want to
           | access the filesystem? Or the network?
           | 
           | Like, I get it for a few things. But it is a short path to
           | wanting access to files I have created for other things.
           | Pictures and videos being obvious files that I likely want
           | access to from applications that didn't create them.
           | 
           | Similarly, it is a short hop from "I don't want any other
           | application to be able to control my browser" to "except for
           | this accessibility application, and this password management
           | application, and ..." As we push more and more to happen in
           | the browser, it should be little surprise that we need more
           | and more things to interact with said browser.
        
             | jonahx wrote:
             | I think you misunderstood. Among the coarse grained
             | capabilities I mentioned would be "access to folder X and
             | it's subfolders" (read or write).
             | 
             | But to answer your question there are, eg, _tons_ of
             | programming packages in any language that I want _purely_
             | for their computational abilities, and I know this for
             | certain when using them. In fact for the vast majority of
             | GUI programs I use, or programming packages I use, I know
             | exactly what kind of permissions they need, and yet I
             | cannot easily restrict them in those ways.
        
               | taeric wrote:
               | It is specifically running applications that always trips
               | me up here. As a user/operator of the computer, I have
               | been bitten by applications being too locked down for
               | them to be useful in the past. I /think/ we have gotten
               | better such that it is easy to have better OS behavior
               | when it wants to restrict an application. But
               | specifically sandboxing by default has been a source of
               | terrible application behavior for me, in the past. Is a
               | lot like using a shadow banned account where everything
               | looks correct, but nothing is actually showing up. Very
               | confusing.
               | 
               | Now, I think your point on restricting the libraries that
               | are imported to a program makes a ton of sense. I'm not
               | entirely clear where I would want the "breaker box" of
               | what an application is allowed to do to be located, but
               | it is crazy how much just importing some library will do
               | in many programs.
        
               | jonahx wrote:
               | Well you are ofc free to give applications full reign if
               | you want. But you should at least be _able_ to say,  "No,
               | desktop calculator I just downloaded, you can't do
               | anything but compute and draw things in your application
               | window".
               | 
               | More broadly, creating a good UI around granting
               | capabilities is non-trivial. But that's a separate
               | problem from simply not being able to make even the most
               | basic kinds of restrictions that you want in most cases.
        
               | taeric wrote:
               | Totally fair. I just don't know of that many (any?)
               | "desktop calculator" applications that people download.
               | I'm far more expecting that people are downloading and
               | running social applications than they are isolated
               | things.
               | 
               | Mostly fair that it would be good if we could say "on
               | site foo.com, request for any access to not-foo.whatever
               | that happens." I can't remember the last time I saw the
               | sheer number of third party network accesses that happens
               | on far too many sites. It was sobering.
        
             | groby_b wrote:
             | Simple example: Third party SW in a corporate context.
             | Maybe you want to extend some permissions to some internal
             | sites/parts of the FS, but fundamentally, there's limited
             | trust.
        
               | taeric wrote:
               | This is an odd one. At face value, I want to agree. At
               | the same time, if you don't trust the operator of the
               | computer with access to data, why are we also worried
               | about programs they run? If you don't trust them with
               | access, then just don't give them access?
               | 
               | I'm open to the idea that some people are locked down
               | such that they can't install things. And, that makes a
               | lot of sense. You can have a relationship that is
               | basically, "I trust them with access to data running this
               | closed set of applications." Managing system
               | configurations makes a ton of sense.
               | 
               | But, as soon as you have full trust of system management
               | on a group, you start getting in odd worlds where you
               | want to allow them to have full access, but want to stop
               | unauthorized use. Which, we don't have a way to
               | distinguish use from access for most data.
        
               | groby_b wrote:
               | Trusting the user does not transitively extend to the
               | software they use. You might be OK with them e.g. looking
               | at company financials, but you'd really like to be sure
               | e.g. that the syntax highlighter they use doesn't go and
               | exfil that data. You still want them to be able to use
               | the syntax highlighter. (Yes, it's an obviusly made-up
               | example_
               | 
               | You _can_ fully vet apps, each and every one. Or you can
               | choose a zero-trust approach and only vet the apps where
               | it's necessary to extend trust.
        
             | bluGill wrote:
             | Anything really. I tried to print from a sandboxed
             | application the other day and turns out it can't be done -
             | or at least it can't be done by "common user". As an
             | educated person who has been using unix of all sorts I
             | could probably figure it out, but it isn't something I
             | should have to figure out in 2025. (it was a pain in 1998,
             | but it worked better than the snap sandboxes of today
             | despite the pushers of snap from an organization claiming
             | that ease of use is important)
        
               | taeric wrote:
               | Right, but this is largely to my point? I said in another
               | thread that sandboxing often feels like being shadow
               | banned on your own computer.
               | 
               | I get wanting "safe" computers. I'm not clear that we can
               | technically define what legally "safe" means, though. :(
               | 
               | Now, i grant, we can probably get further than I would
               | spit ball based on some bad interactions in the past.
        
             | BobbyTables2 wrote:
             | How about "curl" and "wget" shouldn't have free rein to
             | read/upload and/or overwrite every damn file owned by my
             | user?
             | 
             | Why does "ping" need to have file system access?
        
           | zokier wrote:
           | systemd-run inherits afaik all the extensive sandboxing
           | features from systemd
           | 
           | https://www.freedesktop.org/software/systemd/man/latest/syst.
           | ..
           | 
           | https://www.freedesktop.org/software/systemd/man/latest/syst.
           | ..
           | 
           | sure, the command line get bit verbose but nothing that an
           | alias or small wrapper couldn't solve
           | 
           | the big problem is that modern operating systems have huge
           | surface area and applications tend to expect all sorts of
           | things, so figuring out what you need to allow is often non-
           | trivial
        
           | dooglius wrote:
           | Can do this with Qubes OS by running in a non-networked qube
        
           | est31 wrote:
           | What about Deno?
           | https://docs.deno.com/runtime/fundamentals/security/#key-
           | pri...
        
             | IshKebab wrote:
             | Deno controls access at the process level, so it's better
             | than nothing but it doesn't really help with this specific
             | problem. Also it delegates setting the permissions up to
             | the user, and we know that in practice everyone is just
             | going to --allow-all.
        
           | daveguy wrote:
           | Doing this at the program level is implemented in Linux by
           | SELinux, which defines mandatory access controls (aka
           | limitations on capabilities). This was difficult to get right
           | by default and make a smoothly functioning distro with
           | policies enabled. But it is enabled by default in Fedora.
           | 
           | https://en.m.wikipedia.org/wiki/Security-Enhanced_Linux
           | 
           | To enable this at the programming level would require an
           | enforcement mechanism at the level of a language VM or OS. It
           | would require more overhead to enforce at that level, but the
           | safety benefits within a language may be worth it.
        
           | fsflover wrote:
           | > in 2025 no easy way for me to run a program that, say,
           | "can't touch the filesystem or network".
           | 
           | Qubes OS exists for more than 10 years already. My daily
           | driver, can't recommend it enough.
        
         | Veserv wrote:
         | That is almost the exact backwards way to talk about
         | capabilities. It is not about "restricting" access, it is about
         | "granting" access.
         | 
         | "These libraries can not access the network." No. "These
         | libraries have not been given access to the network (and by
         | default none are given access)."
         | 
         | From an implementation perspective, this is just passing in
         | access rights as "local" resources instead of using "global"
         | resources. For instance, it is self-evident that other code can
         | not use your B-Tree local variable if you did not pass a
         | reference to it to any called functions (assuming no arbitrary
         | pointer casts). You just do the same with these "resources". It
         | is just passing things to functions instead of relying on
         | globals. The only difficulty is making these actions/resources
         | "passable", which is trivial at the language-level, and "fine-
         | grained/divisible" to avoid over-granting.
        
       | JoachimSchipper wrote:
       | I really like this article. I do think it's useful to consider
       | that the unit of isolation ("process") of the cloud era is a VM
       | or container, and that the major clouds _do_ have some sort of
       | permissions model.
        
       | zokier wrote:
       | I'm bit surprised that browsers did not get a mention here. They
       | are one of the big examples of how an application can be split
       | into gazillion small processes, split along trust boundaries,
       | while also being pretty performance sensitive applications.
       | 
       | As for transitive deps, I have some hopes for more "distro" like
       | models to arise. In particular I see clear parallels in how
       | traditional Linux distros work and how large faang style
       | monorepos work. So maybe we could see more these sort of
       | platforms/collections of curated libraries that avoid these deep
       | transitive dep trees by hoisting all the deps into one _cohesive_
       | global dependency that has at least some more eyes on it.
        
         | mike_hearn wrote:
         | Yes, and Chrome's Mojo IPC system is actually one of the only
         | parts of the codebase that's neatly factored out (somewhat)
         | into a reusable library.
         | 
         | https://chromium.googlesource.com/chromium/src/+/master/mojo...
         | 
         | In the past I used the Java SecurityManager to do a PoC PDF
         | renderer that sandboxed the Apache PDFbox library. I lowered
         | the privilege of the PDF rendering component and tested it with
         | a PDF that exploited an old XXE vulnerability in the library.
         | It worked! Unfortunately, figuring out how to do that wasn't
         | easy and the Java maintainers got tired of maintaining
         | something that wasn't widely used, so they ripped it out.
         | 
         | There are some conceptual and social difficulties with this
         | kind of security, at some point I should write about them.
         | 
         | 1. People get distracted by the idea of pure capability
         | systems. See the thread above. Pure caps don't work, it's been
         | tried and is an academic concept that nothing real uses but
         | which sucks up energy and mental bandwidth.
         | 
         | 2. People get distracted by speculation attacks. In process
         | sandboxing can't stop sandboxed code from reading the address
         | space, so this is often taken as meaning everything has to be
         | multi-process (like Mojo). But that's not the case. Speculation
         | attacks are read only attacks. To do anything useful you have
         | to be able to exfiltrate data. A lot of libraries, if properly
         | restricted, have no way to exfiltrate any data they
         | speculatively access. So in-process sandboxing can still be
         | highly useful even in the presence of Spectre. At the same
         | time, some libraries DO need to be put into a separate address
         | space, and it may even change depending on how it's used. Mojo
         | is neat partly because it abstracts location, allowing
         | components to run either inproc or outproc and the calling code
         | doesn't know.
         | 
         | 3. People get distracted by language neutrality. Once you add
         | IPC you need RPC, and once you add RPC it's easy to end up
         | making something that's fully language neutral so it turns into
         | a fairly complex IDL driven system. The SecurityManager was
         | nice because it didn't have this problem.
         | 
         | 4. Kernel sandboxing is an absolute shitshow on every OS.
         | Either the APIs are atrocious and impossible to figure out, or
         | they're undocumented, or both, and none of them provide
         | sandboxing at the right level e.g. you can't allow a process to
         | make HTTP requests to specific hosts because the kernel doesn't
         | know anything about HTTP.
         | 
         | Sandboxing libraries effectively is still IMHO an open research
         | problem. The usability problems need someone to crack it, and
         | it'll probably be language/runtime specific when they do even
         | if libraries like Mojo are sitting there under the hood.
        
       ___________________________________________________________________
       (page generated 2025-01-28 23:00 UTC)