5
5
//! This uses raw pointers to locate and read the kernel-provided auxv array.
6
6
#![ allow( unsafe_code) ]
7
7
8
+ use super :: super :: conv:: { c_int, pass_usize, ret_usize} ;
8
9
use crate :: backend:: c;
9
10
use crate :: fd:: OwnedFd ;
10
11
#[ cfg( feature = "param" ) ]
@@ -27,6 +28,8 @@ use linux_raw_sys::general::{
27
28
use linux_raw_sys:: general:: {
28
29
AT_EGID , AT_ENTRY , AT_EUID , AT_GID , AT_PHDR , AT_PHENT , AT_PHNUM , AT_RANDOM , AT_SECURE , AT_UID ,
29
30
} ;
31
+ #[ cfg( feature = "alloc" ) ]
32
+ use { alloc:: borrow:: Cow , alloc:: vec} ;
30
33
31
34
#[ cfg( feature = "param" ) ]
32
35
#[ inline]
@@ -120,12 +123,19 @@ pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
120
123
121
124
/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, so
122
125
/// if we don't see it, this function returns a null pointer.
126
+ ///
127
+ /// And, this function returns a null pointer, rather than panicking, if the
128
+ /// auxv records can't be read.
123
129
#[ inline]
124
130
pub ( in super :: super ) fn sysinfo_ehdr ( ) -> * const Elf_Ehdr {
125
131
let mut ehdr = SYSINFO_EHDR . load ( Relaxed ) ;
126
132
127
133
if ehdr. is_null ( ) {
128
- init_auxv ( ) ;
134
+ // Use `maybe_init_auxv` to to read the aux vectors if it can, but do
135
+ // nothing if it can't. If it can't, then we'll get a null pointer
136
+ // here, which our callers are prepared to deal with.
137
+ maybe_init_auxv ( ) ;
138
+
129
139
ehdr = SYSINFO_EHDR . load ( Relaxed ) ;
130
140
}
131
141
@@ -177,74 +187,122 @@ static ENTRY: AtomicUsize = AtomicUsize::new(0);
177
187
#[ cfg( feature = "runtime" ) ]
178
188
static RANDOM : AtomicPtr < [ u8 ; 16 ] > = AtomicPtr :: new ( null_mut ( ) ) ;
179
189
180
- #[ cfg( feature = "alloc" ) ]
181
- fn pr_get_auxv ( ) -> crate :: io:: Result < Vec < u8 > > {
182
- use super :: super :: conv:: { c_int, pass_usize, ret_usize} ;
183
- const PR_GET_AUXV : c:: c_int = 0x4155_5856 ;
184
- let mut buffer = alloc:: vec![ 0u8 ; 512 ] ;
190
+ const PR_GET_AUXV : c:: c_int = 0x4155_5856 ;
191
+
192
+ /// Use Linux >= 6.4's `PR_GET_AUXV` to read the aux records, into a provided
193
+ /// statically-sized buffer. Return:
194
+ /// - `Ok(...)` if the buffer is big enough.
195
+ /// - `Err(Ok(len))` if we need a buffer of length `len`.
196
+ /// - `Err(Err(err))` if we failed with `err`.
197
+ #[ cold]
198
+ fn pr_get_auxv_static ( buffer : & mut [ u8 ; 512 ] ) -> Result < & mut [ u8 ] , crate :: io:: Result < usize > > {
185
199
let len = unsafe {
186
200
ret_usize ( syscall_always_asm ! (
187
201
__NR_prctl,
188
202
c_int( PR_GET_AUXV ) ,
189
- buffer. as_ptr ( ) ,
203
+ buffer. as_mut_ptr ( ) ,
190
204
pass_usize( buffer. len( ) ) ,
191
205
pass_usize( 0 ) ,
192
206
pass_usize( 0 )
193
- ) ) ?
207
+ ) )
208
+ . map_err ( Err ) ?
194
209
} ;
195
210
if len <= buffer. len ( ) {
196
- buffer. truncate ( len) ;
197
- return Ok ( buffer) ;
211
+ return Ok ( & mut buffer[ ..len] ) ;
198
212
}
199
- buffer. resize ( len, 0 ) ;
213
+ Err ( Ok ( len) )
214
+ }
215
+
216
+ /// Use Linux >= 6.4's `PR_GET_AUXV` to read the aux records, using a provided
217
+ /// statically-sized buffer if possible, or a dynamically allocated buffer
218
+ /// otherwise. Return:
219
+ /// - Ok(...) on success.
220
+ /// - Err(err) on failure.
221
+ #[ cfg( feature = "alloc" ) ]
222
+ #[ cold]
223
+ fn pr_get_auxv_dynamic ( buffer : & mut [ u8 ; 512 ] ) -> crate :: io:: Result < Cow < ' _ , [ u8 ] > > {
224
+ // First try use the static buffer.
225
+ let len = match pr_get_auxv_static ( buffer) {
226
+ Ok ( buffer) => return Ok ( Cow :: Borrowed ( buffer) ) ,
227
+ Err ( Ok ( len) ) => len,
228
+ Err ( Err ( err) ) => return Err ( err) ,
229
+ } ;
230
+
231
+ // If that indicates it needs a bigger buffer, allocate one.
232
+ let mut buffer = vec ! [ 0u8 ; len] ;
200
233
let len = unsafe {
201
234
ret_usize ( syscall_always_asm ! (
202
235
__NR_prctl,
203
236
c_int( PR_GET_AUXV ) ,
204
- buffer. as_ptr ( ) ,
237
+ buffer. as_mut_ptr ( ) ,
205
238
pass_usize( buffer. len( ) ) ,
206
239
pass_usize( 0 ) ,
207
240
pass_usize( 0 )
208
241
) ) ?
209
242
} ;
210
243
assert_eq ! ( len, buffer. len( ) ) ;
211
- return Ok ( buffer) ;
244
+ Ok ( Cow :: Owned ( buffer) )
245
+ }
246
+
247
+ /// Read the auxv records and initialize the various static variables. Panic
248
+ /// if an error is encountered.
249
+ #[ cold]
250
+ fn init_auxv ( ) {
251
+ init_auxv_impl ( ) . unwrap ( ) ;
252
+ }
253
+
254
+ /// Like `init_auxv`, but don't panic if an error is encountered. The caller
255
+ /// must be prepared for initialization to be skipped.
256
+ #[ cold]
257
+ fn maybe_init_auxv ( ) {
258
+ if let Ok ( ( ) ) = init_auxv_impl ( ) {
259
+ return ;
260
+ }
212
261
}
213
262
214
263
/// If we don't have "use-explicitly-provided-auxv" or "use-libc-auxv", we
215
264
/// read the aux vector via the `prctl` `PR_GET_AUXV`, with a fallback to
216
265
/// /proc/self/auxv for kernels that don't support `PR_GET_AUXV`.
217
266
#[ cold]
218
- fn init_auxv ( ) {
267
+ fn init_auxv_impl ( ) -> Result < ( ) , ( ) > {
268
+ let mut buffer = [ 0u8 ; 512 ] ;
269
+
270
+ // If we don't have "alloc", just try to read into our statically-sized
271
+ // buffer. This might fail due to the buffer being insufficient; we're
272
+ // prepared to cope, though we may do suboptimal things.
273
+ #[ cfg( not( feature = "alloc" ) ) ]
274
+ let result = pr_get_auxv_static ( & mut buffer) ;
275
+
276
+ // If we do have "alloc" then read into our statically-sized buffer if
277
+ // it fits, or fall back to a dynamically-allocated buffer.
219
278
#[ cfg( feature = "alloc" ) ]
220
- {
221
- match pr_get_auxv ( ) {
222
- Ok ( buffer) => {
223
- // SAFETY: We assume the kernel returns a valid auxv.
224
- unsafe {
225
- init_from_aux_iter ( AuxPointer ( buffer. as_ptr ( ) . cast ( ) ) ) . unwrap ( ) ;
226
- }
227
- return ;
228
- }
229
- Err ( _) => {
230
- // Fall back to /proc/self/auxv on error.
231
- }
279
+ let result = pr_get_auxv_dynamic ( & mut buffer) ;
280
+
281
+ if let Ok ( buffer) = result {
282
+ // SAFETY: We assume the kernel returns a valid auxv.
283
+ unsafe {
284
+ init_from_aux_iter ( AuxPointer ( buffer. as_ptr ( ) . cast ( ) ) ) . unwrap ( ) ;
232
285
}
286
+ return Ok ( ( ) ) ;
233
287
}
234
288
235
- // Open "/proc/self/auxv", either because we trust "/proc", or because
236
- // we're running inside QEMU and `proc_self_auxv`'s extra checking foils
237
- // QEMU's emulation so we need to do a plain open to get the right
238
- // auxv records.
239
- let file = crate :: fs:: open ( "/proc/self/auxv" , OFlags :: RDONLY , Mode :: empty ( ) ) . unwrap ( ) ;
289
+ // If `PR_GET_AUXV` is unavailable, or if we don't have "alloc" and
290
+ // the aux records don't fit in our static buffer, then fall back to trying
291
+ // to open "/proc/self/auxv". We don't use `proc_self_fd` because its extra
292
+ // checking breaks on QEMU.
293
+ if let Ok ( file) = crate :: fs:: open ( "/proc/self/auxv" , OFlags :: RDONLY , Mode :: empty ( ) ) {
294
+ #[ cfg( feature = "alloc" ) ]
295
+ init_from_auxv_file ( file) . unwrap ( ) ;
240
296
241
- #[ cfg( feature = "alloc" ) ]
242
- init_from_auxv_file ( file) . unwrap ( ) ;
297
+ #[ cfg( not( feature = "alloc" ) ) ]
298
+ unsafe {
299
+ init_from_aux_iter ( AuxFile ( file) ) . unwrap ( ) ;
300
+ }
243
301
244
- #[ cfg( not( feature = "alloc" ) ) ]
245
- unsafe {
246
- init_from_aux_iter ( AuxFile ( file) ) . unwrap ( ) ;
302
+ return Ok ( ( ) ) ;
247
303
}
304
+
305
+ Err ( ( ) )
248
306
}
249
307
250
308
/// Process auxv entries from the open file `auxv`.
0 commit comments