relibc: pass level via SocketCall wire format for set/get sockopt

DEF-P0-11 (Finding 1.7: option collision) from
NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md §3.4: the previous
relibc->netstack wire format was [SocketCall::SetSockOpt, option_name].
The netstack dispatched on option only, with no level. Options that
share a numeric value across levels collided silently:
- option 4: TCP_KEEPIDLE (SOL_SOCKET) vs IP_TOS (IPPROTO_IP)
- option 2: TCP_MAXSEG (IPPROTO_TCP) vs IP_TTL (IPPROTO_IP) vs
  SO_REUSEADDR (SOL_SOCKET)

Wire format fix: [SocketCall::Set/GetSockOpt, level, option_name].
The netstack trait SocketT now takes (level, name) separately so each
impl can dispatch on both. The stale 'TODO convert back to match
when we support more levels' comment in setsockopt is removed
(the level is now passed in the wire format directly).

Also matches the netstack scheme/socket.rs dispatch which already
reads metadata[1] as level and metadata[2] as option.
This commit is contained in:
Red Bear OS
2026-07-27 18:02:15 +09:00
parent ccd379c660
commit 06bd61d0fc
+19 -4
View File
@@ -860,7 +860,14 @@ unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
return Ok(());
}
_ => {
let metadata = [SocketCall::GetSockOpt as u64, option_name as u64];
// Wire format: [SocketCall::GetSockOpt, level, option]
// Level disambiguates option 4 (TCP_KEEPIDLE at SOL_SOCKET)
// from option 4 (IP_TOS at IPPROTO_IP) etc.
let metadata = [
SocketCall::GetSockOpt as u64,
level as u64,
option_name as u64,
];
let payload =
// SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(option_value.cast::<u8>(), option_len) };
@@ -1206,18 +1213,26 @@ unsafe { &*option_value.cast::<timeval>() };
Ok(())
};
// TODO convert back to match when we support more levels
// Wire format: [SocketCall::SetSockOpt, level, option]
// The netstack dispatches on level + option together. Without
// level in the wire format, option 4 (TCP_KEEPIDLE at SOL_SOCKET)
// reads as IP_TOS (also option 4) at IPPROTO_IP. See
// NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md §3.4
// (Finding 1.7: option collision).
if level == SOL_SOCKET {
match option_name {
SO_RCVTIMEO => return set_timeout(b"read_timeout"),
SO_SNDTIMEO => return set_timeout(b"write_timeout"),
_ => {
let metadata = [SocketCall::SetSockOpt as u64, option_name as u64];
let metadata = [
SocketCall::SetSockOpt as u64,
level as u64,
option_name as u64,
];
let payload = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(option_value as *mut u8, option_len as usize)
};
let call_flags = CallFlags::empty();
redox_rt::sys::sys_call_rw(
socket as usize,
payload,