why a non root user call getenv on an exported variable returns nil

C code here:

#include <stdio.h>
#include <stdlib.h>

int main () {
   printf("PATH : %sn", getenv("PATH"));
   printf("HOME : %sn", getenv("HOME"));
   printf("ROOT : %sn", getenv("ROOT"));
   printf("TMPDIR : %sn", getenv("TMPDIR"));

after doing:

gcc env.c -o printenv
setcap 'cap_dac_override+eip' printenv
sudo -S su -s $(which bash) steve
export TMDIR=hello

I got this output:

PATH : /sbin:/bin:/usr/sbin:/usr/bin
HOME : /home/steve
ROOT : (null)
TMPDIR : (null)

If I remove the CAP set to ‘printenv’ the output is:

PATH : /sbin:/bin:/usr/sbin:/usr/bin
HOME : /home/steve
ROOT : (null)
TMPDIR : hello

How could this be?

After some searching, I found this: http://polarhome.com/service/man/?qf=secure_getenv&tf=2&of=RedHat&sf=

It mentions that it might be due to when capabilities are set getenv becomes secure_getenv therefore all getenv() lib calls return nil, However in that case how come PATH and HOME environment variables are printed?

Asked By: Steve Wu


OK, after some digging I found out the reason behind this. "TMPDIR" is among those special variables that ld. so ignores when CAP is set and the running user is non-root for security concerns. For more details please see the man page of ld. so: https://man7.org/linux/man-pages/man8/ld.so.8.html.

ENVIRONMENT         top
       Various environment variables influence the operation of the
       dynamic linker.

   Secure-execution mode
       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:
       TMPDIR, and TZDIR.

       A binary is executed in secure-execution mode if the AT_SECURE
       entry in the auxiliary vector (see getauxval(3)) has a nonzero
       value.  This entry may have a nonzero value for various reasons,

       *  The process's real and effective user IDs differ, or the real
          and effective group IDs differ.  This typically occurs as a
          result of executing a set-user-ID or set-group-ID program.

       *  A process with a non-root user ID executed a binary that
          conferred capabilities to the process.

       *  A nonzero value may have been set by a Linux Security Module.

Answered By: Steve Wu
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.