{"record":{"id":"0545dff8c0dd9726","repo":"shadowsocks/shadowsocks-rust","slug":"sockaddr-as-socket","errorCode":null,"errorMessage":"SockAddr.as_socket","messagePattern":"SockAddr\\.as_socket","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks/src/net/sys/unix/linux/mod.rs","lineNumber":457,"sourceCode":"fn recvmsg_fallback<S: AsRawFd>(sock: &S, msg: &mut BatchRecvMessage<'_>) -> io::Result<()> {\n    let mut hdr: libc::msghdr = unsafe { mem::zeroed() };\n\n    let addr_storage = SockAddrStorage::zeroed();\n    let addr_len = addr_storage.size_of() as libc::socklen_t;\n\n    let sock_addr = unsafe { SockAddr::new(addr_storage, addr_len) };\n    hdr.msg_name = sock_addr.as_ptr() as *mut _;\n    hdr.msg_namelen = sock_addr.len() as _;\n\n    hdr.msg_iov = msg.data.as_ptr() as *mut _;\n    hdr.msg_iovlen = msg.data.len() as _;\n\n    let ret = unsafe { libc::recvmsg(sock.as_raw_fd(), &mut hdr as *mut _, 0) };\n    if ret < 0 {\n        return Err(io::Error::last_os_error());\n    }\n\n    msg.addr = sock_addr.as_socket().expect(\"SockAddr.as_socket\");\n    msg.data_len = ret as usize;\n\n    Ok(())\n}\n\npub fn batch_recvmsg<S: AsRawFd>(sock: &S, msgs: &mut [BatchRecvMessage<'_>]) -> io::Result<usize> {\n    if msgs.is_empty() {\n        return Ok(0);\n    }\n\n    if !SUPPORT_BATCH_SEND_RECV_MSG.load(Ordering::Relaxed) {\n        recvmsg_fallback(sock, &mut msgs[0])?;\n        return Ok(1);\n    }\n\n    let mut vec_msg_name = Vec::with_capacity(msgs.len());\n    let mut vec_msg_hdr = Vec::with_capacity(msgs.len());\n","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks/src/net/sys/unix/linux/mod.rs#L439-L475","documentation":"In the Linux fast-path UDP recvmsg wrapper, the socket address filled by the kernel is converted with SockAddr::as_socket() and unwrapped with expect(). as_socket returns None if the stored address family is not AF_INET/AF_INET6. The library assumes recvmsg on a UDP socket always yields a valid internet socket address, so a foreign family (e.g. AF_UNSPEC/AF_UNIX) is an invariant violation and panics.","triggerScenarios":"Calling batch_recvmsg/recvmsg_fallback on a UDP socket when the kernel returns a sender address whose family is not AF_INET or AF_INET6 — e.g. recvmsg returning a truncated/zeroed sockaddr, or the socket somehow being bound to a non-internet family.","commonSituations":"Rare kernel/edge cases on Linux where msg_name is not populated as AF_INET/6; misuse of the internal net::sys API with a non-UDP socket; unusual socket setups (e.g. raw or unix sockets passed into the batch-recv path).","solutions":["Replace expect() with graceful handling: if as_socket() returns None, return an io::Error (e.g. ErrorKind::InvalidData) instead of panicking","Ensure only AF_INET/AF_INET6 UDP sockets are passed to this receive path","Check for invalid/zero-length msg_name before conversion and skip/normalize the address"],"exampleFix":"// before\nmsg.addr = sock_addr.as_socket().expect(\"SockAddr.as_socket\");\n// after\nmsg.addr = sock_addr.as_socket().ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, \"recvmsg returned non-internet address\"))?;","handlingStrategy":"try-catch","validationCode":"// ensure socket family before use\nassert!(matches!(socket.local_addr()?.family(), AF_INET | AF_INET6));","typeGuard":"fn is_inet_sockaddr(sa: &SockAddr) -> bool { matches!(sa.family(), AF_INET | AF_INET6) }","tryCatchPattern":"match sock_addr.as_socket() {\n    Some(a) => msg.addr = a,\n    None => return Err(io::Error::new(io::ErrorKind::InvalidData, \"non-internet sender address\")),\n}","preventionTips":["Only pass AF_INET/AF_INET6 UDP sockets to the batch recv path","Patch the library to convert None into an io::Error instead of panicking","Watch for kernel quirks on the Linux versions you deploy"],"tags":["rust","udp","panic","linux","networking"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}