Bug 17100

Summary: secure_getenv() does not seem to properly detect if an environment is secure
Product: glibc Reporter: Brent Cook <busterb>
Component: libcAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal CC: drepper.fsp, fweimer
Priority: P2 Flags: fweimer: security-
Version: 2.19   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Brent Cook 2014-06-29 03:16:36 UTC
Until getauxval(AT_SECURE) was added, there did not appear to be a good way to detect if a process is running setuid/setgid or not. You can find various discussions about how to implement the BSD issetugid() function on Linux for reference.

Checks like (uid==euid||gid==egid) can fail in various ways, e.g. it cannot detect if a process has changed its uid/gid back, it is racy in multi-threaded contexts, among other issues. I think that future glibc versions should only use AT_SECURE, removing the getuid/geteuid check. If AT_SECURE is unavailable, just assume the worst.

<snip>
     case AT_SECURE:
   seen = -1;
   __libc_enable_secure = av->a_un.a_val;
   __libc_enable_secure_decided = 1;

<snip>
__libc_init_secure (void)
{
 if (__libc_enable_secure_decided == 0)
   __libc_enable_secure = (__geteuid () != __getuid ()
               || __getegid () != __getgid ());
}

<snip>
char *
__libc_secure_getenv (name)
    const char *name;
{
 return __libc_enable_secure ? NULL : getenv (name);
}
Comment 1 Andreas Schwab 2014-06-29 07:40:23 UTC
__libc_enable_secure is computed by the libc initializer before any application code is run.  No multi threading, no setuid/setgid calls.
Comment 2 jsm-csl@polyomino.org.uk 2014-06-29 11:55:12 UTC
On Sun, 29 Jun 2014, busterb at gmail dot com wrote:

> contexts, among other issues. I think that future glibc versions should only
> use AT_SECURE, removing the getuid/geteuid check. If AT_SECURE is unavailable,
> just assume the worst.

AT_SECURE is always available, since we removed support for pre-2.6 
kernels.
Comment 3 Florian Weimer 2014-06-29 12:17:08 UTC
Should we add a check which aborts if AT_SECURE is not present?  Beyond that, there isn't anything libc can do here.
Comment 4 Brent Cook 2014-06-29 13:36:02 UTC
Thank you for the clarification.

Though AT_SECURE is available in all kernels that glibc supports, is there be any way for an adversary to cause the fallback case to be triggered through external means?

That there is a fallback case is a little misleading since it does not also perform the capabilities checks that the kernel does, so I don't think one would want it to inadvertently execute on any kernel that implements capabilities:

http://lxr.free-electrons.com/source/security/commoncap.c#L590
Comment 5 Florian Weimer 2014-06-29 13:52:28 UTC
(In reply to Brent Cook from comment #4)
> Though AT_SECURE is available in all kernels that glibc supports, is there
> be any way for an adversary to cause the fallback case to be triggered
> through external means?

No, the kernel prepares the aux vector as part of the execve implementation.  It is possible to invoke the new process through userspace emulation, supplying a bogus aux vector, but then, no privilege transition occurs, so there is no security impact.
Comment 6 Brent Cook 2014-06-29 14:04:16 UTC
So at worst, the fallback case is a vestigial tail?

It would seem to be ready for the chopping block if so.
Comment 7 jsm-csl@polyomino.org.uk 2014-06-29 15:20:03 UTC
elf/enbl-secure.c is used on Hurd as well as Linux, but I suppose that 
part of the code ought to be disabled if HAVE_AUX_SECURE.