Changeset View
Changeset View
Standalone View
Standalone View
lib/libc/gen/auxv.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | __init_elf_aux_vector(void) | ||||
if (&_DYNAMIC != NULL) | if (&_DYNAMIC != NULL) | ||||
return; | return; | ||||
_once(&aux_vector_once, init_aux_vector_once); | _once(&aux_vector_once, init_aux_vector_once); | ||||
} | } | ||||
static pthread_once_t aux_once = PTHREAD_ONCE_INIT; | static pthread_once_t aux_once = PTHREAD_ONCE_INIT; | ||||
static int pagesize, osreldate, canary_len, ncpus, pagesizes_len; | static int pagesize, osreldate, canary_len, ncpus, pagesizes_len; | ||||
static bool hwcap_present, hwcap2_present; | static bool hwcap_present, hwcap2_present; | ||||
static char *canary, *pagesizes; | static bool execfd_present, stackprot_present; | ||||
static bool egid_present, euid_present, gid_present, uid_present; | |||||
static char *canary, *execpath, *pagesizes; | |||||
static void *timekeep; | static void *timekeep; | ||||
static u_long hwcap, hwcap2; | static u_long hwcap, hwcap2; | ||||
static u_long base, e_hdr, entry, flags; | |||||
static u_long phdr, phent, phnum; | |||||
static u_long egid, euid, gid, uid; | |||||
static int execfd, execpath_len, stackprot; | |||||
static void | static void | ||||
init_aux(void) | init_aux(void) | ||||
{ | { | ||||
Elf_Auxinfo *aux; | Elf_Auxinfo *aux; | ||||
for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { | for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { | ||||
switch (aux->a_type) { | switch (aux->a_type) { | ||||
case AT_BASE: | |||||
base = (u_long)(aux->a_un.a_val); | |||||
break; | |||||
case AT_CANARY: | case AT_CANARY: | ||||
canary = (char *)(aux->a_un.a_ptr); | canary = (char *)(aux->a_un.a_ptr); | ||||
break; | break; | ||||
case AT_CANARYLEN: | case AT_CANARYLEN: | ||||
canary_len = aux->a_un.a_val; | canary_len = aux->a_un.a_val; | ||||
break; | break; | ||||
case AT_EGID: | |||||
egid_present = true; | |||||
egid = aux->a_un.a_val; | |||||
break; | |||||
case AT_EHDRFLAGS: | |||||
e_hdr = (u_long)(aux->a_un.a_val); | |||||
break; | |||||
case AT_ENTRY: | |||||
entry = (u_long)(aux->a_un.a_ptr); | |||||
break; | |||||
case AT_EUID: | |||||
euid_present = true; | |||||
euid = aux->a_un.a_val; | |||||
break; | |||||
case AT_EXECFD: | |||||
execfd_present = true; | |||||
execfd = aux->a_un.a_val; | |||||
break; | |||||
case AT_EXECPATH: | |||||
execpath = (char *)(aux->a_un.a_ptr); | |||||
execpath_len = strlen(execpath) + 1; | |||||
mhorne: Are there any guarantees on execpath being null-terminated? I assumed so here but if that's not… | |||||
break; | |||||
case AT_FLAGS: | |||||
flags = (u_long)(aux->a_un.a_val); | |||||
break; | |||||
case AT_GID: | |||||
gid_present = true; | |||||
gid = aux->a_un.a_val; | |||||
break; | |||||
case AT_HWCAP: | case AT_HWCAP: | ||||
hwcap_present = true; | hwcap_present = true; | ||||
hwcap = (u_long)(aux->a_un.a_val); | hwcap = (u_long)(aux->a_un.a_val); | ||||
break; | break; | ||||
case AT_HWCAP2: | case AT_HWCAP2: | ||||
hwcap2_present = true; | hwcap2_present = true; | ||||
hwcap2 = (u_long)(aux->a_un.a_val); | hwcap2 = (u_long)(aux->a_un.a_val); | ||||
Show All 10 Lines | for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { | ||||
case AT_PAGESIZESLEN: | case AT_PAGESIZESLEN: | ||||
pagesizes_len = aux->a_un.a_val; | pagesizes_len = aux->a_un.a_val; | ||||
break; | break; | ||||
case AT_PAGESZ: | case AT_PAGESZ: | ||||
pagesize = aux->a_un.a_val; | pagesize = aux->a_un.a_val; | ||||
break; | break; | ||||
case AT_PHDR: | |||||
phdr = (u_long)(aux->a_un.a_val); | |||||
break; | |||||
case AT_PHENT: | |||||
phent = (u_long)(aux->a_un.a_val); | |||||
break; | |||||
case AT_PHNUM: | |||||
phnum = (u_long)(aux->a_un.a_val); | |||||
break; | |||||
case AT_OSRELDATE: | case AT_OSRELDATE: | ||||
osreldate = aux->a_un.a_val; | osreldate = aux->a_un.a_val; | ||||
break; | break; | ||||
case AT_STACKPROT: | |||||
stackprot_present = true; | |||||
stackprot = aux->a_un.a_val; | |||||
break; | |||||
case AT_TIMEKEEP: | case AT_TIMEKEEP: | ||||
timekeep = aux->a_un.a_ptr; | timekeep = aux->a_un.a_ptr; | ||||
break; | break; | ||||
case AT_UID: | |||||
uid_present = true; | |||||
uid = aux->a_un.a_val; | |||||
break; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
__weak_reference(_elf_aux_info, elf_aux_info); | __weak_reference(_elf_aux_info, elf_aux_info); | ||||
int | int | ||||
_elf_aux_info(int aux, void *buf, int buflen) | _elf_aux_info(int aux, void *buf, int buflen) | ||||
{ | { | ||||
int res; | int res; | ||||
__init_elf_aux_vector(); | __init_elf_aux_vector(); | ||||
if (__elf_aux_vector == NULL) | if (__elf_aux_vector == NULL) | ||||
return (ENOSYS); | return (ENOSYS); | ||||
_once(&aux_once, init_aux); | _once(&aux_once, init_aux); | ||||
switch (aux) { | switch (aux) { | ||||
case AT_BASE: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (base != 0) { | |||||
*(u_long *)buf = base; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_CANARY: | case AT_CANARY: | ||||
if (canary_len >= buflen) { | if (canary_len >= buflen) { | ||||
if (canary != NULL) { | if (canary != NULL) { | ||||
memcpy(buf, canary, buflen); | memcpy(buf, canary, buflen); | ||||
memset(canary, 0, canary_len); | memset(canary, 0, canary_len); | ||||
canary = NULL; | canary = NULL; | ||||
res = 0; | res = 0; | ||||
} else | } else | ||||
res = ENOENT; | res = ENOENT; | ||||
} else | } else | ||||
res = EINVAL; | res = EINVAL; | ||||
break; | break; | ||||
case AT_CANARYLEN: | |||||
if (buflen >= sizeof(int)) { | |||||
if (canary_len != 0) { | |||||
*(int *)buf = canary_len; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_EGID: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (egid_present) { | |||||
*(u_long *)buf = egid; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_EHDRFLAGS: | |||||
if (buflen >= sizeof(u_long)) { | |||||
*(u_long *)buf = e_hdr; | |||||
res = 0; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_ENTRY: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (entry != 0) { | |||||
*(u_long *)buf = entry; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_EUID: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (euid_present) { | |||||
*(u_long *)buf = euid; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_EXECFD: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (execfd_present) { | |||||
*(u_long *)buf = execfd; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_EXECPATH: | |||||
if (buflen >= execpath_len) { | |||||
if (execpath != NULL) { | |||||
memcpy(buf, execpath, execpath_len); | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_FLAGS: | |||||
if (buflen >= sizeof(u_long)) { | |||||
*(u_long *)buf = flags; | |||||
res = 0; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_GID: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (gid_present) { | |||||
*(u_long *)buf = gid; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_HWCAP: | case AT_HWCAP: | ||||
if (buflen == sizeof(u_long)) { | if (buflen == sizeof(u_long)) { | ||||
if (hwcap_present) { | if (hwcap_present) { | ||||
*(u_long *)buf = hwcap; | *(u_long *)buf = hwcap; | ||||
res = 0; | res = 0; | ||||
} else | } else | ||||
res = ENOENT; | res = ENOENT; | ||||
} else | } else | ||||
Show All 24 Lines | if (pagesizes_len >= buflen) { | ||||
if (pagesizes != NULL) { | if (pagesizes != NULL) { | ||||
memcpy(buf, pagesizes, buflen); | memcpy(buf, pagesizes, buflen); | ||||
res = 0; | res = 0; | ||||
} else | } else | ||||
res = ENOENT; | res = ENOENT; | ||||
} else | } else | ||||
res = EINVAL; | res = EINVAL; | ||||
break; | break; | ||||
case AT_PAGESIZESLEN: | |||||
if (buflen >= sizeof(int)) { | |||||
if (pagesizes_len != 0) { | |||||
*(int *)buf = pagesizes_len; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_PAGESZ: | case AT_PAGESZ: | ||||
if (buflen == sizeof(int)) { | if (buflen == sizeof(int)) { | ||||
if (pagesize != 0) { | if (pagesize != 0) { | ||||
*(int *)buf = pagesize; | *(int *)buf = pagesize; | ||||
res = 0; | res = 0; | ||||
} else | } else | ||||
res = ENOENT; | res = ENOENT; | ||||
} else | } else | ||||
res = EINVAL; | res = EINVAL; | ||||
break; | break; | ||||
case AT_PHDR: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (phdr != 0) { | |||||
*(u_long *)buf = phdr; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_PHENT: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (phent != 0) { | |||||
*(u_long *)buf = phent; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_PHNUM: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (phnum != 0) { | |||||
*(u_long *)buf = phnum; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_OSRELDATE: | case AT_OSRELDATE: | ||||
if (buflen == sizeof(int)) { | if (buflen == sizeof(int)) { | ||||
if (osreldate != 0) { | if (osreldate != 0) { | ||||
*(int *)buf = osreldate; | *(int *)buf = osreldate; | ||||
res = 0; | res = 0; | ||||
} else | } else | ||||
res = ENOENT; | res = ENOENT; | ||||
} else | } else | ||||
res = EINVAL; | res = EINVAL; | ||||
break; | break; | ||||
case AT_STACKPROT: | |||||
if (buflen >= sizeof(int)) { | |||||
if (stackprot_present) { | |||||
*(int *)buf = stackprot; | |||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_TIMEKEEP: | case AT_TIMEKEEP: | ||||
if (buflen == sizeof(void *)) { | if (buflen == sizeof(void *)) { | ||||
if (timekeep != NULL) { | if (timekeep != NULL) { | ||||
*(void **)buf = timekeep; | *(void **)buf = timekeep; | ||||
res = 0; | |||||
} else | |||||
res = ENOENT; | |||||
} else | |||||
res = EINVAL; | |||||
break; | |||||
case AT_UID: | |||||
if (buflen >= sizeof(u_long)) { | |||||
if (uid_present) { | |||||
*(u_long *)buf = uid; | |||||
res = 0; | res = 0; | ||||
} else | } else | ||||
res = ENOENT; | res = ENOENT; | ||||
} else | } else | ||||
res = EINVAL; | res = EINVAL; | ||||
break; | break; | ||||
default: | default: | ||||
res = ENOENT; | res = ENOENT; | ||||
break; | break; | ||||
} | } | ||||
return (res); | return (res); | ||||
} | } |
Are there any guarantees on execpath being null-terminated? I assumed so here but if that's not the case we could instead require a buflen of PATH_MAX or expose an AT_EXECPATHLEN entry.