Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 725d5253 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add safety comments." into main am: 367ade7e

parents f9c1bc51 367ade7e
Loading
Loading
Loading
Loading
+6 −10
Original line number Diff line number Diff line
@@ -57,8 +57,7 @@ impl BootTime {
    /// Gets a `BootTime` representing the current moment in time.
    pub fn now() -> BootTime {
        let mut t = libc::timespec { tv_sec: 0, tv_nsec: 0 };
        // # Safety
        // clock_gettime's only action will be to possibly write to the pointer provided,
        // SAFETY: clock_gettime's only action will be to possibly write to the pointer provided,
        // and no borrows exist from that object other than the &mut used to construct the pointer
        // itself.
        if unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut t as *mut libc::timespec) } != 0
@@ -93,9 +92,8 @@ struct TimerFd(RawFd);

impl Drop for TimerFd {
    fn drop(&mut self) {
        // # Safety
        // The fd is owned by the TimerFd struct, and no memory access occurs as a result of this
        // call.
        // SAFETY: The fd is owned by the TimerFd struct, and no memory access occurs as a result of
        // this call.
        unsafe {
            libc::close(self.0);
        }
@@ -110,9 +108,8 @@ impl AsRawFd for TimerFd {

impl TimerFd {
    fn create() -> io::Result<Self> {
        // # Unsafe
        // This libc call will either give us back a file descriptor or fail, it does not act on
        // memory or resources.
        // SAFETY: This libc call will either give us back a file descriptor or fail, it does not
        // act on memory or resources.
        let raw = unsafe {
            libc::timerfd_create(libc::CLOCK_BOOTTIME, libc::TFD_NONBLOCK | libc::TFD_CLOEXEC)
        };
@@ -131,8 +128,7 @@ impl TimerFd {
                tv_nsec: duration.subsec_nanos().try_into().unwrap(),
            },
        };
        // # Unsafe
        // We own `timer` and there are no borrows to it other than the pointer we pass to
        // SAFETY: We own `timer` and there are no borrows to it other than the pointer we pass to
        // timerfd_settime. timerfd_settime is explicitly documented to handle a null output
        // parameter for its fourth argument by not filling out the output. The fd passed in at
        // self.0 is owned by the `TimerFd` struct, so we aren't breaking anyone else's invariants.
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ fn new_scid() -> [u8; quiche::MAX_CONN_ID_LEN] {
fn mark_socket(socket: &std::net::UdpSocket, socket_mark: u32) -> io::Result<()> {
    use std::os::unix::io::AsRawFd;
    let fd = socket.as_raw_fd();
    // libc::setsockopt is a wrapper function calling into bionic setsockopt.
    // SAFETY: libc::setsockopt is a wrapper function calling into bionic setsockopt.
    // The only pointer being passed in is &socket_mark, which is valid by virtue of being a
    // reference, and the foreign function doesn't take ownership or a reference to that memory
    // after completion.
+38 −16
Original line number Diff line number Diff line
@@ -35,8 +35,12 @@ use tokio::sync::oneshot;
use tokio::task;
use url::Url;

pub type ValidationCallback =
    extern "C" fn(net_id: uint32_t, success: bool, ip_addr: *const c_char, host: *const c_char);
pub type ValidationCallback = unsafe extern "C" fn(
    net_id: uint32_t,
    success: bool,
    ip_addr: *const c_char,
    host: *const c_char,
);
pub type TagSocketCallback = extern "C" fn(sock: RawFd);

#[repr(C)]
@@ -61,7 +65,9 @@ fn wrap_validation_callback(validation_fn: ValidationCallback) -> ValidationRepo
                }
            };
            let netd_id = info.net_id;
            task::spawn_blocking(move || {
            // SAFETY: The string pointers are obtained from `CString`, so they must be valid C
            // strings.
            task::spawn_blocking(move || unsafe {
                validation_fn(netd_id, success, ip_addr.as_ptr(), domain.as_ptr())
            })
            .await
@@ -167,12 +173,16 @@ pub extern "C" fn doh_dispatcher_new(
}

/// Deletes a DoH engine created by doh_dispatcher_new().
///
/// # Safety
///
/// `doh` must be a non-null pointer previously created by `doh_dispatcher_new()`
/// and not yet deleted by `doh_dispatcher_delete()`.
#[no_mangle]
pub unsafe extern "C" fn doh_dispatcher_delete(doh: *mut DohDispatcher) {
    Box::from_raw(doh).lock().exit_handler()
    // SAFETY: The caller guarantees that `doh` was created by `doh_dispatcher_new` (which does so
    // using `Box::into_raw`), and that it hasn't yet been deleted by this function.
    unsafe { Box::from_raw(doh) }.lock().exit_handler()
}

/// Probes and stores the DoH server with the given configurations.
@@ -194,12 +204,15 @@ pub unsafe extern "C" fn doh_net_new(
    network_type: uint32_t,
    private_dns_mode: uint32_t,
) -> int32_t {
    let (url, domain, ip_addr, cert_path) = match (
    // SAFETY: The caller guarantees that these are all valid nul-terminated C strings.
    let (url, domain, ip_addr, cert_path) = match unsafe {
        (
            std::ffi::CStr::from_ptr(url).to_str(),
            std::ffi::CStr::from_ptr(domain).to_str(),
            std::ffi::CStr::from_ptr(ip_addr).to_str(),
            std::ffi::CStr::from_ptr(cert_path).to_str(),
    ) {
        )
    } {
        (Ok(url), Ok(domain), Ok(ip_addr), Ok(cert_path)) => {
            if domain.is_empty() {
                (url, None, ip_addr.to_string(), None)
@@ -268,7 +281,9 @@ pub unsafe extern "C" fn doh_query(
    response_len: size_t,
    timeout_ms: uint64_t,
) -> ssize_t {
    let q = slice::from_raw_parts_mut(dns_query, dns_query_len);
    // SAFETY: The caller guarantees that `dns_query` is a valid pointer to a buffer of at least
    // `dns_query_len` items.
    let q = unsafe { slice::from_raw_parts_mut(dns_query, dns_query_len) };

    let (resp_tx, resp_rx) = oneshot::channel();
    let t = Duration::from_millis(timeout_ms);
@@ -298,7 +313,10 @@ pub unsafe extern "C" fn doh_query(
                        if answer.len() > response_len || answer.len() > isize::MAX as usize {
                            return DOH_RESULT_INTERNAL_ERROR;
                        }
                        let response = slice::from_raw_parts_mut(response, answer.len());
                        // SAFETY: The caller guarantees that response points to a valid buffer at
                        // least `response_len` long, and we just checked that `answer.len()` is no
                        // longer than `response_len`.
                        let response = unsafe { slice::from_raw_parts_mut(response, answer.len()) };
                        response.copy_from_slice(&answer);
                        answer.len() as ssize_t
                    }
@@ -341,25 +359,27 @@ mod tests {
    const LOOPBACK_ADDR: &str = "127.0.0.1:443";
    const LOCALHOST_URL: &str = "https://mylocal.com/dns-query";

    extern "C" fn success_cb(
    unsafe extern "C" fn success_cb(
        net_id: uint32_t,
        success: bool,
        ip_addr: *const c_char,
        host: *const c_char,
    ) {
        assert!(success);
        // SAFETY: The caller guarantees that ip_addr and host are valid nul-terminated C strings.
        unsafe {
            assert_validation_info(net_id, ip_addr, host);
        }
    }

    extern "C" fn fail_cb(
    unsafe extern "C" fn fail_cb(
        net_id: uint32_t,
        success: bool,
        ip_addr: *const c_char,
        host: *const c_char,
    ) {
        assert!(!success);
        // SAFETY: The caller guarantees that ip_addr and host are valid nul-terminated C strings.
        unsafe {
            assert_validation_info(net_id, ip_addr, host);
        }
@@ -373,10 +393,12 @@ mod tests {
        host: *const c_char,
    ) {
        assert_eq!(net_id, TEST_NET_ID);
        let ip_addr = std::ffi::CStr::from_ptr(ip_addr).to_str().unwrap();
        // SAFETY: The caller guarantees that `ip_addr` is a valid nul-terminated C string.
        let ip_addr = unsafe { std::ffi::CStr::from_ptr(ip_addr) }.to_str().unwrap();
        let expected_addr: SocketAddr = LOOPBACK_ADDR.parse().unwrap();
        assert_eq!(ip_addr, expected_addr.ip().to_string());
        let host = std::ffi::CStr::from_ptr(host).to_str().unwrap();
        // SAFETY: The caller guarantees that `host` is a valid nul-terminated C string.
        let host = unsafe { std::ffi::CStr::from_ptr(host) }.to_str().unwrap();
        assert_eq!(host, "");
    }

+3 −0
Original line number Diff line number Diff line
@@ -477,6 +477,9 @@ fn into_tokio_udp_socket(socket: std::net::UdpSocket) -> Result<UdpSocket> {

fn build_pipe() -> Result<(File, File)> {
    let mut fds = [0, 0];
    // SAFETY: The pointer we pass to `pipe` must be valid because it comes from a reference. The
    // file descriptors it returns must be valid and open, so they are safe to pass to
    // `File::from_raw_fd`.
    unsafe {
        if libc::pipe(fds.as_mut_ptr()) == 0 {
            return Ok((File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1])));
+20 −8
Original line number Diff line number Diff line
@@ -38,10 +38,14 @@ pub unsafe extern "C" fn frontend_new(
    backend_addr: *const c_char,
    backend_port: *const c_char,
) -> *mut DohFrontend {
    let addr = CStr::from_ptr(addr).to_str().unwrap();
    let port = CStr::from_ptr(port).to_str().unwrap();
    let backend_addr = CStr::from_ptr(backend_addr).to_str().unwrap();
    let backend_port = CStr::from_ptr(backend_port).to_str().unwrap();
    // SAFETY: Our caller promises that addr is a valid C string.
    let addr = unsafe { CStr::from_ptr(addr) }.to_str().unwrap();
    // SAFETY: Our caller promises that port is a valid C string.
    let port = unsafe { CStr::from_ptr(port) }.to_str().unwrap();
    // SAFETY: Our caller promises that backend_addr is a valid C string.
    let backend_addr = unsafe { CStr::from_ptr(backend_addr) }.to_str().unwrap();
    // SAFETY: Our caller promises that backend_port is a valid C string.
    let backend_port = unsafe { CStr::from_ptr(backend_port) }.to_str().unwrap();

    let socket_addr = to_socket_addr(addr, port).or_else(logging_and_return_err);
    let backend_socket_addr =
@@ -73,13 +77,19 @@ pub extern "C" fn frontend_stop(doh: &mut DohFrontend) -> bool {
/// If the caller has called `frontend_start` to start `DohFrontend`, it has to call
/// call `frontend_stop` to stop the worker thread before deleting the object.
///
/// The DohFrontend is not set to null pointer, caller needs to do it on its own.
///
/// # Safety
///
/// The DohFrontend is not set to null pointer, caller needs to do it on its own.
/// `doh` must be a pointer either null or previously returned by `frontend_new`, and not yet passed
/// to `frontend_delete`.
#[no_mangle]
pub unsafe extern "C" fn frontend_delete(doh: *mut DohFrontend) {
    if !doh.is_null() {
        drop(Box::from_raw(doh));
        // SAFETY: Our caller promised that `doh` was either null or previously returned by
        // `frontend_new`. We just checked that it's not null, so it must have been returned by
        // `frontend_new`, which obtained it from `Box::into_raw`.
        drop(unsafe { Box::from_raw(doh) });
    }
}

@@ -96,7 +106,8 @@ pub unsafe extern "C" fn frontend_set_certificate(
    if certificate.is_null() {
        return false;
    }
    let certificate = CStr::from_ptr(certificate).to_str().unwrap();
    // SAFETY: Our caller promises that certificate is a valid C string.
    let certificate = unsafe { CStr::from_ptr(certificate) }.to_str().unwrap();
    doh.set_certificate(certificate).or_else(logging_and_return_err).is_ok()
}

@@ -113,7 +124,8 @@ pub unsafe extern "C" fn frontend_set_private_key(
    if private_key.is_null() {
        return false;
    }
    let private_key = CStr::from_ptr(private_key).to_str().unwrap();
    // SAFETY: Our caller promises that private_key is a valid C string.
    let private_key = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
    doh.set_private_key(private_key).or_else(logging_and_return_err).is_ok()
}