Email or username:

Password:

Forgot your password?
Top-level
Lennart Poettering

… worse, but are not in themselves the main issue with sudo.

SUID processes are weird concepts: they are invoked by unprivileged code and inherit the execution context intended for and controlled by unprivileged code. By execution context I mean the myriad of properties that a process has on Linux these days, from environment variables, process scheduling properties, cgroup assignments, security contexts, file descriptors passed, and so on and so on. A few of these settings the kernel is nice…

84 comments
Lennart Poettering

… enough to clean up automatically when a SUID binary is invoked, but much of it has to be cleaned up by the invoked suid binary. This has to be done very very carefully, and history has shown that SUID binaries are generally pretty shit at that.

So, in my ideal world, we'd have an OS entirely without SUID. Let's throw out the concept of SUID on the dump of UNIX' bad ideas. An execution context for privileged code that is half under the control of unprivileged code and that needs careful, …

Lennart Poettering

… manual clean-up is just not how security engineering should be done in 2024 anymore.

With systemd v256 we are going one step towards this. There's a new tool in systemd, called "run0". Or actually, it's not a new tool, it's actually the long existing tool "systemd-run", but when invoked under the "run0" name (via a symlink) it behaves a lot like a sudo clone. But with one key difference: it's *not* in fact SUID. Instead it just asks the service manager to invoke a command or shell under…

Lennart Poettering

… the target user's UID. It allocates a new PTY for that, and then shovels data back and forth from the originating TTY and this PTY.

Or in other words: the target command is invoked in an isolated exec context, freshly forked off PID 1, without inheriting any context from the client (well, admittedly, we *do* propagate $TERM, but that's an explicit exception, i.e. allowlist rather than denylist).

One could say, "run0" is closer to behaviour of "ssh" than to "sudo", in many ways. Except that…

Lennart Poettering

it doesn't bother with encryption or cryptographic authentication, key management and stuff, but instead relies on the kernel's local identification mechanisms.

run0 doesn't implement a configuration language of its own btw (i.e. no equivalent of /etc/sudoers). Instead, it just uses polkit for that, i.e. how we these days usually let unpriv local clients be authorized by priv servers.

By isolating the contexts and the resources of client and target we remove some other classes of attacks…

Lennart Poettering

… entirely, for example this stuff:

ruderich.org/simon/notes/su-su

But enough about all that security blabla. The tool is also a lot more fun to use than sudo. For example, by default it will tint your terminal background in a reddish tone while you are operating with elevated privileges. That is supposed to act as a friendly reminder that you haven't given up the privileges yet, and marks the output of all commands that ran with privileges appropriately. (If you don't like this, …

Lennart Poettering

… you can easily turn it off via the --background= switch). It also inserts a red dot (unicode ftw) in the window title while you operate with privileges, and drops it afterwards.

And since it's just systemd-run called under a different name it supports the --property= switch that systemd-run supports, i.e. it allows you to set arbitrary service settings for the invoked privileged command/session if you like.

Anyway, that's all for now. Enjoy "run0"!

Stephan Herbers

@pid_eins When you say "while you are operating with elevated privileges", do you mean you can use run0 to create a root shell to work in, or do you just mean while the current programm I started as run0 ist running?

Lennart Poettering replied to Stephan

@stephan not sure I grok what you are saying. run0 can invoke a shell as root for you, but can also invoke any other command you like as root. The shell is after all just a program too. A program that is typically used to invoke further programs, but still just a program.

Regardless what you precisely invoke: run0 will tint the bg of its output (and your input) in a reddish tone. Once the program terminates this tinting ends, and you get your usual black (or white or whatever) background back.

Stephan Herbers replied to Lennart

@pid_eins Yes that explains it. I kinda forget that running a shell is also just running a programm. Looking forward to run0.

Sandor Szücs

@pid_eins wow the auto coloring and title changes would be really annoying. The config to disable it seems to be not user friendly, too:
--background=switch
Whatever background means in this case and why it’s correct to set to switch seems like arbitrary to me.
The tool itself seems to be indeed great!

A Manzer replied to Sandor

@sszuecs @pid_eins I think it's the switch that is called `--background=`. I don't think the thread described the different settings you can give to --background.

Lennart Poettering replied to A

@amanzer @sszuecs oh. i didn't grok @sszuecs's comment, I was sure there was some misunderstanding but I couldn't figure out how! But your explanation explains the misunderstanding perfectly! So yes, the switch is called "--background=" and you can override the background color with that, or you can assign an empty string to disable the tinting altogether.

A Manzer replied to Lennart

@pid_eins @sszuecs Next up, adding "--background=magenta" to my run0.rc. 😂

Lennart Poettering replied to A

@amanzer @sszuecs note quite. we expect ANSI color specifications, hence you probably want --background=35

Sandor Szücs replied to Lennart

@pid_eins @amanzer haha, ok so basically—background=<color>
Ok 👌

TheStroyer

@pid_eins I think it's a good take one sudo. I think there were some vulnerabilities found in sudo recently, so it's good to look at other ways to do it.

I wonder what the adoption of this tool is gonna be. Just very pragmatically, the name run0 is harder to type than sudo. So you would have to make a shell alias. Would it be possible for a distro to completely replace sudo with this and create an alias by default? Maybe it would need to get a compatibility mode for it to replace sudo

Lennart Poettering replied to TheStroyer

@TheStroyer the command line of run0 is intentionally kept close to sudo's. But that's were the compatibility really ends, i.e. /etc/sudoers and so on we're never going to add compat for.

From my perspective run0 should be fine already for a distro to replace sudo with. But let's see how this plays out, I am pretty sure there might be a feature or two we still need to add before the first distros decide it's ready to switch over.

And I am pretty sure there are plenty of distributions…

Lennart Poettering replied to Lennart

@TheStroyer … which think that things like pluggable client-side modules, LDAP and so on are actually a good thing, even though I would vehemently disagree with that.

Dave Anderson replied to Lennart

@pid_eins Same disagreement here. But also iirc policykit is extensible right? So if someone is brave enough they could probably extend pk with whatever things they want, and then it can apply to all privilege escalation not just run0!

Maybe I shouldn't give people ideas...

Lennart Poettering replied to Dave

@danderson PK is scriptable with JS, so people kinda can do any kind of shit with it, of course. But I think it's much less problematic than what sudo is doing, because PK runs that stuff in a well defined execution context forked off PK's service which runs unprivileged – and not on the client side, in an icky, undefined, half-inherited mess of an execution context under user control – like sudo does it.

Dave Anderson replied to Lennart

@pid_eins 100% yes. N:M dlopen() in unpredictable contexts should really go away as a plugin mechanism, it's so easy to create massive problems.

I saw some distros try to fix PAM this way too, they (ab)use the nscd caching protocol in glibc to move all lookups into a system daemon, and hide the .so's from the rest of the system. Same idea, move all the scary plugin stuff to a central location where you can manage it more safely.

Dave Anderson replied to Dave

@pid_eins Looks like there was a short discussion on the glibc ML in 2022 about formalizing this interface and explicitly support the privilege separation use case, but I'm not sure if anything more happened since...

Lennart Poettering replied to Dave

@danderson from my perspective as a systemd person I wouldn't ask for that from glibc. We have nss-systemd these days which is an IPC frontend to the generic varlink IPC API described here:

systemd.io/USER_GROUP_API

Anyone can plug in their stuff there. It's generic, extensible and IPC based. Unless you are a systemd hater I see no reason why we'd need to shove that into glibc.

Dave Anderson replied to Lennart

@pid_eins Ooh, TIL! I didn't know about this entire subsystem of systemd. My worry was going to be what to do with the cursed legacy modules that some people have, but I see with userdbd there's bidirectional compatibility between varlink and nss clients. Very nice, and yes I agree this is a better way to set up the system.

I look forward to the posts for next release, I'm even learning stuff about older releases!

Simo ✔️ replied to Dave

@danderson @pid_eins if later systemd is not enough sssd has provided this service with proper caching for almost 15 years.

It was built specifically for 3 reasons: consistent caching, remove unwanted libraries from binaries, allow centally controlled private credentials.

Because it predates systemd it has its own protcol but also a fast, mmaped shared cache that avoid process context switching when not needed.

(full disclosure I am the original author).

TheStroyer replied to Lennart

@pid_eins So the intention for it to be a replacement for sudo right? I.e. sudo does not need to be present on a system.

jasmin

@pid_eins ooooh, that's nice! thanks!

/cc @ytvwld you might be interested in run0 as well ^^

verbumfeit

@pid_eins How would one check, within a bash script, if it was executed with run0?
Verifying the same for/with sudo always felt confusing to me, with countless different ways to do it, each one less readable than the previous..

Lennart Poettering replied to verbumfeit

@verbumfeit sudo sets a bunch of env vars, and we set the same (i.e. SUDO_UID/SUDO_GID/SUDO_USER), for compat.

Jann Horn

@pid_eins yesss this is great, thank you. it would be really nice if NO_NEW_PRIVS was more widely used, and I think daemon-based sudo is a big step towards that...

Scott Leggett :fedi: :golang:

@pid_eins It sounds like a great improvement on sudo, but I have a question: how do you pronounce "run0"?

Mr. Hmpf

@pid_eins While I welcome the decision to rely on polkit, I find the indirect dependency on a javascript engine a bit... iffy.

Lennart Poettering

@phako well, i am not a fan of that facet of pk either, but I think that's a different problem to tackle. For now, it's *the* local authorization framework on Linux, and all alternatives are worse.

bluca

@pid_eins @phako the JavaScript engine does not process untrusted inputs, only trusted configuration, so it's really not a security problem anyway. People like to talk down js but it's extremely popular and well know and stable and there are tiny engines like duktape, unlike other alternatives with similar properties like lua

Lennart Poettering replied to bluca

@bluca @phako still I think that the right solution here would be to define some minimal IPC rather than choose a programming language for users.

I figure the reason why JS was picked here has more to do with the fact that back when PK was designed there was only D-Bus and D-Bus is simply not a great choice if you want to quickly implement an IPC interface. D-Bus is OK to use from a simple client, but it's really hard to use for a simpler server, after all.

bluca replied to Lennart

@pid_eins @phako not really, JS was chosen because you need to be able to express complex configuration rules, and it's better to use a known tool than inventing a new one. It's not about IPC, the transport doesn't matter, you need a configuration-like DSL because it's unfeasible to ask every admin/user to write and deploy a new program every time some rule needs to be adjusted.

Lennart Poettering replied to bluca

@bluca @phako I don't see why dropping in a JS-based varlink mini-service would be any harder than dropping in a PK JS fragment. you get a function call with a JS(ON) object, you answer it with a JS(ON) object. done.

But by doing this via a Varlink IPC call you gain security (i.e. that stuff runs out of process), and make it generic (i.e. people can chose other languages than JS)

bluca replied to Lennart

@pid_eins @phako because writing a new config file and writing a new running program are not the same thing, and while for us developers there's not much difference, for non-developers the difference is huge. JS was already a though sell because, while the dialect used is minimal and restricted, it's still potentially a full-blown language. Dealing with writing and deploying and maintaining fully independent executables would be way too much. You need dependency tracking, pipelines, etc etc.

Lennart Poettering replied to bluca

@bluca @phako i don't follow why running JS embedded would make anything "easier" than running it as a process of its own?

bluca replied to Lennart

@pid_eins @phako it's not about running, it's about writing, deploying, maintaining

Simo ✔️ replied to bluca

@bluca @pid_eins @phako writing js is as hard as any other program, and it is turing complete which makes "configuration" uncheckable (unless you solved the halting problem) and this is definitely not good security.

A decent basic configuration set + extension via IPC for those extremely rare cases where you would need it (and that you can block) would be much better from a security pov.

Simo ✔️ replied to Simo

@bluca @pid_eins @phako Most people can't think adversarially when writing code, which means using js to configure access to a high privileges is very risky. And can't be easily checked for correctness.

If you do anything more complex than just assigning variables you risk opening huge holes by not paying attention at how things are evaluated.

bluca replied to Simo

@simo5 @pid_eins @phako there can be no "decent basic configuration set", that's the point - otherwise it would be there. It's been working like this for a decade, and it's been just fine as it's simple enough do to the variety of basic things that everybody need. The problems aren't there, they are elsewhere, and requiring users and admins to become software developers and supply chain managers is not a realistic or good or desirable solution

Mr. Hmpf replied to bluca

@bluca @pid_eins Does duktype have the same language level as mozjs now?

bluca replied to Mr.

@phako @pid_eins lower ecma level, but doesn't matter for what one needs to do in polkit rules

Eskild Hustvedt

@pid_eins Might be a stupid question, but how then do you grant 'run0' privileges? I must admit that I haven't paid *that* much attention to polkit, usually just using /etc/sudoers and/or the wheel/sudoers group.

jaseg

@pid_eins That sounds like a nice and clean solution. As far as I understand, this is also basically how privilege escalation is done on Windows, as opposed to the suid mechanism.

tokudan

@pid_eins how does it interact with NoNewPrivileges? Will pid1 refuse a run0 request if that's enabled?

Lennart Poettering

@tokudan NNP has no effect on run0.

I mean, in my ideal world NNP would be a thing that we set globally, early on in PID 1, so that *all* userspace code has NNP set. And then run0 would be the way you get sudo-like behaviour still.

NNP is really about prohibiting code forked off to acquire additional privs, but that's precisely not what run0 will do anyway, it instead asks via an IPC code to run priv code elsewhere, subject to polkit authorization.

Go Up