Run0: introduction and usage
Introduction
Run0 was introduced in systemd version 256 and is intended as an alternative to sudo. Both commands elevate privileges, but are also somewhat different. Author Lennart Poettering describes run0 as somewhat more similar to the ssh command than it is to sudo.
Basics
When you use run0, it will create a transient service unit. Opposed to a permanent service unit that will run for a long time, transient units typically run very shortly. It can be compared with a towel versus a disposable paper towel. When the task is completed or you switched back to an unprivileged user, the service unit will be gone.
Differences with sudo
- Run0 uses isolated services (transient units). Almost no execution or security context credentials are transferred into this new service.
- Run0 allocates a pseudo-tty, further isolating the unit.
- When possible, the authentication prompt is isolated from the terminal. This is done via polkit authentication.
- SetUID and SetGID file access bit are not used.
- No configuration file like /etc/sudoers.
Usage and basic options
Like most tools, run0 comes with a range of options. Here are some of the basic ones that you probably will use.
Option | Action |
---|---|
--background=[COLOR] | Set background color, or disable when set empty value |
--chdir=PATH | Set current working directory to PATH |
--description="TEXT" | Give the transient unit a custom description |
--nice=VALUE | Define nice level (19 to -20) |
--property=NAME=VALUE | Set property (e.g. sandboxing/resource limitation) |
--setenv=ENV=VALUE | Declare an environment variable ENV with value VALUE |
--unit=NAME | Define a name of our transient unit instead of random one |
Let’s have a look at how to use run0 and apply these options.
Become root user
To elevate permissions without running a specific command, run run0 without any parameters.
run0
Background color
You may notice that the background color changed, one of the features of run0. Don’t like this color? Let’s use a blue background instead of red.
run0 --background=44 ps -ef
Use a blue background with bold characters. Use quotes when using the semicolon character.
run0 --background="44;1" ps -ef
Not interested in a background color at all? Give it an empty value.
run0 --background= ps -ef
Unit and description
When we run a command with run0, it will be assigned a new service unit. This is called an transient unit, one of a short duration. The name that is assigned is somewhat random, something like ‘run-u302’. By using the option --unit= we can give it a custom name. Additionally, we can provide a description as well.
By defining a clear name to the unit, it can easily be monitored. Let’s fire up a new task and look at the status of our new service unit.
$ run0 --nice=19 --unit=slowcopy --description="This is a copy task" systemctl status slowcopy.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
Authentication is required to manage system services or other units.
Authenticating as: Michael (michael)
Password:
==== AUTHENTICATION COMPLETE ====
● slowcopy.service - This is a copy task
Loaded: loaded (/run/systemd/transient/slowcopy.service; transient)
Transient: yes
Active: active (running) since Wed 2024-06-19 10:33:39 CEST; 4ms ago
Invocation: 1e903a4c842c453dba816188f65ca8d6
Main PID: 4804 (systemctl)
Tasks: 2 (limit: 4671)
Memory: 1.5M (peak: 1.5M)
CPU: 6ms
CGroup: /user.slice/slowcopy.service
├─4804 /usr/bin/systemctl status slowcopy.service
└─4805 less
Change work directory
The work directory defaults to the home directory of the user. To adjust this, use --chdir= followed by the work directory.
run0 --chdir=/var pwd
Nice level
Run0 allows to run a task with elevated privileges and directly an assignment of the nice level. This is very useful for longer running tasks like a file copy. This way it won’t impact the production system too much.
run0 --nice=19 my-task-with-low-priority
Environment variables
If you need to provide an environment variable, then this can be done using --setenv= followed by the variable and its value. To test that it is really available, let’s display the environment variables from within the newly created service.
run0 --setenv=SECRET=true bash -c 'export'
Sandboxing capabilities with properties
One of the most powerful features with run0 is to set a property. A property defines one or more aspects of the environment that processes are running in. To see available properties, use the show subcommand of systemctl.
systemctl show dmesg.service
Defining a property within run0 is an interesting combination. So even though you elevate privileges, you can still define restrictions and sandbox the command or application.
Example
Let’s say you created a new shell script to automate an important system task. While it may need root privileges to run and interact with other commands, the script should not be able to wreck the system. One option is to use the ProtectSystem setting, which can mark the file system as read-only.
Let’s run a simple task to write a string of text into a file.
$ run0 --property=ProtectSystem=strict bash -c 'echo test > /var/log/write-test'
/usr/bin/bash: line 1: /var/log/write-test: Read-only file system
So even though we run0 will give us root permissions, we are not allowed to write to a new file in our /var/log directory. But what if exactly that directory is what our script requires as part of its tasks? No problem, just set a second property that grants us write permission for that particular location.
run0 --property=ProtectSystem=strict --property=ReadWritePaths=/var/log/write-test bash -c 'echo test > /var/log/write-test'
Now our file can be created, exactly as we intended. Testing a new script that requires root permissions has become a lot safer!