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