linux process with any capabilities will fail when invoke getenv() system call
This is a copy of code9016 at https://unix.stackexchange.com/questions/588572/linux-capabilities-to-read-environment-variables.
copy here to avoid it was droped.
Thank code9016's research.
I'd like to run a service as a non-privileged user, but it needs to bind to a system port number (i.e. less than 1024), so I give it setcap 'cap_net_bind_service=+ep' <path for service>
, all good.
Problem is, on startup, the service reads environment vars and for some reason it can't do that when it has cap_net_bind_service
. So, with two copies of the executable, one with cap_net_bind_service
, one without, only the one without can read environment vars.
It's as though there's a default set of capabilities that allows reading env vars, but the exe loses that capability when I give it cap_net_bind_service
. Is that right, or is something else going on? What additional capability might I need to give to the service so that it can read env vars? There's nothing in capability.h that jumps out as being "allow env var reading"?
Answer:
In brief, the binary is using secure_getenv
to access environment variables. This returns null
, instead of accessing the variables, when the binary is run in "secure execution" mode (AT_SECURE=1
). Having any capability set, causes it to run in this mode.
Confirm that the binary is using secure_getenv
using readelf
:
readelf -a <path for service> | grep getenv
00000040ac28 004b00000007 R_X86_64_JUMP_SLO 0000000000000000 secure_getenv@GLIBC_2.17 + 0
00000040ad90 007a00000007 R_X86_64_JUMP_SLO 0000000000000000 getenv@GLIBC_2.2.5 + 0
75: 0000000000000000 0 FUNC GLOBAL DEFAULT UND secure_getenv@GLIBC_2.17 (6)
122: 0000000000000000 0 FUNC GLOBAL DEFAULT UND getenv@GLIBC_2.2.5 (2)
Confirm that it's running in secure execution mode with environment variables (how ironic!) LD_DEBUG=all
and/or LD_SHOW_AUXV
(see man ld.so
).
If it isn't then LD_SHOW_AUXV
produces output with AT_SECURE
set to 0. There is no output from LD_SHOW_AUXV
when it is running in secure execution mode.
Normally, there is/isn't output from LD_DEBUG
too when it is/isn't running in secure execution mode. However, if /etc/suid-debug
is present (empty file, create with touch), then LD_DEBUG
will produce output when running in secure execution mode.
See man getauxval
for more information about AT_SECURE
and secure execution mode.