Regular users start GUI with root privileges

My question is not about a technical solution but more about the concept and possible security problems. And one question is also if pip(x) & similar tools and build-backends are suited for that scenario.

There are several use cases where a regular user starting a GUI with root privileges. Known examples are “synaptics” (a distro package manager) or “GParted” (partition GUI). The user is asked for a root/sudo password and everything goes well.

How can I achiev something like this with a Python application (e.g. using PyQt) that is installed via pip(x)?

One technical approach was described and is in short that the application do start itself again via something like os.execvp(['pkexec', 'myapplication']).

But this is tricky and has some technical implications not completely solved yet (be me).

And more important it seems to have a security problem because the generated entry point scripts are editable and can be used to inject additional commands when the user is compromised.

Or am I totally on the wrong way here? Might it be that such a use case (user starting a GUI with root privileges) is not intended to be solved by vanilla Python packaging tools like pip(x) and the available build-backends? Is this a job that should always be handled by distro maintainers creating deb/rpm packages for specific GNU Linux distributions?

1 Like

Yes, I think so.

What exactly is your threat model?

The Python code (i.e., the part of it that requires the elevated privileges) is also editable.

If I’m installing something intended to run as root, then I already need to be able to trust everything that gets installed - including convenience scripts for elevation.

If the documentation says that the package is going to use pkexec (or worse: I run it and it unexpectedly prompts me) and I don’t want to trust that, then either I just don’t get to use it, or I have to expect someone else to trust (and audit) it for me (i.e., the distro maintainer).

If “the user is compromised”, I don’t know what you expect to do, or why you would consider it your responsibility to… reduce the attack surface from outside, or something like that… ?

1 Like

I would design such an app in two parts, the GUI and a backend that does the priviledged work. The GUI does not require privs and calls into the backend via dbus or sudo etc to get the priviledged access it requires.

Bare in mind sysadmin’s prefer command line, scriptable, interfaces.
If the GUI is the only interrace you will get push back to build a CLI version.
Many systems are managed over ssh and the command line interface is required.

1 Like

I’m with @kknechtel on this. I’m not sure what you’re looking to prevent/stop. If an application/script requires elevated privileges and the user is able to elevate, then they’ve already got everything they need to do harm. Why worry about locking down your python files when they can already do something like sudo rm -rf / --no-preserve-root?

Raymond Chen (legendary MS Developer) calls this “being on the other side of this airtight hatchway”: It rather involved being on the other side of this airtight hatchway - The Old New Thing

If there’s something else I’m missing here, please elabroate.

1 Like

Thanks a lot for your replies. Especially about the security problem I don’t have the expertise to answer. But please be sure I will take your opinions to my team and they will be considered.

I totally agree with you here!

But I was not the designer or founder of the related project. The project is 15 year old and well smelling Python code. I took over the project with two other guys and now we try to fix things and modernize the infrastructure and design.
These “two parts” is on our list but not a solution in for the near future.

I think the security issue is very real and needs to be taken seriously.

The basic security principle on a multi-user machine is isolating users from each other, and preventing a user without special privileges from affecting the whole machine. The problem here is that by design, your method of running the app with pkexec is giving root privileges to a user-editable file. This is wholly different from running something as root that requires root privileges to modify.

Say I’m the sysadmin of a school and my personal account on the server gets hacked (e.g., I run some email virus inadvertently). This is bad, but the damage is confined. However, if I install the backup tool in the proposed way, the virus can potentially modify that tool’s source code. Then, when I run the tool for the next time, it gets the opportunity to infect the entire school network.

In short, installing programs in this way breaks the user/root separation. A user-editable program should not be casually run with root privileges.

2 Likes

To be clear, it’s going to be perfectly fine if you install the app on the system level, but I don’t know if pipx can do that and I don’t have the time to investigate. It should also be fine from the security POV to install them with sudo pip, but you might have to pass the self-explanatory --break-system-packages flag, for the reasons explained on Externally Managed Environments - Python Packaging User Guide. That flag needs a lot of care to use without risk for the system. You could also just create a venv as root and install the app there, reproducing pipx’s work manually.

2 Likes

I do not ask because I don’t believe you. I just try to understand it better. My understanding goes not very far on that topic.

The problem here is that by design, your method of running the app with pkexec is giving root privileges to a user-editable file.

Isn’t this always the case when using pkexec, sudo or something similar?
I assume I am wrong here?

Might it be the problem that the application do call itself again with root privileges? The problem is not the use of pkexec but that the app is calling itself?

How could this be solved better? Let me try:

Separating the root-features into a second application and naming it myroot. Having the GUI application naming it mygui. Installing mygui as usual via users pip(x) but installing myroot via sudo pip(x) into the root users environment. Then mygui can use subprocess.run() or os.execvp() calling myroot via pkexec?

Is this theoretically more secure?

Both sudo and pkexec can be configure to only allow specific users to do specific actions. You would only allow the minimum access that is required.

All the program code and the data it operates on must be root owned.

As for installing into the system it depends on your OS.
For my purposes I often package apps as RPMs and installed the RPMs on my Fedora systems. The same can be done for debian .deb files.
The key rule is never replace a system surplied file.

Using a venv is also a viable solution. But consider supply-chain attacks.
You will be exposing your self to attack via PyPI if you just grab from the web.
A good practice is to get the source of libraries you use from a trusted source and
keep your own copy of it. Also audit that code if worth considering.

I would not use the --break-system-packages as that is asking for trouble and can be avoided with venv etc.

2 Likes

No. When you run, say, sudo rm x, you’re running the executable /usr/bin/rm. That executable is owned by root, and cannot be replaced by an unprivileged user.

The situation created by your method of installation would be equivalent to making /usr/bin/rm writable by some non-root user. A process spawned by that user could then wreak havoc on the system by replacing rm with an executable that does nefarious things, and waiting for it to be run, the next time someone does sudo rm something.

Yes, but also unnecessarily complicated since you could just install the entire app into the root environment. The key point is that all code executed by root should be owned by root.

1 Like

Agreed, with the caveat that sometimes it is quite useful to have the same app be able to run in “read-only” mode without privileges, but if you have root privs, it can make changes. That might be a justification for the split: keep all of the UI in the unprivileged part, and then when you ask it to commit those changes, it invokes the privileged part to do that.

3 Likes

It is not clear to me if “installing everything into the root environment” would help in my case. Isn’t then the regular user unable to start the application “as user”?

The real use case we do talk about here is a backup application (Back In Time using rsync in the back) where the users are able to create backup jobs with files/folders accessible by root.

Currently it use a make-file based “build-system” when installed from upstream and of course the package systems of the GNU Linux distributions. The original founder of that application decided about that feature. Now it is there and I am not in the position to cut it of for the users.

The app has two “entry point” like scripts. One start it as a regular user and the other do use pkexecv to start it “as root” using the first entry point script but with pkexecv.

In the near feature I need to migrate it to modern Python build-system (pyproject.toml etc pp) and remove the make-file system. Because I am not able to modify the entry point scripts then I was pointed to the solution I do use here in the demo project I linked to.

In practice this means that the files are owned by root user and permissions do not allow none root to write to them. The permissions do allow the app main file to be executed.

Thanks a lot.

I realize that this is the situation when the application is installed from the official Debian repo. Everything is owned by “root:root” but “others” do have read access.

I would keep it that way:

  • This situation is not realizable with Pythons vanilla build-tools (pip, setuptools & Co).
  • Using pip to install my(!) appliation from upstream is not recommended for regular users but only for develoers and testers.
1 Like

Once you have built the app as a dev I had assumed that you would then have a script to install it into a system, for example into /usr/local/bin etc.
Its at that step you can enforce file ownership and file permissions.

2 Likes

Why should I have such a script when using vanilla Python build system? Isn’t it what pip and a pyproject.toml is for?

Yes currently there is an old and ugly makefile system but I want to get rid of it.
The real installing should be handled by distro maintainers only.

Python build systems are like C compilers, it is not their job to install software into a system. As a developer you need to take the results of the build and use appropriate tooling to get the built assets on to your system.

I, for example, package some of my python tools as RPMs for installation on Fedora. Others I use a script to install into my Fedora systems that runs as root.

1 Like

[quote=“Barry Scott, post:18, topic:42314, username:barry-scott”]
Python build systems are like C compilers, it is not their job to install software into a system.[/quote]

But they do. I can define entry points etc pp. Pip will install a package into my system. Why do they do “the job” when it is not “their job”?

What is an “appropriate tooling” for a Python GUI application? Makefiles do work (as I can see in my own project) but IMHO for away from being appropriate.

I disagree with “as a developer you need…”. As upstream developer it is not my job. It is the job of the distro maintainers taking care of that. And they do a damn good job most of the time (except Canonical Ubuntu of course :imp: :joy: ).

Sounds as an extra burden for you. It could save resources on your site if you would let that up to the distro maintainers. If the latter are not fast enough encourage your users to open tickets at the distro and not at upstream.

You are assuming that there are people that will do the work for me to package stuff. That is simple not the case. Packagers are typically doing the work in their free time. Just getting a package added to a distro can be difficult even when there is a volunteer to do the packaging.

I had assumed that you are doing this GUI as your day job.
Part of making this internal tool securely available is to install it in the system.
And you are the one that will need to do that work if you need it done.

2 Likes