1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Syd: rock-solid application kernel
// src/kernel/net/getsockname.rs: getsockname(2) handler
//
// Copyright (c) 2023, 2024, 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0
use libseccomp::ScmpNotifResp;
use nix::{errno::Errno, sys::socket::SockaddrLike};
use crate::{
compat::{fstatx, STATX_INO},
confine::is_valid_ptr,
fd::SafeOwnedFd,
req::UNotifyEventRequest,
unix::unix_addr_len,
};
pub(crate) fn handle_getsockname(
fd: SafeOwnedFd,
request: &UNotifyEventRequest,
args: &[u64; 6],
) -> Result<ScmpNotifResp, Errno> {
// Get socket inode.
let inode = fstatx(&fd, STATX_INO).map(|statx| statx.stx_ino)?;
drop(fd); // Close our copy of the socket.
// Lookup path by inode in sandbox unix map.
// peer=None check filters out connect(2).
let addr = if let Some(addr) = request.get_unix(inode).and_then(|unix| unix.addr) {
addr
} else {
// Not a UNIX domain socket, continue.
// SAFETY: No pointer-dereference in access check.
return unsafe { Ok(request.continue_syscall()) };
};
// Determine address length.
let addrlen = if args[2] != 0 {
const SIZEOF_SOCKLEN_T: usize = size_of::<libc::socklen_t>();
let mut buf = [0u8; SIZEOF_SOCKLEN_T];
if request.read_mem(&mut buf, args[2], SIZEOF_SOCKLEN_T)? == SIZEOF_SOCKLEN_T {
// libc defines socklen_t as u32.
// Linux rejects negative length.
let len = i32::from_ne_bytes(buf);
libc::socklen_t::try_from(len).or(Err(Errno::EINVAL))?
} else {
// Linux returns EFAULT for invalid address length pointer.
return Err(Errno::EFAULT);
}
} else {
// addrlen must not be NULL.
return Err(Errno::EFAULT);
};
// Linux writes address length before address.
//
// Convert address length into a vector of bytes.
let buf = unix_addr_len(&addr).to_ne_bytes();
// Write address length into memory.
request.write_mem_all(&buf, args[2])?;
// Linux doesn't dereference address for zero length.
if addrlen > 0 && !is_valid_ptr(args[1], request.scmpreq.data.arch) {
return Err(Errno::EFAULT);
}
// Write address buffer.
//
// Create a byte slice from the socket address pointer.
let ptr = addr.as_ptr() as *const u8;
let len = addr.len() as usize;
// SAFETY: `ptr` is a valid pointer to memory of at least `len`
// bytes, as it is provided by the `UnixAddr` instance.
let buf = unsafe { std::slice::from_raw_parts(ptr, len) };
// Write the truncated socket address into memory.
let len = len.min(addrlen as usize);
request.write_mem_all(&buf[..len], args[1])?;
Ok(request.return_syscall(0))
}