1/* $NetBSD: issuid.c,v 1.2 2017/01/28 21:31:50 christos Exp $ */ 2 3/* 4 * Copyright (c) 1998 - 2001 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <config.h> 37 38#ifdef HAVE_SYS_AUXV_H 39#include <sys/auxv.h> 40#endif 41 42#include <errno.h> 43 44#include <krb5/roken.h> 45 46/* NetBSD calls AT_UID AT_RUID. Everyone else calls it AT_UID. */ 47#if defined(AT_EUID) && defined(AT_RUID) && !defined(AT_UID) 48#define AT_UID AT_RUID 49#endif 50#if defined(AT_EGID) && defined(AT_RGID) && !defined(AT_GID) 51#define AT_GID AT_RGID 52#endif 53 54#ifdef __GLIBC__ 55#ifdef __GLIBC_PREREQ 56#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) __GLIBC_PREREQ(maj, min) 57#else 58#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) \ 59 ((__GLIBC << 16) + GLIBC_MINOR >= ((maj) << 16) + (min)) 60#endif 61 62#if HAVE_GLIBC_API_VERSION_SUPPORT(2, 19) 63#define GETAUXVAL_SETS_ERRNO 64#endif 65#endif 66 67#ifdef HAVE_GETAUXVAL 68static unsigned long 69rk_getauxval(unsigned long type) 70{ 71 errno = 0; 72#ifdef GETAUXVAL_SETS_ERRNO 73 return getauxval(type); 74#else 75 unsigned long ret = getauxval(type); 76 77 if (ret == 0) 78 errno = ENOENT; 79 return ret; 80#endif 81} 82#define USE_RK_GETAUXVAL 83#endif 84 85/** 86 * Returns non-zero if the caller's process started as set-uid or 87 * set-gid (and therefore the environment cannot be trusted). 88 * 89 * @return Non-zero if the environment is not trusted. 90 */ 91ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 92issuid(void) 93{ 94 /* 95 * We want to use issetugid(), but issetugid() is not the same on 96 * all OSes. 97 * 98 * On Illumos derivatives, OpenBSD, and Solaris issetugid() returns 99 * true IFF the program exec()ed was set-uid or set-gid. 100 * 101 * On NetBSD and FreeBSD issetugid() returns true if the program 102 * exec()ed was set-uid or set-gid, or if the process has switched 103 * UIDs/GIDs or otherwise changed privileges or is a descendant of 104 * such a process and has not exec()ed since. 105 * 106 * What we want here is to know only if the program exec()ed was 107 * set-uid or set-gid, so we can decide whether to trust the 108 * enviroment variables. We don't care if this was a process that 109 * started as root and later changed UIDs/privs whatever: since it 110 * started out as privileged, it inherited an environment from a 111 * privileged pre-exec self, and so on, so the environment is 112 * trusted. 113 * 114 * Therefore the FreeBSD/NetBSD issetugid() does us no good. 115 * 116 * Linux, meanwhile, has no issetugid() (at least glibc doesn't 117 * anyways). 118 * 119 * Systems that support ELF put an "auxilliary vector" on the stack 120 * prior to starting the RTLD, and this vector includes (optionally) 121 * information about the process' EUID, RUID, EGID, RGID, and so on 122 * at the time of exec(), which we can use to construct proper 123 * issetugid() functionality. 124 * 125 * Where available, we use the ELF auxilliary vector as a fallback 126 * if issetugid() is not available. 127 * 128 * All of this is as of late March 2015, and might become stale in 129 * the future. 130 */ 131 132#ifdef USE_RK_GETAUXVAL 133 /* If we have getauxval(), use that */ 134 135#if (defined(AT_EUID) && defined(AT_UID) || (defined(AT_EGID) && defined(AT_GID))) 136 int seen = 0; 137#endif 138 139#if defined(AT_EUID) && defined(AT_UID) 140 { 141 unsigned long euid; 142 unsigned long uid; 143 144 euid = rk_getauxval(AT_EUID); 145 if (errno == 0) 146 seen |= 1; 147 uid = rk_getauxval(AT_UID); 148 if (errno == 0) 149 seen |= 2; 150 if (euid != uid) 151 return 1; 152 } 153#endif 154#if defined(AT_EGID) && defined(AT_GID) 155 { 156 unsigned long egid; 157 unsigned long gid; 158 159 egid = rk_getauxval(AT_EGID); 160 if (errno == 0) 161 seen |= 4; 162 gid = rk_getauxval(AT_GID); 163 if (errno == 0) 164 seen |= 8; 165 if (egid != gid) 166 return 2; 167 } 168#endif 169#ifdef AT_SECURE 170 /* AT_SECURE is set if the program was set-id. */ 171 if (rk_getauxval(AT_SECURE) != 0) 172 return 1; 173#endif 174 175#if (defined(AT_EUID) && defined(AT_UID) || (defined(AT_EGID) && defined(AT_GID))) 176 if (seen == 15) 177 return 0; 178#endif 179 180 /* rk_getauxval() does set errno */ 181 if (errno == 0) 182 return 0; 183 /* 184 * Fall through if we have getauxval() but we didn't have (or don't 185 * know if we don't have) the aux entries that we needed. 186 */ 187#endif /* USE_RK_GETAUXVAL */ 188 189#if defined(HAVE_ISSETUGID) 190 /* 191 * If we have issetugid(), use it. 192 * 193 * We may lose on some BSDs. This manifests as, for example, 194 * gss_store_cred() not honoring KRB5CCNAME. 195 */ 196 return issetugid(); 197#endif /* USE_RK_GETAUXVAL */ 198 199 /* 200 * Paranoia: for extra safety we ought to default to returning 1. 201 * But who knows what that might break where users link statically 202 * and use a.out, say. Also, on Windows we should always return 0. 203 * 204 * For now we stick to returning zero by default. 205 */ 206 207#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) 208 if (getuid() != geteuid()) 209 return 1; 210#endif 211#if defined(HAVE_GETGID) && defined(HAVE_GETEGID) 212 if (getgid() != getegid()) 213 return 2; 214#endif 215 216 return 0; 217} 218