I am a complete fresh to Nix/NixOS. I currently have a GUI program that is essentially a wrapper for a CLI program. This CLI program will be referred to as the core from now on. Since some features of this core require root privileges, on regular distributions, to allow users to run the GUI program with normal privileges while still accessing the core’s root-required functionality, the GUI program typically sets the core executable’s owner to root and sets the setuid bit, allowing regular users to access privileged features. However, on NixOS, we know that /nix/store is read-only, so there’s no way to ensure privileged functionality through normal means. Using overrideAttrs to perform the same chown operation during the postInstall phase doesn’t seem feasible either. While using security.wrappers might solve the problem, having the GUI program run as root feels dirty and potentially raises security concerns. Is there a way to have only the core program run with root privileges while keeping the GUI running as a regular user, without having to modify and compile the source code?
If you want to test this program specifically, the package name is mihomo-party, and the relevant functionality is its TUN mode.
I can think of one perhaps hacky option: create a setuid wrapper for the core, then have the GUI call the core wrapper. Though I don’t know enough about the program to know if it’d require a recompilation to just point it at a new location for the core.
Since the program relies on Electron’s app.getPath() to determine the main directory and uses relative paths to execute the core binary, your solution would require source code modifications and recompilation, which is an overly complex approach.
This is a cross-platform project, so bundling all resources together is at least understandable - that’s partly why Electron was chosen in the first place. Regarding using overrideAttrs for patching, I personally feel that any solution requiring recompilation is heading in the wrong direction. In other words, not all software is open-source and free software - I’m looking for a solution that preferably doesn’t involve modifying source code and recompiling, as not all software permits you to do so.
This might reflect my personal preference - I’m not a zealous open-source advocate. If a software’s functionality is excellent enough, I’ll use it even if it’s closed-source. For this reason, I’m more interested in finding a universal solution rather than a specific one that only works for open-source software.
Nevertheless, thank you for the inspiration. If I really run out of options, I’ll take your approach.
Sure, I myself use a closed-source video editor since there are no good open-source options, but that wasn’t my point. Even closed-source software has to somehow be packaged on NixOS, whether that requires some sort of binary-level patching or wrapping. My approach to solving problems usually involves solving one simple problem at a time, then getting more complex as the situation requires, rather than the other way round. I cannot think of a solution that will work universally, since all software is different (and some software is downright - perhaps intentionally - abstruse).
Rename the core binary to something else and put the setuid wrapper in its place. I believe for some wrapper functions, this is even the default. The wrapper script gets the original name and the original binary is renamed to .<original>_wrapped or something like that.
No need for binary patching here as far as I can see.
Btw to address the other point - whatever is chosen for the frontend, if the frontend and backend are separate programs then upstream would ideally allow the location of the binary to be user-configurable rather than assuming that the core binary is always in ./mihomo or whatever. Or at least, if it execvp()'d then it could find it from $PATH. I don’t really understand why a cross-platform program is making it harder to use cross-platform.
So instead of .overrideAttrs, IMO the ideal solution would be add a setting in the GUI with their current relative path as the default. Though getting upstreams to agree to such changes is not always easy, hence I usually don’t go that route.
Are there any issues with using overrideAttrs? I just don’t want to modify the binary / recompile that, not that I’m against repackaging. I’m new to NixOS, so I’m not sure what problems this approach might have.
Yes it is. Sorry for my lazyness, I just know security.wrappers will create an wrapper under /run/wrappers, which functions can create wrappers in the package?
Absolutely agree that. I will contact the author to see if he agree to add this feature. After carefully reading your insights, I realize I was a bit too fixated - I was too focused on finding a one-time solution or a low-cost fix. Thank you for helping me see this clearly.
I will try everyone’s suggestions tomorrow, as it’s already late night here and I can’t try them immediately. Good night
I ultimately chose the bare binary approach, which also makes it convenient to manage mihomo’s configuration files with git. When using binaries wrapped with security.wrappers and writing wrap scripts during the postInstall phase, mihomo-party doesn’t seem to recognize it as an privileged core and refuses to enable the TUN functionality. Perhaps the best solution to this problem would be to patch and recompile it. However, since we’re already using NixOS, why bother with a frontend - the WebUI is sufficient, maybe.