Conversation

next step for capsudo is to add socket activation support (supporting both the systemd and s6 protocols)

this allows you to not have a giant herd of long running capsudod processes

related to this is allowing capsudod to receive already connected sockets in general, which will allow for extending the capsudo protocol with additional features like requiring a secret to mint the capability

2
0
0

@ariadne I wonder if sealed capabilities, like in CHERI, would be useful. If you're not familiar, sealed caps represent the ability to do something just like any other cap, but cannot be used until they are unsealed by the correct "unsealing capability".

This allows for separation of concerns, so one service might have access to sealed caps for various commands and file accesses, thus being able to send those caps for other services, while being unable to actually use the caps.

Another service might have an unsealing cap for a particular domain, but only be able to access the items of that domain when given sealed caps of that domain. And not be able to use sealed caps belonging to some other domain.

0
0
0
@ariadne i really gotta stop slacking and design/add socket activation to openrc's provided tools
1
0
0

@navi @ariadne And I really wish people would stop using the "socket activation" vocable because it is not a well-defined concept.

I wrote this 10 years ago, and it is still relevant today: https://forums.gentoo.org/viewtopic-t-994548-postdays-0-postorder-asc-start-25.html#7581522

1
1
0
@ska @ariadne i know but "fd holding plus generic super server" doesn't roll off the tongue so well, or rather, most people won't know what it means at all :/
2
0
0

@navi @ska i mean what i want is ultimately inetd but for unix sockets

2
0
0
@ariadne @ska that's more or less what i want to add to openrc, not exactly but very similar

(and it's also what i mean by "socket activation", daemon that opens the socket, holds it old, and when something attempts to start a connection, it starts the openrc service proper, passing in the fd to it)
1
0
0

@navi @ariadne but that's the thing, when you say "socket activation" most people know what it means even less.

And this confusion is but one on the long list of systemd's crimes.

1
0
0

@navi @ariadne Like https://skarnet.org/software/s6/s6-ipcserver.html? or do you want to pass the listening socket to the daemon, so the daemon itself can do the accepts?

1
0
0
@ska @ariadne listening i think, since that's what most current services are expecting afaik (since those services are made to work with systemd's LISTEN_FDS)
1
0
0

@navi @ariadne OK. What benefit are you looking for? (this is a real question, I'm trying to understand)

1
0
0
@ska @ariadne the "goal" is to not have the services running until there's something trying to talk to them (and some services even make themselves exit if idle for long enough, hoping to be re-started by the super-server when new connections pop in)

but while that is the idea, as i mentioned to you before, i am (so far) unconvinced it bears any benefit over a daemon that calls poll or a blocking accept or smth (and is thus not scheduled to execute until there *is* a connection) -- so i can't say it's a benefit until i test out a variety of setups with either system in place
2
0
0

@navi @ariadne @ska one possible benefit of a super-server that opens the listening socket and passes it to the real service: the service can listen on a privileged port (below 1024) without ever running as root (or with CAP_NET_BIND_SERVICE)

2
0
0

@dakkar @ska @navi ugh do not get me started on the stupidity of cap_net_bind_service in 2025

1
0
0

@navi @ariadne Yeah, I am unconvinced as well (and that's a euphemism), but if you're willing to experiment with it and test various metrics, why not.

The reason why systemd does this in the first place is to cut corners with dependencies. When a service is accessible over a socket, in the absence of Type=notify, systemd considers the service ready as soon as something listens to the socket, and dependent services can then start. So, in order to make the boot appear faster, systemd itself listens to the socket, so it can start dependent services immediately in parallel.

Never mind that the service itself might then take a long time to start up when a client wants to connect; or even might fail. It's all about the appearance of speed. It's fake. And that's why I don't like it.

0
0
0

@dakkar @ariadne @navi as long as the server drops privileges after binding, this is no different from the supervisor needing to have privileges to bind to the socket.

(supervisor, not super-server: a super-server binds to a socket and listens, and spawns servers with the accepted socket as stdin and stdout)

You could say, well, this dispenses the server author from thinking about it. And I'd answer: I want my server authors to think about the level of privilege they need, I want them to know these things and handle them correctly, and I'd rather have them do that than learn how to use sd_listen_fds which isn't even a good API to begin with.

1
0
0

@ariadne @dakkar @ska @navi what’s stupid about CAP_NET_BIND_SERVICE? services like ident should be restricted to root and it makes sense for there to be a capability to allow not actually running them all as root

1
0
1

@noisytoot @ska @navi @dakkar yes, some services should be restricted to root.

in 2025 we have better answers to this problem than "only root/cap_net_bind_service can use ports below 1024"

netfilter's UID matching being one example, eBPF being another

3
0
0

@noisytoot @ska @navi @dakkar basically, the <1024 thing is top-down imposed policy, while software freedom is better served by bottom-up policy

2
0
0

@ariadne @noisytoot @navi @dakkar I think the question is, what's the problem with "only cap_net_bind_service can bind to 1023 and lower"? Why is it a bad solution, why is this a problem that needs solving?

1
0
0

@ariadne @noisytoot @navi @dakkar I'm usually with you but I don't follow that. What does "ports 1023 and below are restricted to root" have to do with software freedom and imposing policy? it only looks like a technical convention to me.

2
0
1

@ska @noisytoot @navi @dakkar yes, an outdated one. it encourages spawning services as root that would not need to start as root to begin with otherwise.

1
0
0

@ska @noisytoot @navi @dakkar basically i am saying that this should be handled by the firewall at this point

0
0
0
@ska @ariadne @noisytoot @dakkar

in my view i always found it weird, why are ports <1024 special? sure they're used for likely critical services that you won't want any user abusing a crash to claim access to

but that's not limited to <1024, if we ever got more than 1023 unique "privileged" services then what? it's a lot more reasonable to me for privileged ports to be configurable, so the administrator can say what they consider privilege and who should have the access as well

we already do that with files in the filesystem and a lot of other resources, i never got why inet ports were special-cased to begin with (tbh i kinda wish those ports were just sockets in /dev or smth)
1
0
0

@navi @noisytoot @ska @dakkar it is literally a thing that was implemented in Unix before firewalls were invented

1
0
1

@noisytoot @ska @navi @dakkar also, while here, i will point out that identd in 2025 is also incredibly stupid, disclosing information about system users based on a 16-bit secret is madness

0
0
0

@ariadne @ska @navi @noisytoot the way it was described to me (ages ago), was: if I’m talking to some random machine on the network, on a low-numbered port, I can have some assurance I’m talking to a service that the administrator of that machine set up, and not something that a user started

still weird, still outdated, but not much to do with firewalls or eBFP

and it had to be a non-configurable thing, because it was for the benefit of other machines

1
0
0

@dakkar @ska @navi @noisytoot it does have much to do with both, as both are ways of enforcing that policy

0
0
0

@ska you’re not wrong
but also consider: code that’s not written can’t have bugs
if the service never needs to run at higher privileges, it doesn’t need to care about dropping them
and I would trust you, or @navi, or even Lennart, to run a child process with the correct priveleges from your supervisors, than I would trust most developers (e.g. me) to do the whole set*id dance correctly in all execution paths…

I agree that it’s not a great reason, but maybe it’s not a bad reason either?

@ariadne

1
0
0

@dakkar @navi I trust the shortest code path. Going through sd_listen_fds lengthens the code path. If you want to trust random devs with the least possible amount of code (which is a sensible position!), give them a super-server and tell them to only read from stdin and write to stdout. That way, they're not even in charge of the accept() and the main loop. And that factorization actually shortens the code path.

1
0
0

@ska the few times I’ve written servers, that’s pretty much what I’ve done ☺

@navi

0
0
0

@ska @ariadne it's too coarse? We should be able to control privileges for each port independently at this point.

1
0
0

@ariadne @mcrees ah yes, let non-root users race to bind their RCE in a can to port 443, perfect.

The point of making low ports special is that there are global conventions on what services should be running where and restricting ports is essential to correctness in addition to security. Whether you're hardcoding the split or using nonportable kernel communication mechanisms for more fine-grained control doesn't change that.

1
0
0

@ska @mcrees nobody is saying that. we are saying make 443 restricted by configured policy.

1
0
0

@ariadne @mcrees my point is that every system will need the same policy, by virtue or vice of IANA registration. What will configurability bring, apart from more complexity and brittleness ?

1
0
0

@ariadne @ska @mcrees or conversely, prevent non-root users from owning a high port. there are plenty of administrative systems out there that listen on >1024 by default and are expected to run as root.

1
0
1

@ska @navi @ariadne Agreed here. I always have to think when I see that term to remember which combination of behaviors it means. And the idea of passing the _listening_ socket into a service and having it do the accept()s is to me very weird and unrelated to a super-server. That's more of a daemonize-type wrapper to avoid rolling-your-own privilege-dropping code.

0
0
0

@ariadne @ska @mcrees Why the requirement for a <1024 port number? The only one I can think of is when the well-known port is already assigned to a low port number, and IMO writing a small application that deals only with opening the listening socket and dropping privileges before passing the socket to the real service makes for a smaller amount of code subject to breakage.

0
0
0
@ariadne @ska @navi @dakkar How do I actually achieve this using netfilter or eBPF?

nftables's skuid/skgid matching only works on output rules: I can easily prevent specific users from connecting to certain ports, but I'm not sure how this can be used to prevent specific users from listening on certain ports.

eBPF I don't know that much about but I'd be interested in how I can do this with it.
0
0
0