How to best enable `sudo` en a systemd.services."rustdesk"?

Hi,

Yeah, I know. One shouldn’t use sudo in a systemd service script:

You don’t. sudo is for interactive use. Doing anything else with it is either incredibly cumbersome or rips security holes into your system. NixOS makes this rather hard anyway due to how setuid is handled.

But I’m trying to get rustdesk --service, a background service that allows remote logins, to work with NixOS. And it calls sudo - not much I can do about it.

Many gory (but perhaps irrelevant) details in Can’t get rustdesk to run under systemd in NixOS - works fine from terminal : r/rustdesk. The problem here was that rustdesk didn’t have a sudo in the path with setuid.

This fix did the trick:

diff -u configuration.nix.doesnt-work configuration.nix
--- configuration.nix.doesnt-work	2025-03-23 16:43:42.150263373 +0100
+++ configuration.nix	2025-03-23 16:26:03.500585285 +0100
@@ -578,8 +578,11 @@
     description = "RustDesk";
     requires = [ "network.target" ];
     after= [ "systemd-user-sessions.service" ];
+    script = ''
+      export PATH=/run/wrappers/bin:$PATH
+      ${pkgs.rustdesk}/bin/rustdesk --service
+    '';
     serviceConfig = {
-      ExecStart = "${pkgs.rustdesk}/bin/rustdesk --service";
       ExecStop = "${pkgs.procps}/pkill -f 'rustdesk --'";
       PIDFile = "/run/rustdesk.pid";
       KillMode = "mixed";

(full service definition below)

Is this the best way of doing this? Does anyone have better recommendations? (Other than modifying rustdesk which is out of scope).

I was thinking that instead of adding /run/wrappers/bin to the path, I could perhaps create a temporary directory, copy sudo from the path into it, chmod +s /path/to/sudo (as script runs as root), and add that directory to the path. And then I need to make sure I delete that temporary directory again. But that is cumbersome and for perhaps very little gain. And there’d be two sudo executables with the setuid bit set in the system rather than only one.

systemd.services."rustdesk"

  systemd.services."rustdesk" = {
    enable = true;
    path = with pkgs; [
      pkgs.rustdesk
      procps
      # This doesn't work since the version of sudo that will then be in the
      # path, won't have the setuid bit set
      # sudo
      # See the trick in `script` below modifying the path
    ];
    description = "RustDesk";
    requires = [ "network.target" ];
    after= [ "systemd-user-sessions.service" ];
    script = ''
      export PATH=/run/wrappers/bin:$PATH
      ${pkgs.rustdesk}/bin/rustdesk --service
    '';
    serviceConfig = {
      ExecStop = "${pkgs.procps}/pkill -f 'rustdesk --'";
      PIDFile = "/run/rustdesk.pid";
      KillMode = "mixed";
      TimeoutStopSec = "30";
      User = "root";
      LimitNOFILE = "100000";
    };
    wantedBy = [ "multi-user.target" ];
  };

1 Like

Whoa, that’s quite some horrible application code. This should be done with polkit. I’d seen this project around, really expected slightly better quality from it…

Your fix is the only half-reasonable solution, in fact I’ve seen similar things here and there in nixpkgs that should probably be cleaned up. Copying around stuff to add more things that are setuid sounds like the opposite of what you should be doing, and it’s not like only making a subset of the wrappers available would make this any less imperative.

I’d add some assertion that security.wrappers.sudo is set (and that program is actually sudo). There are sudo alternatives that don’t just replace the binary, an eval-time check to tell anyone using one of them that they need to switch to a sudo-compatible one seems appropriate. Plus it brings it back to being a bit closer to being resolved properly.

I’d also see if there’s an issue about using polkit upstream and stay far away from this until at least that is resolved, and probably longer given the poor quality and just how impactful an exploit against this is, but that’s just me.


To be clear to anyone coming here from search engines, though: No you should not be doing this. If you think there is no other option, ask first, especially if you’re planning to upstream whatever you’re doing.

This is an insane hack and only “necessary” in this super specific case where a remote system management service that has an obvious design flaw is being packaged. If you’re doing the same, consider using cockpit instead of packaging something new.

2 Likes

FYI it seems they are not going with polkit as an approach, based on gui window for ask user password not everywhere work (polkit not work on hardened Linux) · Issue #2756 · rustdesk/rustdesk · GitHub and Debian Unable to unlock settings (debian, xfce) · Issue #8719 · rustdesk/rustdesk · GitHub. They even had some hackish polkit-related code that was removed in favor of sudo in replace pkexec with gtk sudo by 21pages · Pull Request #9383 · rustdesk/rustdesk · GitHub.

1 Like

Right, looks like too many support requests around polkit config. Understandable from a business perspective, I guess, as much as the result is awful.