@@ -67,9 +67,8 @@ const fn make_pointer<T>(value: usize) -> Option<*const T> {
67
67
///
68
68
/// `base` must be a valid pointer to an ELF image in memory.
69
69
unsafe fn init_from_sysinfo_ehdr ( base : usize ) -> Option < Vdso > {
70
- extern "C" {
71
- static __ehdr_start: c:: c_void ;
72
- }
70
+ // Check that `base` is a valid pointer to the kernel-provided vDSO.
71
+ let hdr = check_vdso_base ( base) ?;
73
72
74
73
let mut vdso = Vdso {
75
74
load_addr : base,
@@ -85,94 +84,6 @@ unsafe fn init_from_sysinfo_ehdr(base: usize) -> Option<Vdso> {
85
84
verdef : null ( ) ,
86
85
} ;
87
86
88
- // Check that we're not attempting to parse our own ELF image.
89
- let ehdr_start: * const c:: c_void = & __ehdr_start;
90
- if base == ( ehdr_start as usize ) {
91
- return None ;
92
- }
93
-
94
- // Check that the vDSO is page-aligned and appropriately mapped.
95
- madvise (
96
- base as * mut c:: c_void ,
97
- size_of :: < Elf_Ehdr > ( ) ,
98
- Advice :: Normal ,
99
- )
100
- . ok ( ) ?;
101
-
102
- let hdr = & * make_pointer :: < Elf_Ehdr > ( base) ?;
103
-
104
- if hdr. e_ident [ ..SELFMAG ] != ELFMAG {
105
- return None ; // Wrong ELF magic
106
- }
107
- if hdr. e_ident [ EI_CLASS ] != ELFCLASS {
108
- return None ; // Wrong ELF class
109
- }
110
- if hdr. e_ident [ EI_DATA ] != ELFDATA {
111
- return None ; // Wrong ELF data
112
- }
113
- if !matches ! ( hdr. e_ident[ EI_OSABI ] , ELFOSABI_SYSV | ELFOSABI_LINUX ) {
114
- return None ; // Unrecognized ELF OS ABI
115
- }
116
- if hdr. e_ident [ EI_ABIVERSION ] != ELFABIVERSION {
117
- return None ; // Unrecognized ELF ABI version
118
- }
119
- if hdr. e_type != ET_DYN {
120
- return None ; // Wrong ELF type
121
- }
122
- // Verify that the `e_machine` matches the architecture we're running as.
123
- // This helps catch cases where we're running under qemu.
124
- if hdr. e_machine != EM_CURRENT {
125
- return None ; // Wrong machine type
126
- }
127
-
128
- // If ELF is extended, we'll need to adjust.
129
- if hdr. e_ident [ EI_VERSION ] != EV_CURRENT
130
- || hdr. e_ehsize as usize != size_of :: < Elf_Ehdr > ( )
131
- || hdr. e_phentsize as usize != size_of :: < Elf_Phdr > ( )
132
- {
133
- return None ;
134
- }
135
- // We don't currently support extra-large numbers of segments.
136
- if hdr. e_phnum == PN_XNUM {
137
- return None ;
138
- }
139
-
140
- // If `e_phoff` is zero, it's more likely that we're looking at memory that
141
- // has been zeroed than that the kernel has somehow aliased the `Ehdr` and
142
- // the `Phdr`.
143
- if hdr. e_phoff < size_of :: < Elf_Ehdr > ( ) {
144
- return None ;
145
- }
146
-
147
- // Check that the vDSO is not writable, since that would indicate that this
148
- // isn't the kernel vDSO. Here we're just using `clock_getres` just as an
149
- // arbitrary system call which writes to a buffer and fails with `EFAULT`
150
- // if the buffer is not writable.
151
- {
152
- use super :: arch:: choose:: syscall2;
153
- use super :: conv:: { clockid_t, ret, void_star} ;
154
- use super :: reg:: nr;
155
- use crate :: time:: ClockId ;
156
- use linux_raw_sys:: general:: __NR_clock_getres;
157
- if ret ( syscall2 (
158
- nr ( __NR_clock_getres) ,
159
- clockid_t ( ClockId :: Monotonic ) ,
160
- void_star ( base as * mut c:: c_void ) ,
161
- ) ) != Err ( io:: Error :: FAULT )
162
- {
163
- // We can't gracefully fail here because we would seem to have just
164
- // mutated some unknown memory.
165
- #[ cfg( feature = "std" ) ]
166
- {
167
- std:: process:: abort ( ) ;
168
- }
169
- #[ cfg( all( not( feature = "std" ) , feature = "rustc-dep-of-std" ) ) ]
170
- {
171
- core:: intrinsics:: abort ( ) ;
172
- }
173
- }
174
- }
175
-
176
87
let pt = make_pointer :: < Elf_Phdr > ( base. checked_add ( hdr. e_phoff ) ?) ?;
177
88
let mut dyn_: * const Elf_Dyn = null ( ) ;
178
89
let mut num_dyn = 0 ;
@@ -274,6 +185,107 @@ unsafe fn init_from_sysinfo_ehdr(base: usize) -> Option<Vdso> {
274
185
Some ( vdso)
275
186
}
276
187
188
+ /// Check that `base` is a valid pointer to the kernel-provided vDSO.
189
+ ///
190
+ /// `base` is some value we got from a `AT_SYSINFO_EHDR` aux record somewhere,
191
+ /// which hopefully holds the value of the kernel-provided vDSO in memory. Do
192
+ /// a series of checks to be as sure as we can that it's safe to use.
193
+ unsafe fn check_vdso_base < ' vdso > ( base : usize ) -> Option < & ' vdso Elf_Ehdr > {
194
+ extern "C" {
195
+ static __ehdr_start: c:: c_void ;
196
+ }
197
+
198
+ // Check that we're not attempting to parse our own ELF image.
199
+ let ehdr_start: * const c:: c_void = & __ehdr_start;
200
+ if base == ( ehdr_start as usize ) {
201
+ return None ;
202
+ }
203
+
204
+ // Check that the vDSO is page-aligned and appropriately mapped.
205
+ madvise (
206
+ base as * mut c:: c_void ,
207
+ size_of :: < Elf_Ehdr > ( ) ,
208
+ Advice :: Normal ,
209
+ )
210
+ . ok ( ) ?;
211
+
212
+ let hdr = & * make_pointer :: < Elf_Ehdr > ( base) ?;
213
+
214
+ if hdr. e_ident [ ..SELFMAG ] != ELFMAG {
215
+ return None ; // Wrong ELF magic
216
+ }
217
+ if hdr. e_ident [ EI_CLASS ] != ELFCLASS {
218
+ return None ; // Wrong ELF class
219
+ }
220
+ if hdr. e_ident [ EI_DATA ] != ELFDATA {
221
+ return None ; // Wrong ELF data
222
+ }
223
+ if !matches ! ( hdr. e_ident[ EI_OSABI ] , ELFOSABI_SYSV | ELFOSABI_LINUX ) {
224
+ return None ; // Unrecognized ELF OS ABI
225
+ }
226
+ if hdr. e_ident [ EI_ABIVERSION ] != ELFABIVERSION {
227
+ return None ; // Unrecognized ELF ABI version
228
+ }
229
+ if hdr. e_type != ET_DYN {
230
+ return None ; // Wrong ELF type
231
+ }
232
+ // Verify that the `e_machine` matches the architecture we're running as.
233
+ // This helps catch cases where we're running under qemu.
234
+ if hdr. e_machine != EM_CURRENT {
235
+ return None ; // Wrong machine type
236
+ }
237
+
238
+ // If ELF is extended, we'll need to adjust.
239
+ if hdr. e_ident [ EI_VERSION ] != EV_CURRENT
240
+ || hdr. e_ehsize as usize != size_of :: < Elf_Ehdr > ( )
241
+ || hdr. e_phentsize as usize != size_of :: < Elf_Phdr > ( )
242
+ {
243
+ return None ;
244
+ }
245
+ // We don't currently support extra-large numbers of segments.
246
+ if hdr. e_phnum == PN_XNUM {
247
+ return None ;
248
+ }
249
+
250
+ // If `e_phoff` is zero, it's more likely that we're looking at memory that
251
+ // has been zeroed than that the kernel has somehow aliased the `Ehdr` and
252
+ // the `Phdr`.
253
+ if hdr. e_phoff < size_of :: < Elf_Ehdr > ( ) {
254
+ return None ;
255
+ }
256
+
257
+ // Check that the vDSO is not writable, since that would indicate that this
258
+ // isn't the kernel vDSO. Here we're just using `clock_getres` just as an
259
+ // arbitrary system call which writes to a buffer and fails with `EFAULT`
260
+ // if the buffer is not writable.
261
+ {
262
+ use super :: arch:: choose:: syscall2;
263
+ use super :: conv:: { clockid_t, ret, void_star} ;
264
+ use super :: reg:: nr;
265
+ use crate :: time:: ClockId ;
266
+ use linux_raw_sys:: general:: __NR_clock_getres;
267
+ if ret ( syscall2 (
268
+ nr ( __NR_clock_getres) ,
269
+ clockid_t ( ClockId :: Monotonic ) ,
270
+ void_star ( base as * mut c:: c_void ) ,
271
+ ) ) != Err ( io:: Error :: FAULT )
272
+ {
273
+ // We can't gracefully fail here because we would seem to have just
274
+ // mutated some unknown memory.
275
+ #[ cfg( feature = "std" ) ]
276
+ {
277
+ std:: process:: abort ( ) ;
278
+ }
279
+ #[ cfg( all( not( feature = "std" ) , feature = "rustc-dep-of-std" ) ) ]
280
+ {
281
+ core:: intrinsics:: abort ( ) ;
282
+ }
283
+ }
284
+ }
285
+
286
+ Some ( hdr)
287
+ }
288
+
277
289
impl Vdso {
278
290
/// Parse the vDSO.
279
291
///
0 commit comments