-
Notifications
You must be signed in to change notification settings - Fork 20
Forward Linux capabilities to child process #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…nd then apply all the capabilities in both the Effective and Inheritable sets to the Ambient set, so that the child process (which can be unaware of capabilities) can have its capabilities set accordingly.
Thank you very much for this contribution. Could you elaborate a bit on the use case? Running desktop Linux since the late 90s, I have never encountered Linux Capabilities. But then, I am mostly just running Linux Live ISOs. Under which circumstances would a normal desktop user benefit from this? Can you think of any security risks this PR might introduce? |
Thank you for your reply. I'd suggest you to read the link I had mentioned, but as it is quite a big read (and I had to read it multiple times to fully grasp it myself), here a really short summary: Linux capabilities had originally been introduced to Linux in version 2.2 (so January 1999) and partition the rights that the root user has so that processes can have a subset of them instead of the whole bunch when simply running as root (including setuid). Capabilities include things like listening on ports <= 1024 (CAP_NET_BIND_SERVICES), changing file ownership (CAP_CHOWN), sending SIGKILL to any process (CAP_KILL) or the ability to change the capabilities set on a file (CAP_SETFCAP). The ability to set the capabilities on a file had been introduced with Linux 2.6.24 and allows a system administrator (aka someone whose processes have the CAP_SETFCAP capability; e.g. root) to allow specific programs to have specific rights without granting it all rights that are granted to root. To give you an example where we use this: we have a product called BootCast which we're currently preparing for a Linux release (as an AppImage) and which provides PXE services, thus it needs to be able to listen to TFTP connections which require a port <= 1024 which in turn normally requires root privileges. Running an application - especially something as complex as a server application - as root can be quite a security problem. By using Linux capabilities this risk potential can be reduced, because a system administrator only needs to apply the CAP_NET_BIND_SERVICES capability to the application file and the Linux kernel will deal with the remainder. Regarding security risks: Feel free to ask other Linux users with more experience with capabilities before accepting this PR as I definitely wouldn't consider myself a “pro” here; we simply had a problem (namely running our product which is an AppImage without root privileges if possible) and implemented a solution (this PR), so we'll continue to maintain our fork due to us needing it, but we'd prefer this to be part of upstream obviously. Also feel free to ask further questions, I'll do my best to answer them. |
Thanks @miray-sb for your detailed answer. Indeed I didn't know about this before, but your explanation does make sense to me. I'd be interested to hear how @TheAssassin sees this, as on the basis of your explanation it seems reasonable to me to forward Linux capabilities to the child process, like you propose. |
Pending @TheAssassin TODO list |
It'd be nice to have this code under an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new function to adjust Linux capabilities for child processes, ensuring that capabilities are forwarded appropriately when starting an AppImage.
- Added a new function to modify capability sets via SYS_capget/SYS_capset and prctl calls.
- Integrated the capability adjustment call into the main execution flow.
struct __user_cap_header_struct hdr; | ||
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; | ||
int res, datacnt; | ||
unsigned long long capeff, capperm, capinh; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variables 'capeff', 'capperm', and 'capinh' are declared but never used. Consider removing them to clean up the code.
unsigned long long capeff, capperm, capinh; |
Copilot uses AI. Check for mistakes.
if (res) | ||
{ | ||
fprintf(stderr, "Failed to set ambient capability %d; error: %d\n", capval, errno); | ||
return 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function returns 1 upon failure in the prctl call while other errors return -1. Consider standardizing error return values for consistency.
return 1; | |
return -1; |
Copilot uses AI. Check for mistakes.
@@ -1704,6 +1798,9 @@ int main(int argc, char* argv[]) { | |||
setenv("XDG_CONFIG_HOME", portable_config_dir, 1); | |||
} | |||
|
|||
/* Ensure that capabilities for the AppImage are applied to the children */ | |||
appimage_adjust_capabilities(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value of appimage_adjust_capabilities() is not checked. Consider verifying the result to handle potential errors appropriately.
appimage_adjust_capabilities(); | |
if (appimage_adjust_capabilities() != 0) { | |
fprintf(stderr, "Error: Failed to adjust capabilities for the AppImage.\n"); | |
exit(EXIT_FAILURE); | |
} |
Copilot uses AI. Check for mistakes.
When a user starts an AppImage from inside a shell that has certain Linux capabilities set, but the AppImage itself has none set, then the child process will have those capabilities enabled thus allowing the child process certain privileged functionality (e.g. listening on ports <= 1024).
However if capabilities are set on the AppImage file (using setcap) then the child process won't inherit any capabilities due to how capabilities are handled in that case (the Ambient set will be set to 0 which is what a process unaware of capabilities relies on).
This can be worked around by extracting the AppImage, setting the capabilities on the executable file and then running that. However this isn't a very convenient solution.
Thus we propose the extension contained in this merge request: before doing the
execve
for the child process all currently effective capabilities will be added to the Inheritable set and then all capabilities in both the Effective and Inheritable sets will be added to the Ambient set (only capabilities that are in both the Effective and Inheritable sets can be raised in the Ambient set).This way a binary inside the AppImage can make use of privileged operations without running as root, but the system administrator still has full control what the AppImage can do.