-
-
Notifications
You must be signed in to change notification settings - Fork 193
how to run setcap on python executable #576
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
Comments
That's an error message I haven't seen before and a failure mode I didn't realize was possible! We want to use $ORIGIN in DT_NEEDED because it is the least bad approach for portability. Your patchelf workaround seems reasonable. But undesirable. Definitely not turnkey. This issue feels like yet more justification for statically linking libpython... |
Apparently the glibc dynamic loader straight up refuses dynamic token expansion in DT_NEEDED for setuid/setgid binaries. That error message and logic originates from a commit in 1999! |
Yeah, this is defensible on glibc's part because historically you can hardlink to a binary you don't own, so some other user on the machine could make a hardlink in a directory they control, meaning that Agree re statically linking libpython into the python3 binary - I'll ping here once I have something for you to try. However, since you're granting caps to a Python interpreter which can then run arbitrary code I wonder if you'd be happier with a system design where the user has ambient It appears that you can install libpam-cap, add
to the end of your PAM stack (e.g. /etc/pam.d/common-auth on Debian/Ubuntu, on some distros it might need to be in a file in /etc/pam.d/ named after the specific login program), and add
(or See full docs here. (I have not tried this in production because it was very new functionality the last time I wanted it, so please test it out and make sure it works the way you expect, but it's definitely what I would have reached for if it were available!) Also - note that by default on many UNIX systems ~/.local/share/ is readable by other users, so if you take the file capabilities approach, you're allowing everyone on the system to use this Python interpreter for raw socket access. If that's a concern for you, you may want to either change ~/.local/share/uv/ (or some parent directory, possibly just ~) to be mode 700, or take the ambient capabilities approach. |
@geofft : wow, thanks for a very thorough reply. it seems like the libcam-cap route is the best way forward for us. on the latest raspberry pi os (based on debian bookworm), with
combined with is it even possible? |
We ran into the same issue, using |
Even though the Python interpreter no longer needs libpython3.x.so, it turns out some extension modules (incorrectly) do, and miraculously, allowing them to find libpython3.x.so doesn't actually break things, for reasons detailed in the comment. So set an rpath that allows libpython3.x.so to be loaded if needed by some other library, even though we won't use that ourselves. Note that this change does not risk users who want to make bin/python3 setuid or setcap (e.g. astral-sh#576); while the rpath is presumably ignored for privileged binaries, there is no error message, and the binary launches fine, and _because_ we do not need the rpath in order for the interpreter to work, everything (except these misbuilt extension modules) works.
Even though the Python interpreter no longer needs libpython3.x.so, it turns out some extension modules (incorrectly) do, and miraculously, allowing them to find libpython3.x.so doesn't actually break things, for reasons detailed in the comment. So set an rpath that allows libpython3.x.so to be loaded if needed by some other library, even though we won't use that ourselves. We are already doing this on musl; do it on glibc too. Note that this change does not risk users who want to make bin/python3 setuid or setcap (e.g. astral-sh#576); while the rpath is presumably ignored for privileged binaries, there is no error message, and the binary launches fine, and _because_ we do not need the rpath in order for the interpreter to work, everything (except these misbuilt extension modules) works.
Even though the Python interpreter no longer needs libpython3.x.so, it turns out some extension modules (incorrectly) do, and miraculously, allowing them to find libpython3.x.so doesn't actually break things, for reasons detailed in the comment. So set an rpath that allows libpython3.x.so to be loaded if needed by some other library, even though we won't use that ourselves. We are already doing this on musl; do it on glibc too. Note that this change does not risk users who want to make bin/python3 setuid or setcap (e.g. #576); while the rpath is presumably ignored for privileged binaries, there is no error message, and the binary launches fine, and _because_ we do not need the rpath in order for the interpreter to work, everything (except these misbuilt extension modules) works.
Earlier this week we shipped a version of python-build-standalone that statically links libpython (#592), so it does not use an To upgrade do
(note that this will clobber your existing patchelf'd binary) If I get some downtime I'll see if I can actually set up the libpam-cap example on a Pi image, I would have expected it to work but as mentioned I haven't done it in prod. Also, @Zoltag, while I 100% agree that changing your infrastructure to use high ports is a better solution for many reasons, another thing you can consider is to lower /proc/sys/net/ipv4/ip_unprivileged_port_start to 80 or lower. I have actually done this in prod at a large company, and we chose to set this to 26, which still protects SSH on 22 and SMTP on 25. I think it's technically possible to set it to zero, too. This is a sysctl, so you can set it via |
Hi, @geofft Thanks for your feedback. I have completed the initial update to migrate the first system to higher level port numbers, but took the time this morning to test your update. Running |
Hm, the error message you're getting in that first screenshot means the version of Python you're getting is (probably) the one from uv 0.7.5 or below. Can you double-check whether you need a |
Reopening because uv 0.7.8 reverted the static linking changes that would have made this work, but also I am going to take a look at why this doesn't seem to be working for you even with 0.7.7. |
Uh oh!
There was an error while loading. Please reload this page.
we're having some special requirements. we're using the pysoem library to communicate with ethercat devices. this means that the python executable needs
cap_net_raw+ep
capability, which can be achieved by runningsudo setcap cap_net_raw+ep /path/to/python
.this works fine with the system python, but when setting it on the
uv
provided python executable:i get this when i then try to run python:
if i run this:
it works (after re-running
setcap
), so it seems to be related to the relative path. and sure, from a security point of view i can understand why that may be problematic.i found this:
python-build-standalone/cpython-unix/build-cpython.sh
Lines 684 to 697 in f0abfc9
which is probably what causes this. but what is the right forward here? running pop!_os 22.04 lts (based on ubuntu 24.04) amd64
The text was updated successfully, but these errors were encountered: