It's observed that when running a program having setuid bit set, it won't receive some environment variables set on the shell (bash etc.). Several environment variables which get removed this way are LD_PRELOAD, LD_LIBRARY_PATH, LD_ORIGIN_PATH, LD_DEBUG_OUTPUT, LD_PROFILE, LD_USE_LOAD_BIAS, GCONV_PATH.

As mentioned in here and in this question, this is the intended behavior. Reason for this is to reduce attack vector. Manual page of ld.so (8) also states this.

The question is, which component of a Linux OS removes environment variables like this?

  • Is it the shell?
  • Is it a function like fork() or execve() etc. a shell calls internally when executing a command?
  • Is it the ld.so?

Note: any answer will be helpful. However, if you can direct me to which resources contain information on this matter, like which manual pages should I read, it would be more helpful.


1 Answer 1


Most of these variables are intended for the dynamic linker, or other components of the C library, and it’s the dynamic linker which takes care of removing them when starting setuid binaries. This is documented in the “ENVIRONMENT” section of man ld.so (for the GNU C library):

For security reasons, if the dynamic linker determines that a binary should be run in secure-execution mode, the effects of some environment variables are voided or modified, and furthermore those environment variables are stripped from the environment, so that the program does not even see the definitions. Some of these environment variables affect the operation of the dynamic linker itself, and are described below. Other environment variables treated in this way include: GCONV_PATH, GETCONF_DIR, HOSTALIASES, LOCALDOMAIN, LOCPATH, MALLOC_TRACE, NIS_PATH, NLSPATH, RESOLV_HOST_CONF, RES_OPTIONS, TMPDIR, and TZDIR.

The ld.so-affecting variables are documented individually:

This variable is ignored in secure-execution mode.

appears in the documentation for each such variable.

The full list can also be seen in the GNU C library’s source code, as can the removal code itself, both for dynamically-linked binaries and for dynamic linking in statically-linked binaries.

Other C libraries’ dynamic linkers behave in a similar fashion, for variables which they care about; for example, musl documents that

This variable is completely ignored in programs invoked setuid, setgid, or with other elevated capabilities.

for a number of variables (LD_PRELOAD, LD_LIBRARY_PATH, MUSL_LOCPATH), and that some features of the TZ variable aren’t available in such circumstances.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .