Skip to content

Security

This page tries to provide some background information for security conscious-users and interested readers. On a high-level isd is nothing more than a fancy TUI/wrapper around systemctl. I hope this explains everything. Thanks! See you around! 👋

Wait, you want more details? Wow... I never thought that anybody really wanted to know. 😍 So let's get lost in details 🔬!

Shell Injection

As mentioned above, isd wraps around systemctl calls. systemctl is executed as a sub-process via the Python subprocess module. In this context, the important question is whether or not shell injection attacks are possible.

isd relies on the implementation of Python subprocess to correctly escape arguments and to prevent shell injection attacks. If you would like to learn more about, I would recommend reading the Security Considerations section from the subprocess documentation. The important part is that isd always uses shell=False and let's the battle-tested Python standard library take care of the scary part.

For completeness, isd also calls asyncio.create_subprocess_exec to create and interact with Python Process instances in an asynchronous fashion, but internally, the same escaping is handled by the Python standard library.

Though, what actually happens in the background is always something to scrutinize.

Trust

At the end of the day, it is your call which software you trust. The source of isd is publicly available to increase your trust into the application. Not only that but the software is build via a fully reproducible pipeline with nix! This means that nobody has to use/trust the build artifacts but everybody can build their own artifact via nix build and create an identical version.

But even if you trust isd1, it does not mean that there are no risks this library introduces or that it cannot further improve!

Privileged Execution (sudo)

In general, it is a good idea to never run commands/binaries with elevated privileges. isd is designed in such a way that you never have to run it with sudo. isd is able to automatically prefix the systemctl subprocess calls with sudo if necessary and may ask you for your password via the normal terminal password prompt.

But note that isd can also take advantage of polkit and does not have to rely on sudo to interact with system units2. See the polkit settings page to see how to configure polkit to let an unprivileged user manage specific system units.

The only exception is the systemctl edit command.

Issues with systemctl edit

Opinionated Section

The following section contains my personal opinion about design decisions regarding systemctl edit. Nothing more and nothing less. I am still a big fan of systemd. Otherwise, why would I have spend sooo much time creating a TUI for it?

IMHO, systemctl edit is a bit of an odd 🦆 as it is orthogonal to other systemctl commands. To cite the systemctl man page:

systemctl - Control the systemd system and service manager

Now, is systemctl edit something that controls a service manager? If you ask me, no! systemctl edit does much more/too much.

Before diving into the well-meant criticism, let's start by highlighting the positive ☀️. I am a big fan of systemctl edit3 and think that it is one of the most useful utilities when working with systemd. It makes it a lot easier to debug and improve the security of units. And if it would have been called systemd-edit-unit or something similar, I would have almost no4 complaints.

However, isd is primarily a wrapper around systemctl and systemctl edit is just an odd 🦆. To better understand why, here is a snippet from the systemctl edit man page:

Edit or replace a drop-in snippet or the main unit file, to extend or override the definition of the specified unit. [...] The editor [...] is invoked on temporary files which will be written to the real location if the editor exits successfully. After the editing is finished, configuration is reloaded [...].

So in essence, systemctl edit creates a temporary file, opens an editor, creates/writes a unit/drop-in file, and reloads the configuration.

My main issue is that by creating a drop-in file of a system unit, the systemctl edit command always has to run with elevated privileges, often by prefixing it with sudo. Otherwise, the command does not have the necessary privileges to create the drop-in file. This behavior is also correct and important! No unprivileged users should be able to edit the drop-in files of system units. But this means that systemctl edit cannot rely on polkit rules to allow unprivileged users to manage subsets of system units. Although all other systemctl sub-commands can.

As a result, isd will always have a special case for systemctl edit, since it has to switch back to prefixing commands with sudo even if everything else could be managed with polkit. Also, it takes control over the terminal and starts the editor on its own as root. And this is where I disagree with the current implementation.

Opening any editor as root is, IMHO, not a good idea. One annoyance is that many have user-specific configurations/plugins that are not available if it is running as a different user. The bigger issue is that I do not think we should trust all editors (especially with large plugin ecosystems) to run with elevated privileges. See, for example, the blog titled Can You Trust Your VSCode Extensions?.

You may disagree with this opinion but the interesting thing is that (as far as I understand it), the systemd folks have come to a similar conclusion for pagers. For example, if you run sudo PAGER=<custom-pager> systemctl show <service-with-long-output> where PAGER != less (for example, let the pager be moar) you will, see that it will not open the provided pager. You must explicitly enable it via sudo SYSTEMD_PAGERSECURE=1 PAGER=<custom-pager> systemctl show <service-with-long-output>. For details, see the SYSTEMD_PAGERSECURE discussion. So I wonder if editor should be more trustworthy than pagers?

With this, I hope that I was able to communicate why I believe that systemctl edit is an odd 🦆.

Aside Note

If you made it this far into the document, you need to know that you are an absolute 🦸.

And I hope that you are not scared to use your editor. And if you are, I bet it is not as scary as the reproductive organs of a 🦆.

systemctl edit --stdin

For those that are closely following the release notes of systemd, you may already be aware of systemctl edit --stdin:

--stdin: When used with edit, the contents of the file will be read from standard input and the editor will not be launched. In this mode, the old contents of the file are completely replaced. This is useful to "edit" unit files from scripts:

This already avoids opening an editor with elevated privileges and brings all the other niceties of systemctl edit into a single command. In a future version of isd, I plan on intercepting systemctl edit commands, to open editors as the current user and then only use elevated privileges for the other steps.

Pagers

A pager is a program to display (not edit!) text on the terminal, in a user friendly way5.

By default systemd will avoid running arbitrary pagers for system units. To quote the man pages from SYSTEMD_PAGERSECURE:

When true, the "secure" mode of the pager is enabled; if false, disabled. If $SYSTEMD_PAGERSECURE is not set at all, secure mode is enabled if the effective UID is not the same as the owner of the login session. [...] In secure mode, LESSSECURE=1 will be set when invoking the pager, and the pager shall disable commands that open or create new files or start new subprocesses. When SYSTEMD_PAGERSECURE is not set at all, pagers which are not known to implement secure mode will not be used. (Currently only less(1) implements secure mode.)

Effectively meaning that by default less will be used as a pager for system units. Although this might be an annoyance, the documentation expands on the motivation (emphasize mine):

Note: when commands are invoked with elevated privileges, for example under sudo or pkexec, care must be taken to ensure that unintended interactive features are not enabled. [...] Setting SYSTEMD_PAGERSECURE=0 or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note that if the SYSTEMD_PAGER or PAGER variables are to be honoured, SYSTEMD_PAGERSECURE must be set too.

Neat! So systemd tries to protect us from running untrusted pagers with elevated privileges and/or accidentally running commands/sub-processes with elevated privileges from within the pager. Something that they do not honour for EDITOR, see Issues with systemctl edit for more details on this subject.

Okay, but how does isd work with pagers? Currently, isd takes a rather simple approach for the pagers. It simply uses the pager that is configured via the settings or uses the pager from the environment variables SYSTEMD_PAGER or PAGER. In all instances, isd ignores the value of SYSTEMD_PAGERSECURE!

The simple reason why this is not an issue is that isd does not run the pager with elevated privileges. Even if isd may prefix the systemctl call with sudo, the result (or text) is read from the standard output6 and then fed to a pager as a new sub-process. This pager process runs without elevated privileges and as such does not require more trust than any other program. :)


  1. And if you do, thank you 🥹 

  2. Where systemctl edit is an exception. See Issues with systemctl edit for more details. 

  3. And especially systemctl edit --runtime

  4. With the exception of how systemctl edit trusts $EDITOR

  5. For more details, see the Wikipedia page. 

  6. Some initial data may be dropped while reading to improve the interactive features and avoid high memory usage.