Austin Group Defect Tracker

Aardvark Mark IV

Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000922 [1003.1(2013)/Issue7+TC1] System Interfaces Editorial Clarification Requested 2015-02-11 10:08 2022-06-17 08:52
Reporter Florian Weimer View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Applied  
Name Florian Weimer
Organization Red Hat
User Reference
Section 8.1 Environment Variable Definition
Page Number [^]
Line Number 141
Interp Status ---
Final Accepted Text Note: 0005844
Summary 0000922: Implementations should be allowed to change/remove implementation-defined environment variables
Description Most implementations treat some implementation-defined environment variables in special ways and remove or reset them as part of the initialization of a SUID/SGID process image. The standard is currently not clear whether this is permitted, although it is required to prevent security defects in applications from materializing, which means that implementations are more or less forced to behave in the current way.
Desired Action Add the following clarification to the environment setup:

“If the set-user-ID or set-group-ID mode bit of the new process image file is set, implementations may change or remove variables from the environment of the new process, and functions in the System Interfaces volume may ignore the values of environment variables.”
Tags issue8
Attached Files

- Relationships

-  Notes
dalias (reporter)
2015-02-13 18:45

While there is some historical precedent for this, it has always been non-conforming and its value as a security measure is questionable. I would prefer that this change not be made.

If a program has been invoked with the setuid/setgid bits set, the implementation is of course free to ignore (or restrict the interpretation of) implementation-defined environment variables and may even limit the interpretation of some standard variables (like TZ), for itself. There is little value however in stripping them from the environment, because such a program cannot safely run further programs that were not designed to be invoked setuid/setgid unless the application manually provides a new, safe environment (possibly copying some variables from its own environment, but with a whitelist approach, not a blacklist approach).
eblake (manager)
2015-04-30 15:39

Another thing to consider is glibc's secure_getenv(), which puts the burden on an application that is sometimes run with privileges to audit which environment probes it leaves alone, and which environment probes it ignores when run securely. One benefit of secure_getenv() is that the environment is unchanged, so if the setuid app drops privileges before forking a child, the child can use the original environment. A drawback is that each application that wants to use it must be audited for which variables to use it on.
eblake (manager)
2015-04-30 16:10

Current list dropped by glibc (from;a=blob;f=sysdeps/generic/unsecvars.h;h=d5b8119c9cb5cf5f1391325282287c5935c86589;hb=HEAD [^] and;a=blob;f=sysdeps/unix/sysv/linux/i386/dl-librecon.h;h=687ac3035938c0a3a45cf729f0eba3df86e92c3e;hb=HEAD [^] ):

/* Environment variable to be removed for SUID programs. The names are
   2 all stuffed in a single string which means they have to be terminated
   3 with a '\0' explicitly. */
   4 #define UNSECURE_ENVVARS \
   5 "GCONV_PATH\0" \
   6 "GETCONF_DIR\0" \
   7 "HOSTALIASES\0" \
   8 "LD_AUDIT\0" \
   9 "LD_DEBUG\0" \
  10 "LD_DEBUG_OUTPUT\0" \
  11 "LD_DYNAMIC_WEAK\0" \
  12 "LD_LIBRARY_PATH\0" \
  13 "LD_ORIGIN_PATH\0" \
  14 "LD_PRELOAD\0" \
  15 "LD_PROFILE\0" \
  16 "LD_SHOW_AUXV\0" \
  17 "LD_USE_LOAD_BIAS\0" \
  18 "LOCALDOMAIN\0" \
  19 "LOCPATH\0" \
  20 "MALLOC_TRACE\0" \
  21 "NIS_PATH\0" \
  22 "NLSPATH\0" \
  24 "RES_OPTIONS\0" \
  25 "TMPDIR\0" \
  26 "TZDIR\0"

  56 /* Extra unsecure variables. The names are all stuffed in a single
  57 string which means they have to be terminated with a '\0' explicitly. */
philip-guenther (reporter)
2015-09-04 18:15

The status email says:
> Action on Eric: propose wording for Issue 8 to add secure_getenv(),
> and make it clear that deleting from environment without explicit
> request is not compliant, but ignoring is fine.

Implementations have environment variables that are not safe to blindly pass across security boundaries. The canonical example is, of course, LD_LIBRARY_PATH, though may others have been created by various implementations.

It sounds like the committee is saying that implementation MUST pass those across the suid/sgid security boundary. How and by whom will they be blocked? Is the committee suggesting that each suid/sgid application that ever execs a non-suid/sgid application must somehow determine the list of environment variables used by the implementation and manually delete them? That'll have to be a *runtime* determination, of course, to support OS upgrades creating more such environment variables.

APIs to do that don't exist.

Existing suid/sgid applications don't call those non-existent APIs, obviously, and instead have guessed-at hardcoded lists, or just trust the implementation to do The Right Thing and delete the variables that are dangerous in that implementation.

Lacking any plan on how the POSIX software ecosystem could ever *believably* get to a state where suid/sgid applications will *correctly* and *reliably* do this for themselves, the suggestion from the committee that implementations MUST pass all environment variables through is folly and will certainly not be adopted by OpenBSD.
dalias (reporter)
2015-09-04 18:34

Regarding note 0002810, stripping these variables is neither correct nor sufficient for security.

There are three cases to consider:

1. The suid/sgid application has dropped its elevated privileges and is running an external program on the behalf of the user who invoked it. In this case, the right behavior is to honor any environment variables that user may have set, including "dangerous" things like LD_LIBRARY_PATH or LD_PRELOAD. Failure to do so is functional breakage (and is non-conforming).

2. The suid/sgid application is executing an external program with the same elevated privileges it was invoked with (2a), or fully elevated privileges (2b, real id escalated to effective id). In case 2a, for environment variables meaningful to the implementation (like LD_*), they will be ignored by the same logic that ignored them in the original application: real/effective id mismatch or some other implementation-specific mechanism. Of course, this usage is inherently unsafe anyway if the program being invoked was not designed to be invoked with mismatching real/effective ids. In either case 2a or 2b, however, passing any environment variables (not just implementation-defined ones) that were under the control of the invoking user is unsafe, because they might be interpreted by the application (directly or via third-party library code).

The only safe way to exec or posix_spawn from a suid/sgid program without dropping privileges is to completely sanitize the invoking-user-controlled environmental state, which includes the environment variables and a lot more. This should be done by passing a completely new environment array to execve or posix_spawn rather than using the suid/sgid application's environ.
geoffclare (manager)
2022-05-26 15:17
edited on: 2022-05-26 15:20

Page and line numbers are for Issue 8 draft 2.1

After page 156 line 5406 section 8.1 Environment Variable Definition, add:
Implementations may ignore some environment variables at the point of use for security reasons, for example in programs whose real and effective user IDs or real and effective group IDs were not equal at program startup. The behavior shall be as if the implementation obtains the values for these environment variables using secure_getenv() instead of getenv() (see [xref to getenv()]); they shall not be removed from the environment of affected processes and shall be inherited as required by this standard.

After page 358 line 12432 section <stdlib.h>, add:
[CX]char *secure_getenv(const char *);[/CX]

On page 501 line 17742 section 2.9.1, change:
the getenv() function and
the getenv() and secure_getenv() functions and

On page 774 line 26454 section exec, and
page 3691 line 127760 section E.1, change:
getenv(), secure_getenv()

On page 1022 line 35036 section getenv(), change:
getenv, secure_getenv

After page 1022 line 35039 section getenv(), add:
[CX]char *secure_getenv(const char *name);[/CX]

After page 1022 line 35054 section getenv(), add:
[CX]The secure_getenv() function shall be equivalent to getenv(), except that it shall return a null pointer if the calling process does not meet all of the following security criteria:

  1. The effective user ID and real user ID of the calling process were equal during program startup.

  2. The effective group ID and real group ID of the calling process were equal during program startup.

  3. Additional implementation-defined security criteria.

  4. [/CX]

After page 1022 line 35058 section getenv(), add:
[CX]Upon successful completion, secure_getenv() shall return a pointer to a string containing the value for the specified name. If the specified name cannot be found in the environment of the calling process, or the calling process does not meet the security criteria listed in DESCRIPTION, a null pointer shall be returned.[/CX]

After page 1790, sched_yield() entry, insert secure_getenv() pointer page to getenv()

After page 3457 line 118185 section A.8.1, add:
Some historical implementations removed certain environment variables during program startup when security criteria were not met, instead of just ignoring them at the point of use. The standard developers decided not to allow this behavior because if a process drops all privileges and sets its effective user and group IDs to be the same as its real user and group IDs before executing a program or utility, the behavior should be the same as if the process had originally met the security criteria.

- Issue History
Date Modified Username Field Change
2015-02-11 10:08 Florian Weimer New Issue
2015-02-11 10:08 Florian Weimer Name => Florian Weimer
2015-02-11 10:08 Florian Weimer Organization => Red Hat
2015-02-11 10:08 Florian Weimer Section => 8.1 Environment Variable Definition
2015-02-11 10:08 Florian Weimer Page Number => [^]
2015-02-11 10:08 Florian Weimer Line Number => 141
2015-02-11 10:08 Florian Weimer Issue Monitored: Florian Weimer
2015-02-13 18:45 dalias Note Added: 0002546
2015-04-30 15:39 eblake Note Added: 0002643
2015-04-30 16:10 eblake Note Added: 0002644
2015-09-04 18:15 philip-guenther Note Added: 0002810
2015-09-04 18:34 dalias Note Added: 0002811
2022-05-26 15:17 geoffclare Note Added: 0005844
2022-05-26 15:18 geoffclare Interp Status => ---
2022-05-26 15:18 geoffclare Final Accepted Text => Note: 0005844
2022-05-26 15:18 geoffclare Status New => Resolved
2022-05-26 15:18 geoffclare Resolution Open => Accepted As Marked
2022-05-26 15:18 geoffclare Tag Attached: issue8
2022-05-26 15:19 geoffclare Note Edited: 0005844
2022-05-26 15:20 geoffclare Note Edited: 0005844
2022-06-17 08:52 geoffclare Status Resolved => Applied

Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker