Use getauxval() for issuid() on Linux
This commit is contained in:
@@ -71,6 +71,7 @@ AC_CHECK_HEADERS([\
|
|||||||
search.h \
|
search.h \
|
||||||
shadow.h \
|
shadow.h \
|
||||||
stdint.h \
|
stdint.h \
|
||||||
|
sys/auxv.h \
|
||||||
sys/bswap.h \
|
sys/bswap.h \
|
||||||
sys/errno.h \
|
sys/errno.h \
|
||||||
sys/ioctl.h \
|
sys/ioctl.h \
|
||||||
@@ -184,6 +185,7 @@ AC_CHECK_FUNCS([ \
|
|||||||
asprintf \
|
asprintf \
|
||||||
atexit \
|
atexit \
|
||||||
cgetent \
|
cgetent \
|
||||||
|
getauxval \
|
||||||
getconfattr \
|
getconfattr \
|
||||||
getprogname \
|
getprogname \
|
||||||
getrlimit \
|
getrlimit \
|
||||||
|
@@ -33,24 +33,183 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_AUXV_H
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "roken.h"
|
#include "roken.h"
|
||||||
|
|
||||||
|
/* NetBSD calls AT_UID AT_RUID. Everyone else calls it AT_UID. */
|
||||||
|
#if defined(AT_EUID) && defined(AT_RUID) && !defined(AT_UID)
|
||||||
|
#define AT_UID AT_RUID
|
||||||
|
#endif
|
||||||
|
#if defined(AT_EGID) && defined(AT_RGID) && !defined(AT_GID)
|
||||||
|
#define AT_GID AT_RGID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
#ifdef __GLIBC_PREREQ
|
||||||
|
#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) __GLIBC_PREREQ(maj, min)
|
||||||
|
#else
|
||||||
|
#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) \
|
||||||
|
((__GLIBC << 16) + GLIBC_MINOR >= ((maj) << 16) + (min))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_GLIBC_API_VERSION_SUPPORT(2, 19)
|
||||||
|
#define GETAUXVAL_SETS_ERRNO
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_GETAUXVAL
|
||||||
|
static unsigned long
|
||||||
|
rk_getauxval(unsigned long type)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
#ifdef GETAUXVAL_SETS_ERRNO
|
||||||
|
return getauxval(type);
|
||||||
|
#else
|
||||||
|
unsigned long ret = getauxval(type);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
errno = ENOENT;
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#define USE_RK_GETAUXVAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns non-zero if the caller's process started as set-uid or
|
||||||
|
* set-gid (and therefore the environment cannot be trusted).
|
||||||
|
*
|
||||||
|
* @return Non-zero if the environment is not trusted.
|
||||||
|
*/
|
||||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||||
issuid(void)
|
issuid(void)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* We want to use issetugid(), but issetugid() is not the same on
|
||||||
|
* all OSes.
|
||||||
|
*
|
||||||
|
* On Illumos derivatives, OpenBSD, and Solaris issetugid() returns
|
||||||
|
* true IFF the program exec()ed was set-uid or set-gid.
|
||||||
|
*
|
||||||
|
* On NetBSD and FreeBSD issetugid() returns true if the program
|
||||||
|
* exec()ed was set-uid or set-gid, or if the process has switched
|
||||||
|
* UIDs/GIDs or otherwise changed privileges or is a descendant of
|
||||||
|
* such a process and has not exec()ed since.
|
||||||
|
*
|
||||||
|
* What we want here is to know only if the program exec()ed was
|
||||||
|
* set-uid or set-gid, so we can decide whether to trust the
|
||||||
|
* enviroment variables. We don't care if this was a process that
|
||||||
|
* started as root and later changed UIDs/privs whatever: since it
|
||||||
|
* started out as privileged, it inherited an environment from a
|
||||||
|
* privileged pre-exec self, and so on, so the environment is
|
||||||
|
* trusted.
|
||||||
|
*
|
||||||
|
* Therefore the FreeBSD/NetBSD issetugid() does us no good.
|
||||||
|
*
|
||||||
|
* Linux, meanwhile, has no issetugid() (at least glibc doesn't
|
||||||
|
* anyways).
|
||||||
|
*
|
||||||
|
* Systems that support ELF put an "auxilliary vector" on the stack
|
||||||
|
* prior to starting the RTLD, and this vector includes (optionally)
|
||||||
|
* information about the process' EUID, RUID, EGID, RGID, and so on
|
||||||
|
* at the time of exec(), which we can use to construct proper
|
||||||
|
* issetugid() functionality.
|
||||||
|
*
|
||||||
|
* Where available, we use the ELF auxilliary vector as a fallback
|
||||||
|
* if issetugid() is not available.
|
||||||
|
*
|
||||||
|
* All of this is as of late March 2015, and might become stale in
|
||||||
|
* the future.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_RK_GETAUXVAL
|
||||||
|
/* If we have getauxval(), use that */
|
||||||
|
|
||||||
|
#if (defined(AT_EUID) && defined(AT_UID) || (defined(AT_EGID) && defined(AT_GID)))
|
||||||
|
int seen = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AT_EUID) && defined(AT_UID)
|
||||||
|
{
|
||||||
|
unsigned long euid;
|
||||||
|
unsigned long uid;
|
||||||
|
|
||||||
|
euid = rk_getauxval(AT_EUID);
|
||||||
|
if (errno == 0)
|
||||||
|
seen |= 1;
|
||||||
|
uid = rk_getauxval(AT_UID);
|
||||||
|
if (errno == 0)
|
||||||
|
seen |= 2;
|
||||||
|
if (euid != uid)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(AT_EGID) && defined(AT_GID)
|
||||||
|
{
|
||||||
|
unsigned long egid;
|
||||||
|
unsigned long gid;
|
||||||
|
|
||||||
|
egid = rk_getauxval(AT_EGID);
|
||||||
|
if (errno == 0)
|
||||||
|
seen |= 4;
|
||||||
|
gid = rk_getauxval(AT_GID);
|
||||||
|
if (errno == 0)
|
||||||
|
seen |= 8;
|
||||||
|
if (egid != gid)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef AT_SECURE
|
||||||
|
/* AT_SECURE is set if the program was set-id. */
|
||||||
|
if (rk_getauxval(AT_SECURE) != 0)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(AT_EUID) && defined(AT_UID) || (defined(AT_EGID) && defined(AT_GID)))
|
||||||
|
if (seen == 15)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* rk_getauxval() does set errno */
|
||||||
|
if (errno == 0)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* Fall through if we have getauxval() but we didn't have (or don't
|
||||||
|
* know if we don't have) the aux entries that we needed.
|
||||||
|
*/
|
||||||
|
#endif /* USE_RK_GETAUXVAL */
|
||||||
|
|
||||||
#if defined(HAVE_ISSETUGID)
|
#if defined(HAVE_ISSETUGID)
|
||||||
|
/*
|
||||||
|
* If we have issetugid(), use it.
|
||||||
|
*
|
||||||
|
* We may lose on some BSDs. This manifests as, for example,
|
||||||
|
* gss_store_cred() not honoring KRB5CCNAME.
|
||||||
|
*/
|
||||||
return issetugid();
|
return issetugid();
|
||||||
#else /* !HAVE_ISSETUGID */
|
#endif /* USE_RK_GETAUXVAL */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Paranoia: for extra safety we ought to default to returning 1.
|
||||||
|
* But who knows what that might break where users link statically
|
||||||
|
* and use a.out, say. Also, on Windows we should always return 0.
|
||||||
|
*
|
||||||
|
* For now we stick to returning zero by default.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
|
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
|
||||||
if(getuid() != geteuid())
|
if (getuid() != geteuid())
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_GETGID) && defined(HAVE_GETEGID)
|
#if defined(HAVE_GETGID) && defined(HAVE_GETEGID)
|
||||||
if(getgid() != getegid())
|
if (getgid() != getegid())
|
||||||
return 2;
|
return 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* HAVE_ISSETUGID */
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user