2 * Copyright (c) 2016 - 2017 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #ifdef HAVE_SYS_AUXV_H
40 #if defined(ENABLE_PTHREAD_SUPPORT) && defined(HAVE_PTHREAD_H)
47 #include "getauxval.h"
49 int rk_injected_auxv
= 0; /* shared with issuid() for testing */
50 static int has_proc_auxv
= 1;
51 static int proc_auxv_ret
= 0;
53 #if defined(ENABLE_PTHREAD_SUPPORT) && defined(HAVE_PTHREAD_H)
54 pthread_once_t readprocauxv_once
= PTHREAD_ONCE_INIT
;
58 * There's no standard maximum.
60 * At the time of this writing we observe some 20 or so auxv entries.
61 * If eventually that grows much larger then rk_getprocaux*() will see a
64 #define MAX_AUXV_COUNT 128
65 static auxv_t auxv
[MAX_AUXV_COUNT
];
70 char *p
= (void *)auxv
;
72 size_t sz
= sizeof(auxv
) - sizeof(auxv
[0]); /* leave terminator */
73 int save_errno
= errno
;
77 memset(auxv
, 0, sizeof(auxv
)); /* terminates our copy */
78 if ((fd
= open("/proc/self/auxv", O_RDONLY
)) == -1) {
85 if ((bytes
= read(fd
, p
, sz
)) > 0) {
89 } while (sz
&& ((bytes
== -1 && errno
== EINTR
) || bytes
> 0));
92 proc_auxv_ret
= errno
;
95 if (sz
== 0 && bytes
> 0)
96 warnx("/proc/self/auxv has more entries than expected");
104 #if defined(ENABLE_PTHREAD_SUPPORT) && defined(HAVE_PTHREAD_H)
105 pthread_once(&readprocauxv_once
, do_readprocauxv
);
109 return proc_auxv_ret
;
113 * Looks up an auxv entry in /proc/self/auxv. Preserves errno.
115 * @return a pointer to an auxv_t if found, else NULL.
117 ROKEN_LIB_FUNCTION
const auxv_t
* ROKEN_LIB_CALL
118 rk_getauxv(unsigned long type
)
122 if (!has_proc_auxv
|| type
> INT_MAX
)
125 if (readprocauxv() != 0)
128 for (a
= auxv
; a
- auxv
< MAX_AUXV_COUNT
; a
++) {
129 if ((int)a
->a_type
== (int)type
)
131 if (a
->a_type
== 0 && a
->a_un
.a_val
== 0)
137 #ifdef HAVE_GETAUXVAL
139 rk_getprocauxval(unsigned long type
)
141 const auxv_t
*a
= rk_getauxv(type
);
147 return a
->a_un
.a_val
;
152 * Like the nearly-standard getauxval(). If the auxval is not found
153 * returns zero and always sets errno to ENOENT. Otherwise if auxval is
154 * found it leaves errno as it was, even if the value is zero.
156 * @return The value of the ELF auxiliary value for the given type, or
157 * zero and sets errno to ENOENT.
159 ROKEN_LIB_FUNCTION
unsigned long ROKEN_LIB_CALL
160 rk_getauxval(unsigned long type
)
162 #ifdef HAVE_GETAUXVAL
163 #ifdef GETAUXVAL_SETS_ERRNO
164 if (rk_injected_auxv
)
165 return rk_getprocauxval(type
);
166 return getauxval(type
);
170 static int getauxval_sets_errno
= -1;
172 int save_errno
= errno
;
174 if (rk_injected_auxv
)
175 return rk_getprocauxval(type
);
178 ret
= getauxval(type
);
179 if (ret
!= 0 || errno
== ENOENT
|| getauxval_sets_errno
== 1) {
182 else if (getauxval_sets_errno
> 0 && errno
== 0)
187 if (getauxval_sets_errno
== 0) {
189 a
= rk_getauxv(type
);
194 return a
->a_un
.a_val
;
198 * We've called getauxval() and it returned 0, but we don't know if
199 * getauxval() sets errno = ENOENT when entries are not found.
201 * Attempt to detect whether getauxval() sets errno = ENOENT by
202 * calling it with what should be a bogus type.
206 ret2
= getauxval(~type
);
207 if (ret2
== 0 && errno
== ENOENT
) {
208 getauxval_sets_errno
= 1;
213 getauxval_sets_errno
= 0;
215 if ((a
= rk_getauxv(type
)) == NULL
) {
219 return a
->a_un
.a_val
;
224 if ((a
= rk_getauxv(type
)) == NULL
) {
228 return a
->a_un
.a_val
;
233 * *Internal* function for testing by injecting or overwriting an ELF
234 * auxiliary vector entry.
236 * @return zero on success or ENOSPC if there are too many ELF auxiliary
239 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
240 rk_injectauxv(auxv_t
*e
)
246 * This function is racy, but as an internal function never meant to
247 * be called in a threaded program, we don't care.
250 if ((ret
= readprocauxv()) != 0)
253 rk_injected_auxv
= 1;
254 for (i
= 0; i
< MAX_AUXV_COUNT
- 1 && auxv
[i
].a_type
!= 0; i
++) {
255 /* e->a_type == 0 -> truncate auxv, delete all entries */
256 if (auxv
[i
].a_type
== e
->a_type
|| e
->a_type
== 0)
259 if (i
== MAX_AUXV_COUNT
- 1)