• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Low-level compatibility layer between baremetal Rust and Bionic C functions.
16 
17 use crate::rand::fill_with_entropy;
18 use crate::read_sysreg;
19 use core::ffi::c_char;
20 use core::ffi::c_int;
21 use core::ffi::c_void;
22 use core::ffi::CStr;
23 use core::slice;
24 use core::str;
25 
26 use log::error;
27 use log::info;
28 
29 const EOF: c_int = -1;
30 const EIO: c_int = 5;
31 
32 /// Bionic thread-local storage.
33 #[repr(C)]
34 pub struct Tls {
35     /// Unused.
36     _unused: [u8; 40],
37     /// Use by the compiler as stack canary value.
38     pub stack_guard: u64,
39 }
40 
41 /// Bionic TLS.
42 ///
43 /// Provides the TLS used by Bionic code. This is unique as vmbase only supports one thread.
44 ///
45 /// Note that the linker script re-exports __bionic_tls.stack_guard as __stack_chk_guard for
46 /// compatibility with non-Bionic LLVM.
47 #[link_section = ".data.stack_protector"]
48 #[export_name = "__bionic_tls"]
49 pub static mut TLS: Tls = Tls { _unused: [0; 40], stack_guard: 0 };
50 
51 /// Gets a reference to the TLS from the dedicated system register.
__get_tls() -> &'static mut Tls52 pub fn __get_tls() -> &'static mut Tls {
53     let tpidr = read_sysreg!("tpidr_el0");
54     // SAFETY: The register is currently only written to once, from entry.S, with a valid value.
55     unsafe { &mut *(tpidr as *mut Tls) }
56 }
57 
58 #[no_mangle]
__stack_chk_fail() -> !59 extern "C" fn __stack_chk_fail() -> ! {
60     panic!("stack guard check failed");
61 }
62 
63 /// Called from C to cause abnormal program termination.
64 #[no_mangle]
abort() -> !65 extern "C" fn abort() -> ! {
66     panic!("C code called abort()")
67 }
68 
69 /// Error number set and read by C functions.
70 pub static mut ERRNO: c_int = 0;
71 
72 #[no_mangle]
73 // SAFETY: C functions which call this are only called from the main thread, not from exception
74 // handlers.
__errno() -> *mut c_int75 unsafe extern "C" fn __errno() -> *mut c_int {
76     (&raw mut ERRNO).cast()
77 }
78 
set_errno(value: c_int)79 fn set_errno(value: c_int) {
80     // SAFETY: vmbase is currently single-threaded.
81     unsafe { ERRNO = value };
82 }
83 
get_errno() -> c_int84 fn get_errno() -> c_int {
85     // SAFETY: vmbase is currently single-threaded.
86     unsafe { ERRNO }
87 }
88 
89 /// # Safety
90 ///
91 /// `buffer` must point to an allocation of at least `length` bytes which is valid to write to and
92 /// has no concurrent access while this function is running.
93 #[no_mangle]
getentropy(buffer: *mut c_void, length: usize) -> c_int94 unsafe extern "C" fn getentropy(buffer: *mut c_void, length: usize) -> c_int {
95     if length > 256 {
96         // The maximum permitted value for the length argument is 256.
97         set_errno(EIO);
98         return -1;
99     }
100 
101     // SAFETY: The caller promised that `buffer` is a valid pointer to at least `length` bytes with
102     // no concurrent access.
103     let buffer = unsafe { slice::from_raw_parts_mut(buffer.cast::<u8>(), length) };
104     fill_with_entropy(buffer).unwrap();
105 
106     0
107 }
108 
109 /// Reports a fatal error detected by Bionic.
110 ///
111 /// # Safety
112 ///
113 /// Input strings `prefix` and `format` must be valid and properly NUL-terminated.
114 ///
115 /// # Note
116 ///
117 /// This Rust function is missing the last argument of its C/C++ counterpart, a va_list.
118 #[no_mangle]
async_safe_fatal_va_list(prefix: *const c_char, format: *const c_char)119 unsafe extern "C" fn async_safe_fatal_va_list(prefix: *const c_char, format: *const c_char) {
120     // SAFETY: The caller guaranteed that both strings were valid and NUL-terminated.
121     let (prefix, format) = unsafe { (CStr::from_ptr(prefix), CStr::from_ptr(format)) };
122 
123     if let (Ok(prefix), Ok(format)) = (prefix.to_str(), format.to_str()) {
124         // We don't bother with printf formatting.
125         error!("FATAL BIONIC ERROR: {prefix}: \"{format}\" (unformatted)");
126     }
127 }
128 
129 #[cfg(target_arch = "aarch64")]
130 #[allow(clippy::enum_clike_unportable_variant)] // No risk if AArch64 only.
131 #[repr(usize)]
132 /// Fake FILE* values used by C to refer to the default streams.
133 ///
134 /// These values are intentionally invalid pointers so that dereferencing them will be caught.
135 enum CFilePtr {
136     // On AArch64 with TCR_EL1.EPD1 set or TCR_EL1.T1SZ > 12, these VAs can't be mapped.
137     Stdout = 0xfff0_badf_badf_bad0,
138     Stderr = 0xfff0_badf_badf_bad1,
139 }
140 
141 impl CFilePtr {
write_lines(&self, s: &str)142     fn write_lines(&self, s: &str) {
143         for line in s.split_inclusive('\n') {
144             let (line, ellipsis) = if let Some(stripped) = line.strip_suffix('\n') {
145                 (stripped, "")
146             } else {
147                 (line, " ...")
148             };
149 
150             match self {
151                 Self::Stdout => info!("{line}{ellipsis}"),
152                 Self::Stderr => error!("{line}{ellipsis}"),
153             }
154         }
155     }
156 }
157 
158 impl TryFrom<usize> for CFilePtr {
159     type Error = &'static str;
160 
try_from(value: usize) -> Result<Self, Self::Error>161     fn try_from(value: usize) -> Result<Self, Self::Error> {
162         match value {
163             x if x == Self::Stdout as _ => Ok(Self::Stdout),
164             x if x == Self::Stderr as _ => Ok(Self::Stderr),
165             _ => Err("Received Invalid FILE* from C"),
166         }
167     }
168 }
169 
170 #[no_mangle]
171 static stdout: CFilePtr = CFilePtr::Stdout;
172 #[no_mangle]
173 static stderr: CFilePtr = CFilePtr::Stderr;
174 
175 /// # Safety
176 ///
177 /// `c_str` must be a valid pointer to a NUL-terminated string which is not modified before this
178 /// function returns.
179 #[no_mangle]
fputs(c_str: *const c_char, stream: usize) -> c_int180 unsafe extern "C" fn fputs(c_str: *const c_char, stream: usize) -> c_int {
181     // SAFETY: The caller promised that `c_str` is a valid NUL-terminated string.
182     let c_str = unsafe { CStr::from_ptr(c_str) };
183 
184     if let (Ok(s), Ok(f)) = (c_str.to_str(), CFilePtr::try_from(stream)) {
185         f.write_lines(s);
186         0
187     } else {
188         set_errno(EOF);
189         EOF
190     }
191 }
192 
193 /// # Safety
194 ///
195 /// `ptr` must be a valid pointer to an array of at least `size * nmemb` initialised bytes, which
196 /// are not modified before this function returns.
197 #[no_mangle]
fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: usize) -> usize198 unsafe extern "C" fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: usize) -> usize {
199     let length = size.saturating_mul(nmemb);
200 
201     // SAFETY: The caller promised that `ptr` is a valid pointer to at least `size * nmemb`
202     // initialised bytes, and `length` is no more than that.
203     let bytes = unsafe { slice::from_raw_parts(ptr as *const u8, length) };
204 
205     if let (Ok(s), Ok(f)) = (str::from_utf8(bytes), CFilePtr::try_from(stream)) {
206         f.write_lines(s);
207         length
208     } else {
209         0
210     }
211 }
212 
213 #[no_mangle]
strerror(n: c_int) -> *mut c_char214 extern "C" fn strerror(n: c_int) -> *mut c_char {
215     cstr_error(n).as_ptr().cast_mut().cast()
216 }
217 
218 /// # Safety
219 ///
220 /// `s` must be a valid pointer to a NUL-terminated string which is not modified before this
221 /// function returns.
222 #[no_mangle]
perror(s: *const c_char)223 unsafe extern "C" fn perror(s: *const c_char) {
224     let prefix = if s.is_null() {
225         None
226     } else {
227         // SAFETY: The caller promised that `s` is a valid NUL-terminated string.
228         let c_str = unsafe { CStr::from_ptr(s) };
229         if c_str.is_empty() {
230             None
231         } else {
232             Some(c_str.to_str().unwrap())
233         }
234     };
235 
236     let error = cstr_error(get_errno()).to_str().unwrap();
237 
238     if let Some(prefix) = prefix {
239         error!("{prefix}: {error}");
240     } else {
241         error!("{error}");
242     }
243 }
244 
cstr_error(n: c_int) -> &'static CStr245 fn cstr_error(n: c_int) -> &'static CStr {
246     // Messages taken from errno(1).
247     match n {
248         0 => c"Success",
249         1 => c"Operation not permitted",
250         2 => c"No such file or directory",
251         3 => c"No such process",
252         4 => c"Interrupted system call",
253         5 => c"Input/output error",
254         6 => c"No such device or address",
255         7 => c"Argument list too long",
256         8 => c"Exec format error",
257         9 => c"Bad file descriptor",
258         10 => c"No child processes",
259         11 => c"Resource temporarily unavailable",
260         12 => c"Cannot allocate memory",
261         13 => c"Permission denied",
262         14 => c"Bad address",
263         15 => c"Block device required",
264         16 => c"Device or resource busy",
265         17 => c"File exists",
266         18 => c"Invalid cross-device link",
267         19 => c"No such device",
268         20 => c"Not a directory",
269         21 => c"Is a directory",
270         22 => c"Invalid argument",
271         23 => c"Too many open files in system",
272         24 => c"Too many open files",
273         25 => c"Inappropriate ioctl for device",
274         26 => c"Text file busy",
275         27 => c"File too large",
276         28 => c"No space left on device",
277         29 => c"Illegal seek",
278         30 => c"Read-only file system",
279         31 => c"Too many links",
280         32 => c"Broken pipe",
281         33 => c"Numerical argument out of domain",
282         34 => c"Numerical result out of range",
283         35 => c"Resource deadlock avoided",
284         36 => c"File name too long",
285         37 => c"No locks available",
286         38 => c"Function not implemented",
287         39 => c"Directory not empty",
288         40 => c"Too many levels of symbolic links",
289         42 => c"No message of desired type",
290         43 => c"Identifier removed",
291         44 => c"Channel number out of range",
292         45 => c"Level 2 not synchronized",
293         46 => c"Level 3 halted",
294         47 => c"Level 3 reset",
295         48 => c"Link number out of range",
296         49 => c"Protocol driver not attached",
297         50 => c"No CSI structure available",
298         51 => c"Level 2 halted",
299         52 => c"Invalid exchange",
300         53 => c"Invalid request descriptor",
301         54 => c"Exchange full",
302         55 => c"No anode",
303         56 => c"Invalid request code",
304         57 => c"Invalid slot",
305         59 => c"Bad font file format",
306         60 => c"Device not a stream",
307         61 => c"No data available",
308         62 => c"Timer expired",
309         63 => c"Out of streams resources",
310         64 => c"Machine is not on the network",
311         65 => c"Package not installed",
312         66 => c"Object is remote",
313         67 => c"Link has been severed",
314         68 => c"Advertise error",
315         69 => c"Srmount error",
316         70 => c"Communication error on send",
317         71 => c"Protocol error",
318         72 => c"Multihop attempted",
319         73 => c"RFS specific error",
320         74 => c"Bad message",
321         75 => c"Value too large for defined data type",
322         76 => c"Name not unique on network",
323         77 => c"File descriptor in bad state",
324         78 => c"Remote address changed",
325         79 => c"Can not access a needed shared library",
326         80 => c"Accessing a corrupted shared library",
327         81 => c".lib section in a.out corrupted",
328         82 => c"Attempting to link in too many shared libraries",
329         83 => c"Cannot exec a shared library directly",
330         84 => c"Invalid or incomplete multibyte or wide character",
331         85 => c"Interrupted system call should be restarted",
332         86 => c"Streams pipe error",
333         87 => c"Too many users",
334         88 => c"Socket operation on non-socket",
335         89 => c"Destination address required",
336         90 => c"Message too long",
337         91 => c"Protocol wrong type for socket",
338         92 => c"Protocol not available",
339         93 => c"Protocol not supported",
340         94 => c"Socket type not supported",
341         95 => c"Operation not supported",
342         96 => c"Protocol family not supported",
343         97 => c"Address family not supported by protocol",
344         98 => c"Address already in use",
345         99 => c"Cannot assign requested address",
346         100 => c"Network is down",
347         101 => c"Network is unreachable",
348         102 => c"Network dropped connection on reset",
349         103 => c"Software caused connection abort",
350         104 => c"Connection reset by peer",
351         105 => c"No buffer space available",
352         106 => c"Transport endpoint is already connected",
353         107 => c"Transport endpoint is not connected",
354         108 => c"Cannot send after transport endpoint shutdown",
355         109 => c"Too many references: cannot splice",
356         110 => c"Connection timed out",
357         111 => c"Connection refused",
358         112 => c"Host is down",
359         113 => c"No route to host",
360         114 => c"Operation already in progress",
361         115 => c"Operation now in progress",
362         116 => c"Stale file handle",
363         117 => c"Structure needs cleaning",
364         118 => c"Not a XENIX named type file",
365         119 => c"No XENIX semaphores available",
366         120 => c"Is a named type file",
367         121 => c"Remote I/O error",
368         122 => c"Disk quota exceeded",
369         123 => c"No medium found",
370         124 => c"Wrong medium type",
371         125 => c"Operation canceled",
372         126 => c"Required key not available",
373         127 => c"Key has expired",
374         128 => c"Key has been revoked",
375         129 => c"Key was rejected by service",
376         130 => c"Owner died",
377         131 => c"State not recoverable",
378         132 => c"Operation not possible due to RF-kill",
379         133 => c"Memory page has hardware error",
380         _ => c"Unknown errno value",
381     }
382 }
383