From 39ce623d2df545a6ebea65038e4882b2bbef08c1 Mon Sep 17 00:00:00 2001
From: jD91mZM2 <me@krake.one>
Date: Mon, 29 Jun 2020 11:36:07 +0200
Subject: [PATCH] Fix bind/connect's AF_UNIX socket path... again

I don't really know for sure what all these silly rules are, but I think
I got it now...
---
 src/header/sys_un/mod.rs     |  2 +-
 src/platform/redox/socket.rs | 24 +++++++++++++++++++++---
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/src/header/sys_un/mod.rs b/src/header/sys_un/mod.rs
index b5738899..63d26c8f 100644
--- a/src/header/sys_un/mod.rs
+++ b/src/header/sys_un/mod.rs
@@ -7,7 +7,7 @@ pub struct sockaddr_un {
 }
 
 impl sockaddr_un {
-    pub fn path_len(&self) -> usize {
+    pub fn path_offset(&self) -> usize {
         let base = self as *const _ as usize;
         let path = &self.sun_path as *const _ as usize;
         trace!("base: {:#X}, path: {:#X}", base, path);
diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs
index 60ecdcd6..c7e55088 100644
--- a/src/platform/redox/socket.rs
+++ b/src/platform/redox/socket.rs
@@ -9,6 +9,7 @@ use super::{
 use crate::header::{
     arpa_inet::inet_aton,
     netinet_in::{in_port_t, sockaddr_in, in_addr},
+    string::strnlen,
     sys_socket::{constants::*, sa_family_t, sockaddr, socklen_t},
     sys_time::timeval,
     sys_un::sockaddr_un,
@@ -62,15 +63,32 @@ macro_rules! bind_or_connect {
             },
             AF_UNIX => {
                 let data = &*($address as *const sockaddr_un);
-                trace!("address: {:p}, data: {:p}, data2: {:#X}", $address, data, data as *const _ as usize);
+
+                // NOTE: It's UB to access data in given address that exceeds
+                // the given address length.
+
+                let maxlen = cmp::min(
+                    // Max path length of the full-sized struct
+                    data.sun_path.len(),
+                    // Length inferred from given addrlen
+                    $address_len as usize - data.path_offset()
+                );
+                let len = cmp::min(
+                    // The maximum length of the address
+                    maxlen,
+                    // The first NUL byte, if any
+                    strnlen(&data.sun_path as *const _, maxlen as size_t),
+                );
+
                 let addr = slice::from_raw_parts(
                     &data.sun_path as *const _ as *const u8,
-                    $address_len as usize - data.path_len(),
+                    len,
                 );
                 let path = format!(
                     "{}",
                     str::from_utf8(addr).unwrap()
                 );
+                trace!("path: {:?}", path);
 
                 path
             },
@@ -96,7 +114,7 @@ unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut so
 
     let path = slice::from_raw_parts_mut(
         &mut data.sun_path as *mut _ as *mut u8,
-        data.path_len(),
+        data.sun_path.len(),
     );
 
     let len = cmp::min(path.len(), buf.len());
-- 
GitLab