starnix_core/vfs/socket/
socket_backed_by_zxio.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::bpf::attachments::{SockAddrOp, SockAddrProgramResult, SockOp, SockProgramResult};
6use crate::fs::fuchsia::zxio::{zxio_query_events, zxio_wait_async};
7use crate::mm::{MemoryAccessorExt, UNIFIED_ASPACES_ENABLED};
8use crate::security;
9use crate::task::syscalls::SockFProgPtr;
10use crate::task::{CurrentTask, EventHandler, Task, WaitCanceler, Waiter};
11use crate::vfs::socket::socket::ReadFromSockOptValue as _;
12use crate::vfs::socket::{
13    SockOptValue, Socket, SocketAddress, SocketDomain, SocketHandle, SocketMessageFlags, SocketOps,
14    SocketPeer, SocketProtocol, SocketShutdownFlags, SocketType,
15};
16use crate::vfs::{AncillaryData, InputBuffer, MessageReadInfo, OutputBuffer};
17use byteorder::ByteOrder;
18use ebpf::convert_and_verify_cbpf;
19use ebpf_api::SOCKET_FILTER_CBPF_CONFIG;
20use fidl::endpoints::DiscoverableProtocolMarker as _;
21use linux_uapi::{IP_MULTICAST_ALL, IP_PASSSEC};
22use starnix_logging::{log_warn, track_stub};
23use starnix_sync::{FileOpsCore, Locked};
24use starnix_uapi::auth::{CAP_NET_ADMIN, CAP_NET_RAW};
25use starnix_uapi::errors::{ENOTSUP, Errno, ErrnoCode};
26use starnix_uapi::vfs::FdEvents;
27use starnix_uapi::{
28    AF_PACKET, BPF_MAXINSNS, MSG_DONTWAIT, MSG_WAITALL, SO_ATTACH_FILTER, SO_BINDTODEVICE,
29    SO_BINDTOIFINDEX, SO_COOKIE, c_int, errno, errno_from_zxio_code, error, from_status_like_fdio,
30    sock_filter, uapi, ucred,
31};
32use static_assertions::const_assert_eq;
33use std::mem::size_of;
34use std::sync::OnceLock;
35use syncio::zxio::{
36    IP_RECVERR, SO_DOMAIN, SO_FUCHSIA_MARK, SO_MARK, SO_PROTOCOL, SO_TYPE, SOL_IP, SOL_SOCKET,
37    ZXIO_SOCKET_MARK_DOMAIN_1, ZXIO_SOCKET_MARK_DOMAIN_2, zxio_socket_mark,
38};
39use syncio::{
40    ControlMessage, RecvMessageInfo, ServiceConnector, Zxio, ZxioErrorCode,
41    ZxioSocketCreationOptions, ZxioSocketMark, ZxioWakeGroupToken,
42};
43use zerocopy::IntoBytes;
44use {
45    fidl_fuchsia_posix_socket as fposix_socket,
46    fidl_fuchsia_posix_socket_packet as fposix_socket_packet,
47    fidl_fuchsia_posix_socket_raw as fposix_socket_raw,
48};
49
50/// Linux marks aren't compatible with Fuchsia marks, we store the `SO_MARK`
51/// value in the fuchsia `ZXIO_SOCKET_MARK_DOMAIN_1`. If a mark in this domain
52/// is absent, it will be reported to starnix applications as a `0` since that
53/// is the default mark value on Linux.
54pub const ZXIO_SOCKET_MARK_SO_MARK: u8 = ZXIO_SOCKET_MARK_DOMAIN_1;
55/// Fuchsia does not have uids, we use the `ZXIO_SOCKET_MARK_DOMAIN_2` on the
56/// socket to store the UID for the sockets created by starnix.
57pub const ZXIO_SOCKET_MARK_UID: u8 = ZXIO_SOCKET_MARK_DOMAIN_2;
58
59/// Connects to the appropriate `fuchsia_posix_socket_*::Provider` protocol.
60struct SocketProviderServiceConnector;
61
62impl ServiceConnector for SocketProviderServiceConnector {
63    fn connect(service_name: &str) -> Result<&'static zx::Channel, zx::Status> {
64        match service_name {
65            fposix_socket::ProviderMarker::PROTOCOL_NAME => {
66                static CHANNEL: OnceLock<Result<zx::Channel, zx::Status>> = OnceLock::new();
67                &CHANNEL
68            }
69            fposix_socket_packet::ProviderMarker::PROTOCOL_NAME => {
70                static CHANNEL: OnceLock<Result<zx::Channel, zx::Status>> = OnceLock::new();
71                &CHANNEL
72            }
73            fposix_socket_raw::ProviderMarker::PROTOCOL_NAME => {
74                static CHANNEL: OnceLock<Result<zx::Channel, zx::Status>> = OnceLock::new();
75                &CHANNEL
76            }
77            _ => return Err(zx::Status::INTERNAL),
78        }
79        .get_or_init(|| {
80            let (client, server) = zx::Channel::create();
81            let protocol_path = format!("/svc/{service_name}");
82            fdio::service_connect(&protocol_path, server)?;
83            Ok(client)
84        })
85        .as_ref()
86        .map_err(|status| *status)
87    }
88}
89
90// Trait for types that can be converted to a byte vector that contains a
91// `sockaddr` value.
92trait AsSockAddrBytes {
93    fn as_sockaddr_bytes(&self) -> Result<&[u8], Errno>;
94}
95
96impl AsSockAddrBytes for &SocketAddress {
97    fn as_sockaddr_bytes(&self) -> Result<&[u8], Errno> {
98        match self {
99            SocketAddress::Inet(addr) => Ok(&addr[..]),
100            SocketAddress::Inet6(addr) => Ok(&addr[..]),
101            _ => error!(EAFNOSUPPORT),
102        }
103    }
104}
105
106impl AsSockAddrBytes for &Vec<u8> {
107    fn as_sockaddr_bytes(&self) -> Result<&[u8], Errno> {
108        Ok(self.as_slice())
109    }
110}
111
112/// A socket backed by an underlying Zircon I/O object.
113pub struct ZxioBackedSocket {
114    /// The underlying Zircon I/O object.
115    zxio: syncio::Zxio,
116
117    // SO_COOKIE cache.
118    cookie: OnceLock<u64>,
119}
120
121impl ZxioBackedSocket {
122    pub fn new(
123        locked: &mut Locked<FileOpsCore>,
124        current_task: &CurrentTask,
125        domain: SocketDomain,
126        socket_type: SocketType,
127        protocol: SocketProtocol,
128    ) -> Result<ZxioBackedSocket, Errno> {
129        let marks = &mut [
130            ZxioSocketMark::so_mark(0),
131            ZxioSocketMark::uid(current_task.current_creds().uid),
132        ];
133
134        match (domain, socket_type, protocol) {
135            (SocketDomain::Inet, SocketType::Datagram, SocketProtocol::ICMP)
136            | (SocketDomain::Inet6, SocketType::Datagram, SocketProtocol::ICMPV6) => {
137                let gid_range =
138                    current_task.kernel().system_limits.socket.icmp_ping_gids.lock().clone();
139                if !gid_range.contains(&current_task.current_creds().egid) {
140                    return error!(EACCES);
141                }
142            }
143            _ => (),
144        };
145
146        let zxio = Zxio::new_socket::<SocketProviderServiceConnector>(
147            domain.as_raw() as c_int,
148            socket_type.as_raw() as c_int,
149            protocol.as_raw() as c_int,
150            ZxioSocketCreationOptions {
151                marks,
152                // TODO(https://fxbug.dev/434263247): register sockets in a wake group.
153                wake_group: ZxioWakeGroupToken::new(None),
154            },
155        )
156        .map_err(|status| from_status_like_fdio!(status))?
157        .map_err(|out_code| errno_from_zxio_code!(out_code))?;
158
159        let socket = Self::new_with_zxio(current_task, zxio);
160
161        if matches!(domain, SocketDomain::Inet | SocketDomain::Inet6) {
162            match current_task.kernel().ebpf_state.attachments.root_cgroup().run_sock_prog(
163                locked,
164                current_task,
165                SockOp::Create,
166                domain,
167                socket_type,
168                protocol,
169                &socket,
170            ) {
171                SockProgramResult::Allow => (),
172                SockProgramResult::Block => return error!(EPERM),
173            }
174        }
175
176        Ok(socket)
177    }
178
179    pub fn new_with_zxio(current_task: &CurrentTask, zxio: syncio::Zxio) -> ZxioBackedSocket {
180        let uid = current_task.current_creds().euid;
181        let resolver = current_task
182            .kernel()
183            .socket_tokens_store
184            .get_token_resolver(current_task.kernel(), uid);
185        let zxio = zxio.with_token_resolver(resolver);
186        ZxioBackedSocket { zxio, cookie: Default::default() }
187    }
188
189    fn sendmsg(
190        &self,
191        locked: &mut Locked<FileOpsCore>,
192        socket: &Socket,
193        current_task: &CurrentTask,
194        addr: &Option<SocketAddress>,
195        data: &mut dyn InputBuffer,
196        cmsgs: Vec<ControlMessage>,
197        flags: SocketMessageFlags,
198    ) -> Result<usize, Errno> {
199        let mut addr = match addr {
200            Some(
201                SocketAddress::Inet(sockaddr)
202                | SocketAddress::Inet6(sockaddr)
203                | SocketAddress::Packet(sockaddr),
204            ) => sockaddr.clone(),
205            Some(_) => return error!(EINVAL),
206            None => vec![],
207        };
208
209        // Run `CGROUP_UDP[46]_SENDMSG` eBPF programs for `sendto()` and
210        // `sendmsg()` on UDP sockets. Not necessary for `send()` (i.e. when
211        // `addr` is empty).
212        if matches!(
213            (socket.domain, socket.socket_type),
214            (SocketDomain::Inet | SocketDomain::Inet6, SocketType::Datagram)
215        ) && addr.len() > 0
216        {
217            self.run_sockaddr_ebpf(locked, socket, current_task, SockAddrOp::UdpSendMsg, &addr)?;
218        }
219
220        let map_errors = |res: Result<Result<usize, ZxioErrorCode>, zx::Status>| {
221            res.map_err(|status| match status {
222                zx::Status::OUT_OF_RANGE => errno!(EMSGSIZE),
223                other => from_status_like_fdio!(other),
224            })?
225            .map_err(|out_code| errno_from_zxio_code!(out_code))
226        };
227
228        let flags = flags.bits() & !MSG_DONTWAIT;
229        let sent_bytes = if UNIFIED_ASPACES_ENABLED {
230            match data.peek_all_segments_as_iovecs() {
231                Ok(mut iovecs) => {
232                    Some(map_errors(self.zxio.sendmsg(&mut addr, &mut iovecs, &cmsgs, flags))?)
233                }
234                Err(e) if e.code == ENOTSUP => None,
235                Err(e) => return Err(e),
236            }
237        } else {
238            None
239        };
240
241        // If we can't pass the iovecs directly so fallback to reading
242        // all the bytes from the input buffer first.
243        let sent_bytes = match sent_bytes {
244            Some(sent_bytes) => sent_bytes,
245            None => {
246                let mut bytes = data.peek_all()?;
247                map_errors(self.zxio.sendmsg(
248                    &mut addr,
249                    &mut [syncio::zxio::iovec {
250                        iov_base: bytes.as_mut_ptr() as *mut starnix_uapi::c_void,
251                        iov_len: bytes.len(),
252                    }],
253                    &cmsgs,
254                    flags,
255                ))?
256            }
257        };
258        data.advance(sent_bytes)?;
259        Ok(sent_bytes)
260    }
261
262    fn recvmsg(
263        &self,
264        locked: &mut Locked<FileOpsCore>,
265        socket: &Socket,
266        current_task: &CurrentTask,
267        data: &mut dyn OutputBuffer,
268        flags: SocketMessageFlags,
269    ) -> Result<RecvMessageInfo, Errno> {
270        let flags = flags.bits() & !MSG_DONTWAIT & !MSG_WAITALL;
271
272        let map_errors = |res: Result<Result<RecvMessageInfo, ZxioErrorCode>, zx::Status>| {
273            res.map_err(|status| from_status_like_fdio!(status))?
274                .map_err(|out_code| errno_from_zxio_code!(out_code))
275        };
276
277        let info = if UNIFIED_ASPACES_ENABLED {
278            match data.peek_all_segments_as_iovecs() {
279                Ok(mut iovecs) => {
280                    let info = map_errors(self.zxio.recvmsg(&mut iovecs, flags))?;
281                    // SAFETY: we successfully read `info.bytes_read` bytes
282                    // directly to the user's buffer segments.
283                    (unsafe { data.advance(info.bytes_read) })?;
284                    Some(info)
285                }
286                Err(e) if e.code == ENOTSUP => None,
287                Err(e) => return Err(e),
288            }
289        } else {
290            None
291        };
292
293        // If we can't pass the segments directly, fallback to receiving
294        // all the bytes in an intermediate buffer and writing that
295        // to our output buffer.
296        let info = match info {
297            Some(info) => info,
298            None => {
299                // TODO: use MaybeUninit
300                let mut buf = vec![0; data.available()];
301                let iovec = &mut [syncio::zxio::iovec {
302                    iov_base: buf.as_mut_ptr() as *mut starnix_uapi::c_void,
303                    iov_len: buf.len(),
304                }];
305                let info = map_errors(self.zxio.recvmsg(iovec, flags))?;
306                let written = data.write_all(&buf[..info.bytes_read])?;
307                debug_assert_eq!(written, info.bytes_read);
308                info
309            }
310        };
311
312        // Run eBPF programs for UDP sockets.
313        if matches!(
314            (socket.domain, socket.socket_type),
315            (SocketDomain::Inet | SocketDomain::Inet6, SocketType::Datagram)
316        ) {
317            self.run_sockaddr_ebpf(
318                locked,
319                socket,
320                current_task,
321                SockAddrOp::UdpRecvMsg,
322                &info.address,
323            )?;
324        }
325
326        Ok(info)
327    }
328
329    fn attach_cbpf_filter(&self, _task: &Task, code: Vec<sock_filter>) -> Result<(), Errno> {
330        // SO_ATTACH_FILTER is supported only for packet sockets.
331        let domain = self
332            .zxio
333            .getsockopt(SOL_SOCKET, SO_DOMAIN, size_of::<u32>() as u32)
334            .map_err(|status| from_status_like_fdio!(status))?
335            .map_err(|out_code| errno_from_zxio_code!(out_code))?;
336        let domain = u32::from_ne_bytes(domain.try_into().unwrap());
337        if domain != u32::from(AF_PACKET) {
338            return error!(ENOTSUP);
339        }
340
341        let program = convert_and_verify_cbpf(
342            &code,
343            ebpf_api::SOCKET_FILTER_SK_BUF_TYPE.clone(),
344            &SOCKET_FILTER_CBPF_CONFIG,
345        )
346        .map_err(|_| errno!(EINVAL))?;
347
348        // TODO(https://fxbug.dev/377332291) Use `zxio_borrow()` to avoid cloning the handle.
349        let packet_socket = fidl::endpoints::ClientEnd::<fposix_socket_packet::SocketMarker>::new(
350            self.zxio.clone_handle().map_err(|_| errno!(EIO))?.into(),
351        )
352        .into_sync_proxy();
353        let code = program.to_code();
354        let code: &[u64] = zerocopy::transmute_ref!(code.as_slice());
355        let result = packet_socket.attach_bpf_filter_unsafe(code, zx::MonotonicInstant::INFINITE);
356        result.map_err(|_: fidl::Error| errno!(EIO))?.map_err(|e| {
357            Errno::with_context(
358                ErrnoCode::from_error_code(e.into_primitive() as i16),
359                "AttachBfpFilterUnsafe",
360            )
361        })
362    }
363
364    fn run_sockaddr_ebpf(
365        &self,
366        locked: &mut Locked<FileOpsCore>,
367        socket: &Socket,
368        current_task: &CurrentTask,
369        op: SockAddrOp,
370        socket_address: impl AsSockAddrBytes,
371    ) -> Result<(), Errno> {
372        // BPF_PROG_TYPE_CGROUP_SOCK_ADDR programs are executed only for IPv4 and IPv6 sockets.
373        if !matches!(socket.domain, SocketDomain::Inet | SocketDomain::Inet6) {
374            return Ok(());
375        }
376
377        let ebpf_result =
378            current_task.kernel().ebpf_state.attachments.root_cgroup().run_sock_addr_prog(
379                locked,
380                current_task,
381                op,
382                socket.domain,
383                socket.socket_type,
384                socket.protocol,
385                socket_address.as_sockaddr_bytes()?,
386                self,
387            )?;
388        match ebpf_result {
389            SockAddrProgramResult::Allow => Ok(()),
390            SockAddrProgramResult::Block => error!(EPERM),
391        }
392    }
393
394    pub fn get_socket_cookie(&self) -> Result<u64, Errno> {
395        if let Some(cookie) = self.cookie.get() {
396            return Ok(*cookie);
397        }
398
399        let cookie = u64::from_ne_bytes(
400            self.zxio
401                .getsockopt(SOL_SOCKET, SO_COOKIE, size_of::<u64>() as u32)
402                .map_err(|status| from_status_like_fdio!(status))?
403                .map_err(|out_code| errno_from_zxio_code!(out_code))?
404                .try_into()
405                .unwrap(),
406        );
407        let _: Result<(), u64> = self.cookie.set(cookie);
408
409        return Ok(cookie);
410    }
411}
412
413impl SocketOps for ZxioBackedSocket {
414    fn get_socket_info(&self) -> Result<(SocketDomain, SocketType, SocketProtocol), Errno> {
415        let getsockopt = |optname: u32| -> Result<u32, Errno> {
416            Ok(u32::from_ne_bytes(
417                self.zxio
418                    .getsockopt(SOL_SOCKET, optname, size_of::<u32>() as u32)
419                    .map_err(|status| from_status_like_fdio!(status))?
420                    .map_err(|out_code| errno_from_zxio_code!(out_code))?
421                    .try_into()
422                    .unwrap(),
423            ))
424        };
425
426        let domain_raw = getsockopt(SO_DOMAIN)?;
427        let domain = SocketDomain::from_raw(domain_raw.try_into().map_err(|_| errno!(EINVAL))?)
428            .ok_or_else(|| errno!(EINVAL))?;
429
430        let type_raw = getsockopt(SO_TYPE)?;
431        let socket_type = SocketType::from_raw(type_raw).ok_or_else(|| errno!(EINVAL))?;
432
433        let protocol_raw = getsockopt(SO_PROTOCOL)?;
434        let protocol = SocketProtocol::from_raw(protocol_raw);
435
436        Ok((domain, socket_type, protocol))
437    }
438
439    fn connect(
440        &self,
441        locked: &mut Locked<FileOpsCore>,
442        socket: &SocketHandle,
443        current_task: &CurrentTask,
444        peer: SocketPeer,
445    ) -> Result<(), Errno> {
446        match peer {
447            SocketPeer::Address(
448                ref address @ (SocketAddress::Inet(_) | SocketAddress::Inet6(_)),
449            ) => {
450                self.run_sockaddr_ebpf(locked, socket, current_task, SockAddrOp::Connect, address)?
451            }
452            _ => (),
453        };
454
455        match peer {
456            SocketPeer::Address(
457                SocketAddress::Inet(addr)
458                | SocketAddress::Inet6(addr)
459                | SocketAddress::Packet(addr),
460            ) => self
461                .zxio
462                .connect(&addr)
463                .map_err(|status| from_status_like_fdio!(status))?
464                .map_err(|out_code| errno_from_zxio_code!(out_code)),
465            _ => error!(EINVAL),
466        }
467    }
468
469    fn listen(
470        &self,
471        _locked: &mut Locked<FileOpsCore>,
472        _socket: &Socket,
473        backlog: i32,
474        _credentials: ucred,
475    ) -> Result<(), Errno> {
476        self.zxio
477            .listen(backlog)
478            .map_err(|status| from_status_like_fdio!(status))?
479            .map_err(|out_code| errno_from_zxio_code!(out_code))
480    }
481
482    fn accept(
483        &self,
484        _locked: &mut Locked<FileOpsCore>,
485        socket: &Socket,
486        current_task: &CurrentTask,
487    ) -> Result<SocketHandle, Errno> {
488        let zxio = self
489            .zxio
490            .accept()
491            .map_err(|status| from_status_like_fdio!(status))?
492            .map_err(|out_code| errno_from_zxio_code!(out_code))?;
493
494        Ok(Socket::new_with_ops_and_info(
495            Box::new(Self::new_with_zxio(current_task, zxio)),
496            socket.domain,
497            socket.socket_type,
498            socket.protocol,
499        ))
500    }
501
502    fn bind(
503        &self,
504        locked: &mut Locked<FileOpsCore>,
505        socket: &Socket,
506        current_task: &CurrentTask,
507        socket_address: SocketAddress,
508    ) -> Result<(), Errno> {
509        self.run_sockaddr_ebpf(locked, socket, current_task, SockAddrOp::Bind, &socket_address)?;
510
511        match socket_address {
512            SocketAddress::Inet(addr)
513            | SocketAddress::Inet6(addr)
514            | SocketAddress::Packet(addr) => self
515                .zxio
516                .bind(&addr)
517                .map_err(|status| from_status_like_fdio!(status))?
518                .map_err(|out_code| errno_from_zxio_code!(out_code)),
519            _ => error!(EINVAL),
520        }
521    }
522
523    fn read(
524        &self,
525        locked: &mut Locked<FileOpsCore>,
526        socket: &Socket,
527        current_task: &CurrentTask,
528        data: &mut dyn OutputBuffer,
529        flags: SocketMessageFlags,
530    ) -> Result<MessageReadInfo, Errno> {
531        // MSG_ERRQUEUE is not supported for TCP sockets, but it's expected to fail with EAGAIN.
532        if socket.socket_type == SocketType::Stream && flags.contains(SocketMessageFlags::ERRQUEUE)
533        {
534            return error!(EAGAIN);
535        }
536
537        let mut info = self.recvmsg(locked, socket, current_task, data, flags)?;
538
539        let bytes_read = info.bytes_read;
540
541        let address = if !info.address.is_empty() {
542            Some(SocketAddress::from_bytes(info.address)?)
543        } else {
544            None
545        };
546
547        Ok(MessageReadInfo {
548            bytes_read,
549            message_length: info.message_length,
550            address,
551            ancillary_data: info.control_messages.drain(..).map(AncillaryData::Ip).collect(),
552        })
553    }
554
555    fn write(
556        &self,
557        locked: &mut Locked<FileOpsCore>,
558        socket: &Socket,
559        current_task: &CurrentTask,
560        data: &mut dyn InputBuffer,
561        dest_address: &mut Option<SocketAddress>,
562        ancillary_data: &mut Vec<AncillaryData>,
563    ) -> Result<usize, Errno> {
564        let mut cmsgs = vec![];
565        for d in ancillary_data.drain(..) {
566            match d {
567                AncillaryData::Ip(msg) => cmsgs.push(msg),
568                _ => return error!(EINVAL),
569            }
570        }
571
572        // Ignore destination address if this is a stream socket.
573        let dest_address =
574            if socket.socket_type == SocketType::Stream { &None } else { dest_address };
575        self.sendmsg(
576            locked,
577            socket,
578            current_task,
579            dest_address,
580            data,
581            cmsgs,
582            SocketMessageFlags::empty(),
583        )
584    }
585
586    fn wait_async(
587        &self,
588        _locked: &mut Locked<FileOpsCore>,
589        _socket: &Socket,
590        _current_task: &CurrentTask,
591        waiter: &Waiter,
592        events: FdEvents,
593        handler: EventHandler,
594    ) -> WaitCanceler {
595        zxio_wait_async(&self.zxio, waiter, events, handler)
596    }
597
598    fn query_events(
599        &self,
600        _locked: &mut Locked<FileOpsCore>,
601        _socket: &Socket,
602        _current_task: &CurrentTask,
603    ) -> Result<FdEvents, Errno> {
604        zxio_query_events(&self.zxio)
605    }
606
607    fn shutdown(
608        &self,
609        _locked: &mut Locked<FileOpsCore>,
610        _socket: &Socket,
611        how: SocketShutdownFlags,
612    ) -> Result<(), Errno> {
613        self.zxio
614            .shutdown(how)
615            .map_err(|status| from_status_like_fdio!(status))?
616            .map_err(|out_code| errno_from_zxio_code!(out_code))
617    }
618
619    fn close(&self, locked: &mut Locked<FileOpsCore>, current_task: &CurrentTask, socket: &Socket) {
620        if matches!(socket.domain, SocketDomain::Inet | SocketDomain::Inet6) {
621            // Invoke eBPF release program (if any). Result is ignored since we cannot block
622            // socket release.
623            let _: SockProgramResult =
624                current_task.kernel().ebpf_state.attachments.root_cgroup().run_sock_prog(
625                    locked,
626                    current_task,
627                    SockOp::Release,
628                    socket.domain,
629                    socket.socket_type,
630                    socket.protocol,
631                    self,
632                );
633        }
634
635        let _ = self.zxio.close();
636    }
637
638    fn getsockname(
639        &self,
640        _locked: &mut Locked<FileOpsCore>,
641        socket: &Socket,
642    ) -> Result<SocketAddress, Errno> {
643        match self.zxio.getsockname() {
644            Err(_) | Ok(Err(_)) => Ok(SocketAddress::default_for_domain(socket.domain)),
645            Ok(Ok(addr)) => SocketAddress::from_bytes(addr),
646        }
647    }
648
649    fn getpeername(
650        &self,
651        _locked: &mut Locked<FileOpsCore>,
652        _socket: &Socket,
653    ) -> Result<SocketAddress, Errno> {
654        self.zxio
655            .getpeername()
656            .map_err(|status| from_status_like_fdio!(status))?
657            .map_err(|out_code| errno_from_zxio_code!(out_code))
658            .and_then(SocketAddress::from_bytes)
659    }
660
661    fn setsockopt(
662        &self,
663        _locked: &mut Locked<FileOpsCore>,
664        _socket: &Socket,
665        current_task: &CurrentTask,
666        level: u32,
667        optname: u32,
668        optval: SockOptValue,
669    ) -> Result<(), Errno> {
670        match (level, optname) {
671            (SOL_SOCKET, SO_ATTACH_FILTER) => {
672                let fprog = SockFProgPtr::read_from_sockopt_value(current_task, &optval)?;
673                if fprog.len > BPF_MAXINSNS || fprog.len == 0 {
674                    return error!(EINVAL);
675                }
676                let code: Vec<sock_filter> = current_task
677                    .read_multi_arch_objects_to_vec(fprog.filter, fprog.len as usize)?;
678                return self.attach_cbpf_filter(current_task, code);
679            }
680            (SOL_IP, IP_RECVERR) => {
681                track_stub!(TODO("https://fxbug.dev/333060595"), "SOL_IP.IP_RECVERR");
682                return Ok(());
683            }
684            (SOL_IP, IP_MULTICAST_ALL) => {
685                track_stub!(TODO("https://fxbug.dev/404596095"), "SOL_IP.IP_MULTICAST_ALL");
686                return Ok(());
687            }
688            (SOL_IP, IP_PASSSEC) if current_task.kernel().features.selinux_test_suite => {
689                track_stub!(TODO("https://fxbug.dev/398663317"), "SOL_IP.IP_PASSSEC");
690                return Ok(());
691            }
692            (SOL_SOCKET, SO_MARK) => {
693                // Either `CAP_NET_RAW` or `CAP_NET_ADMIN` is required to set
694                // `SO_MARK`. If `CAP_NET_RAW` is not present, we then check
695                // `CAP_NET_ADMIN` using `check_task_capable`, which will
696                // generate an audit record if the capability is missing.
697                if !security::is_task_capable_noaudit(current_task, CAP_NET_RAW) {
698                    security::check_task_capable(current_task, CAP_NET_ADMIN)?;
699                }
700
701                let mark: u32 = optval.read(current_task)?;
702                let socket_mark = ZxioSocketMark::so_mark(mark);
703                let optval: &[u8; size_of::<zxio_socket_mark>()] =
704                    zerocopy::transmute_ref!(&socket_mark);
705                return self
706                    .zxio
707                    .setsockopt(SOL_SOCKET as i32, SO_FUCHSIA_MARK as i32, optval)
708                    .map_err(|status| from_status_like_fdio!(status))?
709                    .map_err(|out_code| errno_from_zxio_code!(out_code));
710            }
711            (SOL_SOCKET, SO_BINDTODEVICE | SO_BINDTOIFINDEX) => {
712                // Require `CAP_NET_RAW` to bind the socket to a device. This
713                // is consistent with Linux prior to 5.7. Starting from 5.7
714                // Linux allows requires this capability only if the socket
715                // is already bound to a device.
716                security::check_task_capable(current_task, CAP_NET_RAW).inspect_err(|_| {
717                    log_warn!(
718                        "setsockopt(SO_BINDTODEVICE) is called by a \
719                         process without CAP_NET_RAW: {:?}",
720                        current_task.thread_group(),
721                    )
722                })?;
723            }
724            _ => {}
725        }
726
727        let optval = optval.to_vec(current_task)?;
728        self.zxio
729            .setsockopt(level as i32, optname as i32, &optval)
730            .map_err(|status| from_status_like_fdio!(status))?
731            .map_err(|out_code| errno_from_zxio_code!(out_code))
732    }
733
734    fn getsockopt(
735        &self,
736        _locked: &mut Locked<FileOpsCore>,
737        _socket: &Socket,
738        _current_task: &CurrentTask,
739        level: u32,
740        optname: u32,
741        optlen: u32,
742    ) -> Result<Vec<u8>, Errno> {
743        match (level, optname) {
744            // SO_MARK is specialized because linux socket marks are not compatible
745            // with fuchsia socket marks. We need to get the socket mark from the
746            // `ZXIO_SOCKET_MARK_SO_MARK` domain.
747            (SOL_SOCKET, SO_MARK) => {
748                let mut optval: [u8; size_of::<zxio_socket_mark>()] =
749                    zerocopy::try_transmute!(zxio_socket_mark {
750                        is_present: false,
751                        domain: fidl_fuchsia_net::MARK_DOMAIN_SO_MARK as u8,
752                        value: 0,
753                        ..Default::default()
754                    })
755                    .expect("invalid bit pattern");
756                // Retrieves the `zxio_socket_mark` from the domain.
757                let optlen = self
758                    .zxio
759                    .getsockopt_slice(level, SO_FUCHSIA_MARK, &mut optval)
760                    .map_err(|status| from_status_like_fdio!(status))?
761                    .map_err(|out_code| errno_from_zxio_code!(out_code))?;
762                if optlen as usize != size_of::<zxio_socket_mark>() {
763                    return error!(EINVAL);
764                }
765                let socket_mark: zxio_socket_mark =
766                    zerocopy::try_transmute!(optval).map_err(|_validity_err| errno!(EINVAL))?;
767                // Translate to a linux mark, the default value is 0.
768                let mark = if socket_mark.is_present { socket_mark.value } else { 0 };
769                let mut result = vec![0; 4];
770                byteorder::NativeEndian::write_u32(&mut result, mark);
771                Ok(result)
772            }
773            (SOL_SOCKET, SO_COOKIE) => {
774                self.get_socket_cookie().map(|cookie| cookie.as_bytes().to_owned())
775            }
776            _ => self
777                .zxio
778                .getsockopt(level, optname, optlen)
779                .map_err(|status| from_status_like_fdio!(status))?
780                .map_err(|out_code| errno_from_zxio_code!(out_code)),
781        }
782    }
783
784    fn to_handle(
785        &self,
786        _socket: &Socket,
787        _current_task: &CurrentTask,
788    ) -> Result<Option<zx::NullableHandle>, Errno> {
789        self.zxio
790            .deep_clone()
791            .and_then(Zxio::release)
792            .map(Some)
793            .map_err(|status| from_status_like_fdio!(status))
794    }
795}
796
797pub use tokens_store::SocketTokensStore;
798
799mod tokens_store {
800    use crate::task::Kernel;
801    use derivative::Derivative;
802    use fuchsia_async as fasync;
803    use starnix_rcu::RcuHashMap;
804    use starnix_rcu::rcu_hash_map::Entry;
805    use starnix_uapi::uid_t;
806    use std::sync::{Arc, OnceLock, Weak};
807    use zx::HandleBased as _;
808
809    /// Trait for the `Kernel` functionality used in `SocketTokensStore`. Mocked
810    /// in tests.
811    pub trait SocketTokenStoreHost: Sized + Sync + Send + 'static {
812        fn get_socket_tokens_store(&self) -> &SocketTokensStore<Self>;
813        fn spawn_future(&self, future: impl AsyncFnOnce() -> () + Send + 'static);
814    }
815
816    impl SocketTokenStoreHost for Kernel {
817        fn get_socket_tokens_store(&self) -> &SocketTokensStore<Self> {
818            &self.socket_tokens_store
819        }
820        fn spawn_future(&self, future: impl AsyncFnOnce() -> () + Send + 'static) {
821            self.kthreads.spawn_future(future)
822        }
823    }
824
825    // Collection of tokens associated with a UID.
826    #[derive(Debug)]
827    struct TokenCollection {
828        // Sharing domain token. Allocated lazily on first use.
829        sharing_domain_token: OnceLock<zx::Event>,
830    }
831
832    impl TokenCollection {
833        fn new() -> Arc<Self> {
834            Arc::new(Self { sharing_domain_token: OnceLock::new() })
835        }
836
837        /// Returns the number of handles for the tokens held beside this collection itself.
838        fn get_handles_ref_count(&self) -> u32 {
839            self.sharing_domain_token
840                .get()
841                .map(|token| {
842                    token.count_info().expect("ZX_INFO_HANDLE_COUNT query failed").handle_count - 1
843                })
844                .unwrap_or(0)
845        }
846    }
847
848    impl syncio::ZxioTokenResolver for TokenCollection {
849        fn get_token(&self, token_type: syncio::ZxioTokenType) -> Option<zx::NullableHandle> {
850            match token_type {
851                syncio::ZxioTokenType::SharingDomain => {
852                    let token = self
853                        .sharing_domain_token
854                        .get_or_init(|| zx::Event::create())
855                        .duplicate_handle(zx::Rights::TRANSFER)
856                        .expect("Failed to duplicate handle");
857                    Some(token.into_handle())
858                }
859            }
860        }
861    }
862
863    #[derive(Debug, Clone, Copy)]
864    enum UidEntryState {
865        // The entry is unused and can be removed.
866        Unused,
867
868        // The entry is being referenced by sockets.
869        Used,
870
871        // The entry is not referenced by sockets, but the sharing domains socket
872        // is still referenced by netstack.
873        Linger,
874    }
875
876    // Information stored for each UID in `SocketTokensStore`. Each entry is kept
877    // only as long as there may be sockets associated with this UID.
878    #[derive(Derivative)]
879    #[derivative(Clone(bound = ""))]
880    struct UidEntry<H: SocketTokenStoreHost> {
881        tokens: Arc<TokenCollection>,
882
883        // Weak reference to the resolver associated with this UID.
884        weak_resolver: Weak<SocketTokenResolver<H>>,
885
886        // Whether the cleanup task is running.
887        cleanup_task_running: bool,
888    }
889
890    impl<H: SocketTokenStoreHost> UidEntry<H> {
891        fn new() -> Self {
892            Self {
893                tokens: TokenCollection::new(),
894                weak_resolver: Weak::new(),
895                cleanup_task_running: false,
896            }
897        }
898
899        fn get_state(&self) -> UidEntryState {
900            match (self.tokens.get_handles_ref_count(), self.weak_resolver.strong_count()) {
901                (0, 0) => UidEntryState::Unused,
902                (_, 0) => UidEntryState::Linger,
903                _ => UidEntryState::Used,
904            }
905        }
906    }
907
908    #[derive(Derivative)]
909    #[derivative(Default(bound = ""))]
910    pub struct SocketTokensStore<H: SocketTokenStoreHost = Kernel> {
911        map: RcuHashMap<uid_t, UidEntry<H>>,
912    }
913
914    /// Delay between cleanup attempts.
915    const CLEANUP_RETRY_DELAY: zx::MonotonicDuration = zx::MonotonicDuration::from_minutes(1);
916
917    impl<H: SocketTokenStoreHost> SocketTokensStore<H> {
918        pub(super) fn get_token_resolver(
919            &self,
920            host: &Arc<H>,
921            uid: uid_t,
922        ) -> Arc<dyn syncio::ZxioTokenResolver> {
923            let mut guard = self.map.lock();
924            let mut entry = guard.entry(uid).or_insert_with(|| UidEntry::new());
925
926            match entry.get().weak_resolver.upgrade() {
927                Some(resolver) => resolver,
928                None => {
929                    let resolver = SocketTokenResolver::new(entry.get().tokens, host, uid);
930                    let mut new_entry = entry.get();
931                    new_entry.weak_resolver = Arc::downgrade(&resolver);
932                    entry.insert(new_entry);
933                    resolver
934                }
935            }
936        }
937
938        fn on_resolver_dropped(&self, host: &Arc<H>, uid: uid_t) {
939            {
940                let mut guard = self.map.lock();
941                let Entry::Occupied(mut entry) = guard.entry(uid) else {
942                    // The entry may be missing if another thread has created and removed another
943                    // resolver for this UID.
944                    return;
945                };
946                if entry.get().cleanup_task_running {
947                    return;
948                }
949                match entry.get().get_state() {
950                    UidEntryState::Unused => {
951                        entry.remove();
952                        return;
953                    }
954                    UidEntryState::Used => return,
955                    UidEntryState::Linger => (),
956                }
957
958                let mut new_entry = entry.get();
959                new_entry.cleanup_task_running = true;
960                entry.insert(new_entry);
961            }
962
963            // Start cleanup task.
964            let weak_host = Arc::downgrade(host);
965            host.spawn_future(async move || {
966                loop {
967                    // Wait for a bit and then retry cleanup.
968                    fasync::Timer::new(fasync::MonotonicInstant::after(CLEANUP_RETRY_DELAY)).await;
969
970                    let Some(host) = weak_host.upgrade() else {
971                        return;
972                    };
973                    let mut guard = host.get_socket_tokens_store().map.lock();
974                    let Entry::Occupied(mut entry) = guard.entry(uid) else {
975                        return;
976                    };
977                    match entry.get().get_state() {
978                        UidEntryState::Unused => {
979                            // We can remove the entry now.
980                            entry.remove();
981                            return;
982                        }
983                        UidEntryState::Used => {
984                            // Quit cleanup task. It will be restarted later in
985                            // `on_resolver_dropped()`.
986                            let mut new_entry = entry.get();
987                            new_entry.cleanup_task_running = false;
988                            entry.insert(new_entry);
989                            return;
990                        }
991                        UidEntryState::Linger => (),
992                    }
993                }
994            });
995        }
996    }
997
998    // Resolver for socket tokens. This type essentially acts as a proxy for
999    // `TokenCollection` that also notifies `SocketTokensStore` when it is dropped.
1000    struct SocketTokenResolver<H: SocketTokenStoreHost> {
1001        tokens: Arc<TokenCollection>,
1002
1003        // Used in `Drop` implementation to cleanup the entry in
1004        // `SocketTokensStore`.
1005        host: Weak<H>,
1006        uid: uid_t,
1007    }
1008
1009    impl<H: SocketTokenStoreHost> SocketTokenResolver<H> {
1010        fn new(tokens: Arc<TokenCollection>, host: &Arc<H>, uid: uid_t) -> Arc<Self> {
1011            Arc::new(Self { tokens, host: Arc::downgrade(host), uid })
1012        }
1013    }
1014
1015    impl<H: SocketTokenStoreHost> Drop for SocketTokenResolver<H> {
1016        fn drop(&mut self) {
1017            if let Some(host) = self.host.upgrade() {
1018                host.get_socket_tokens_store().on_resolver_dropped(&host, self.uid);
1019            }
1020        }
1021    }
1022
1023    impl<H: SocketTokenStoreHost> syncio::ZxioTokenResolver for SocketTokenResolver<H> {
1024        fn get_token(&self, token_type: syncio::ZxioTokenType) -> Option<zx::NullableHandle> {
1025            self.tokens.get_token(token_type)
1026        }
1027    }
1028
1029    #[cfg(test)]
1030    mod tests {
1031        use super::*;
1032        use fuchsia_async::TestExecutor;
1033        use std::pin::pin;
1034        use test_case::test_matrix;
1035        use zx::MonotonicDuration;
1036
1037        struct TestSocketTokenStoreHost {
1038            socket_tokens_store: SocketTokensStore<TestSocketTokenStoreHost>,
1039        }
1040        impl TestSocketTokenStoreHost {
1041            fn new() -> Arc<Self> {
1042                Arc::new(Self { socket_tokens_store: SocketTokensStore::default() })
1043            }
1044        }
1045
1046        impl SocketTokenStoreHost for TestSocketTokenStoreHost {
1047            fn get_socket_tokens_store(&self) -> &SocketTokensStore<Self> {
1048                &self.socket_tokens_store
1049            }
1050            fn spawn_future(&self, future: impl AsyncFnOnce() -> () + Send + 'static) {
1051                fasync::Task::spawn(async move { fasync::Task::local(future()).await }).detach();
1052            }
1053        }
1054
1055        fn advance_time(executor: &mut TestExecutor, d: MonotonicDuration) {
1056            let r = executor.run_until_stalled(&mut pin!(TestExecutor::advance_to(
1057                fasync::MonotonicInstant::after(d)
1058            )));
1059            assert!(r.is_ready());
1060        }
1061
1062        const UID: uid_t = 100;
1063
1064        #[::fuchsia::test]
1065        fn test_socket_tokens_store_base() {
1066            let host = TestSocketTokenStoreHost::new();
1067            let store = &host.socket_tokens_store;
1068            let token_resolver = store.get_token_resolver(&host, UID);
1069            assert!(store.map.lock().contains_key(&UID));
1070            drop(token_resolver);
1071            assert!(!store.map.lock().contains_key(&UID));
1072        }
1073
1074        #[::fuchsia::test]
1075        fn test_socket_tokens_store_drop_handle_first() {
1076            let host = TestSocketTokenStoreHost::new();
1077            let store = &host.socket_tokens_store;
1078            let token_resolver = store.get_token_resolver(&host, UID);
1079            assert!(store.map.lock().contains_key(&UID));
1080
1081            let token = token_resolver
1082                .get_token(syncio::ZxioTokenType::SharingDomain)
1083                .expect("Failed to get token");
1084            drop(token);
1085            drop(token_resolver);
1086
1087            assert!(!store.map.lock().contains_key(&UID));
1088        }
1089
1090        #[::fuchsia::test]
1091        fn test_socket_tokens_store_linger() {
1092            let mut executor = TestExecutor::new_with_fake_time();
1093            let host = TestSocketTokenStoreHost::new();
1094            let store = &host.socket_tokens_store;
1095            let token_resolver = store.get_token_resolver(&host, UID);
1096            let token = token_resolver
1097                .get_token(syncio::ZxioTokenType::SharingDomain)
1098                .expect("Failed to get token");
1099            assert!(store.map.lock().contains_key(&UID));
1100            drop(token_resolver);
1101
1102            // The entry should not be dropped since we still hold the token
1103            assert!(store.map.lock().contains_key(&UID));
1104            advance_time(&mut executor, CLEANUP_RETRY_DELAY * 2);
1105            assert!(store.map.lock().contains_key(&UID));
1106
1107            // The entry should be dropped shortly after the token is dropped.
1108            drop(token);
1109            advance_time(&mut executor, CLEANUP_RETRY_DELAY);
1110            assert!(!store.map.lock().contains_key(&UID));
1111        }
1112
1113        #[test_matrix(
1114            [CLEANUP_RETRY_DELAY / 2,
1115            CLEANUP_RETRY_DELAY,
1116            CLEANUP_RETRY_DELAY * 3 / 2],
1117            [CLEANUP_RETRY_DELAY / 2,
1118            CLEANUP_RETRY_DELAY,
1119            CLEANUP_RETRY_DELAY * 3 / 2],
1120            [true, false]
1121        )]
1122        #[::fuchsia::test]
1123        fn test_socket_tokens_store_recreate(
1124            delay1: MonotonicDuration,
1125            delay2: MonotonicDuration,
1126            drop_tokens_first: bool,
1127        ) {
1128            let mut executor = TestExecutor::new_with_fake_time();
1129            let host = TestSocketTokenStoreHost::new();
1130            let store = &host.socket_tokens_store;
1131            let token_resolver = store.get_token_resolver(&host, UID);
1132            let token1 = token_resolver
1133                .get_token(syncio::ZxioTokenType::SharingDomain)
1134                .expect("Failed to get token");
1135            drop(token_resolver);
1136
1137            // The entry should not be dropped since we still hold the token
1138            advance_time(&mut executor, delay1);
1139            assert!(store.map.lock().contains_key(&UID));
1140
1141            // Create another resolver. It should reuse the same token.
1142            let token_resolver = store.get_token_resolver(&host, UID);
1143            let token2 = token_resolver
1144                .get_token(syncio::ZxioTokenType::SharingDomain)
1145                .expect("Failed to get token");
1146            assert!(token1.koid() == token2.koid());
1147
1148            // Token should not be dropped while we have a TokenResolver.
1149            advance_time(&mut executor, delay2);
1150            assert!(store.map.lock().contains_key(&UID));
1151
1152            if drop_tokens_first {
1153                drop(token1);
1154                drop(token2);
1155                drop(token_resolver);
1156            } else {
1157                drop(token_resolver);
1158                drop(token1);
1159                drop(token2);
1160            }
1161
1162            // The timer is expected to be rescheduled if it ran between `delay1` and
1163            // `delay1 + delay2`.
1164            let timer_rescheduled = (delay1.into_seconds() / CLEANUP_RETRY_DELAY.into_seconds())
1165                != ((delay1 + delay2).into_seconds() / CLEANUP_RETRY_DELAY.into_seconds());
1166
1167            if timer_rescheduled && drop_tokens_first {
1168                // The entry should be dropped since we dropped the tokens first.
1169                assert!(!store.map.lock().contains_key(&UID));
1170            } else {
1171                let expected_cleanup_delay = if timer_rescheduled {
1172                    CLEANUP_RETRY_DELAY
1173                } else {
1174                    CLEANUP_RETRY_DELAY
1175                        - MonotonicDuration::from_seconds(
1176                            (delay1 + delay2).into_seconds() % CLEANUP_RETRY_DELAY.into_seconds(),
1177                        )
1178                };
1179
1180                // The tokens should be dropped exactly after `expected_cleanup_delay`.
1181                let one_second = MonotonicDuration::from_seconds(1);
1182                advance_time(&mut executor, expected_cleanup_delay - one_second);
1183                assert!(store.map.lock().contains_key(&UID));
1184                advance_time(&mut executor, one_second);
1185                assert!(!store.map.lock().contains_key(&UID));
1186            }
1187        }
1188    }
1189}
1190
1191// Check that values that are passed to and from ZXIO have the same meaning.
1192const_assert_eq!(syncio::zxio::AF_UNSPEC, uapi::AF_UNSPEC as u32);
1193const_assert_eq!(syncio::zxio::AF_UNIX, uapi::AF_UNIX as u32);
1194const_assert_eq!(syncio::zxio::AF_INET, uapi::AF_INET as u32);
1195const_assert_eq!(syncio::zxio::AF_INET6, uapi::AF_INET6 as u32);
1196const_assert_eq!(syncio::zxio::AF_NETLINK, uapi::AF_NETLINK as u32);
1197const_assert_eq!(syncio::zxio::AF_PACKET, uapi::AF_PACKET as u32);
1198const_assert_eq!(syncio::zxio::AF_VSOCK, uapi::AF_VSOCK as u32);
1199
1200const_assert_eq!(syncio::zxio::SO_DEBUG, uapi::SO_DEBUG);
1201const_assert_eq!(syncio::zxio::SO_REUSEADDR, uapi::SO_REUSEADDR);
1202const_assert_eq!(syncio::zxio::SO_TYPE, uapi::SO_TYPE);
1203const_assert_eq!(syncio::zxio::SO_ERROR, uapi::SO_ERROR);
1204const_assert_eq!(syncio::zxio::SO_DONTROUTE, uapi::SO_DONTROUTE);
1205const_assert_eq!(syncio::zxio::SO_BROADCAST, uapi::SO_BROADCAST);
1206const_assert_eq!(syncio::zxio::SO_SNDBUF, uapi::SO_SNDBUF);
1207const_assert_eq!(syncio::zxio::SO_RCVBUF, uapi::SO_RCVBUF);
1208const_assert_eq!(syncio::zxio::SO_KEEPALIVE, uapi::SO_KEEPALIVE);
1209const_assert_eq!(syncio::zxio::SO_OOBINLINE, uapi::SO_OOBINLINE);
1210const_assert_eq!(syncio::zxio::SO_NO_CHECK, uapi::SO_NO_CHECK);
1211const_assert_eq!(syncio::zxio::SO_PRIORITY, uapi::SO_PRIORITY);
1212const_assert_eq!(syncio::zxio::SO_LINGER, uapi::SO_LINGER);
1213const_assert_eq!(syncio::zxio::SO_BSDCOMPAT, uapi::SO_BSDCOMPAT);
1214const_assert_eq!(syncio::zxio::SO_REUSEPORT, uapi::SO_REUSEPORT);
1215const_assert_eq!(syncio::zxio::SO_PASSCRED, uapi::SO_PASSCRED);
1216const_assert_eq!(syncio::zxio::SO_PEERCRED, uapi::SO_PEERCRED);
1217const_assert_eq!(syncio::zxio::SO_RCVLOWAT, uapi::SO_RCVLOWAT);
1218const_assert_eq!(syncio::zxio::SO_SNDLOWAT, uapi::SO_SNDLOWAT);
1219const_assert_eq!(syncio::zxio::SO_ACCEPTCONN, uapi::SO_ACCEPTCONN);
1220const_assert_eq!(syncio::zxio::SO_PEERSEC, uapi::SO_PEERSEC);
1221const_assert_eq!(syncio::zxio::SO_SNDBUFFORCE, uapi::SO_SNDBUFFORCE);
1222const_assert_eq!(syncio::zxio::SO_RCVBUFFORCE, uapi::SO_RCVBUFFORCE);
1223const_assert_eq!(syncio::zxio::SO_PROTOCOL, uapi::SO_PROTOCOL);
1224const_assert_eq!(syncio::zxio::SO_DOMAIN, uapi::SO_DOMAIN);
1225const_assert_eq!(syncio::zxio::SO_RCVTIMEO, uapi::SO_RCVTIMEO);
1226const_assert_eq!(syncio::zxio::SO_SNDTIMEO, uapi::SO_SNDTIMEO);
1227const_assert_eq!(syncio::zxio::SO_TIMESTAMP, uapi::SO_TIMESTAMP);
1228const_assert_eq!(syncio::zxio::SO_TIMESTAMPNS, uapi::SO_TIMESTAMPNS);
1229const_assert_eq!(syncio::zxio::SO_TIMESTAMPING, uapi::SO_TIMESTAMPING);
1230const_assert_eq!(syncio::zxio::SO_SECURITY_AUTHENTICATION, uapi::SO_SECURITY_AUTHENTICATION);
1231const_assert_eq!(
1232    syncio::zxio::SO_SECURITY_ENCRYPTION_TRANSPORT,
1233    uapi::SO_SECURITY_ENCRYPTION_TRANSPORT
1234);
1235const_assert_eq!(
1236    syncio::zxio::SO_SECURITY_ENCRYPTION_NETWORK,
1237    uapi::SO_SECURITY_ENCRYPTION_NETWORK
1238);
1239const_assert_eq!(syncio::zxio::SO_BINDTODEVICE, uapi::SO_BINDTODEVICE);
1240const_assert_eq!(syncio::zxio::SO_ATTACH_FILTER, uapi::SO_ATTACH_FILTER);
1241const_assert_eq!(syncio::zxio::SO_DETACH_FILTER, uapi::SO_DETACH_FILTER);
1242const_assert_eq!(syncio::zxio::SO_GET_FILTER, uapi::SO_GET_FILTER);
1243const_assert_eq!(syncio::zxio::SO_PEERNAME, uapi::SO_PEERNAME);
1244const_assert_eq!(syncio::zxio::SO_PASSSEC, uapi::SO_PASSSEC);
1245const_assert_eq!(syncio::zxio::SO_MARK, uapi::SO_MARK);
1246const_assert_eq!(syncio::zxio::SO_RXQ_OVFL, uapi::SO_RXQ_OVFL);
1247const_assert_eq!(syncio::zxio::SO_WIFI_STATUS, uapi::SO_WIFI_STATUS);
1248const_assert_eq!(syncio::zxio::SO_PEEK_OFF, uapi::SO_PEEK_OFF);
1249const_assert_eq!(syncio::zxio::SO_NOFCS, uapi::SO_NOFCS);
1250const_assert_eq!(syncio::zxio::SO_LOCK_FILTER, uapi::SO_LOCK_FILTER);
1251const_assert_eq!(syncio::zxio::SO_SELECT_ERR_QUEUE, uapi::SO_SELECT_ERR_QUEUE);
1252const_assert_eq!(syncio::zxio::SO_BUSY_POLL, uapi::SO_BUSY_POLL);
1253const_assert_eq!(syncio::zxio::SO_MAX_PACING_RATE, uapi::SO_MAX_PACING_RATE);
1254const_assert_eq!(syncio::zxio::SO_BPF_EXTENSIONS, uapi::SO_BPF_EXTENSIONS);
1255const_assert_eq!(syncio::zxio::SO_INCOMING_CPU, uapi::SO_INCOMING_CPU);
1256const_assert_eq!(syncio::zxio::SO_ATTACH_BPF, uapi::SO_ATTACH_BPF);
1257const_assert_eq!(syncio::zxio::SO_DETACH_BPF, uapi::SO_DETACH_BPF);
1258const_assert_eq!(syncio::zxio::SO_ATTACH_REUSEPORT_CBPF, uapi::SO_ATTACH_REUSEPORT_CBPF);
1259const_assert_eq!(syncio::zxio::SO_ATTACH_REUSEPORT_EBPF, uapi::SO_ATTACH_REUSEPORT_EBPF);
1260const_assert_eq!(syncio::zxio::SO_CNX_ADVICE, uapi::SO_CNX_ADVICE);
1261const_assert_eq!(syncio::zxio::SO_MEMINFO, uapi::SO_MEMINFO);
1262const_assert_eq!(syncio::zxio::SO_INCOMING_NAPI_ID, uapi::SO_INCOMING_NAPI_ID);
1263const_assert_eq!(syncio::zxio::SO_COOKIE, uapi::SO_COOKIE);
1264const_assert_eq!(syncio::zxio::SO_PEERGROUPS, uapi::SO_PEERGROUPS);
1265const_assert_eq!(syncio::zxio::SO_ZEROCOPY, uapi::SO_ZEROCOPY);
1266const_assert_eq!(syncio::zxio::SO_TXTIME, uapi::SO_TXTIME);
1267const_assert_eq!(syncio::zxio::SO_BINDTOIFINDEX, uapi::SO_BINDTOIFINDEX);
1268const_assert_eq!(syncio::zxio::SO_DETACH_REUSEPORT_BPF, uapi::SO_DETACH_REUSEPORT_BPF);
1269const_assert_eq!(syncio::zxio::SO_ORIGINAL_DST, uapi::SO_ORIGINAL_DST);
1270
1271const_assert_eq!(syncio::zxio::MSG_WAITALL, uapi::MSG_WAITALL);
1272const_assert_eq!(syncio::zxio::MSG_PEEK, uapi::MSG_PEEK);
1273const_assert_eq!(syncio::zxio::MSG_DONTROUTE, uapi::MSG_DONTROUTE);
1274const_assert_eq!(syncio::zxio::MSG_CTRUNC, uapi::MSG_CTRUNC);
1275const_assert_eq!(syncio::zxio::MSG_PROXY, uapi::MSG_PROXY);
1276const_assert_eq!(syncio::zxio::MSG_TRUNC, uapi::MSG_TRUNC);
1277const_assert_eq!(syncio::zxio::MSG_DONTWAIT, uapi::MSG_DONTWAIT);
1278const_assert_eq!(syncio::zxio::MSG_EOR, uapi::MSG_EOR);
1279const_assert_eq!(syncio::zxio::MSG_WAITALL, uapi::MSG_WAITALL);
1280const_assert_eq!(syncio::zxio::MSG_FIN, uapi::MSG_FIN);
1281const_assert_eq!(syncio::zxio::MSG_SYN, uapi::MSG_SYN);
1282const_assert_eq!(syncio::zxio::MSG_CONFIRM, uapi::MSG_CONFIRM);
1283const_assert_eq!(syncio::zxio::MSG_RST, uapi::MSG_RST);
1284const_assert_eq!(syncio::zxio::MSG_ERRQUEUE, uapi::MSG_ERRQUEUE);
1285const_assert_eq!(syncio::zxio::MSG_NOSIGNAL, uapi::MSG_NOSIGNAL);
1286const_assert_eq!(syncio::zxio::MSG_MORE, uapi::MSG_MORE);
1287const_assert_eq!(syncio::zxio::MSG_WAITFORONE, uapi::MSG_WAITFORONE);
1288const_assert_eq!(syncio::zxio::MSG_BATCH, uapi::MSG_BATCH);
1289const_assert_eq!(syncio::zxio::MSG_FASTOPEN, uapi::MSG_FASTOPEN);
1290const_assert_eq!(syncio::zxio::MSG_CMSG_CLOEXEC, uapi::MSG_CMSG_CLOEXEC);
1291
1292const_assert_eq!(syncio::zxio::IP_TOS, uapi::IP_TOS);
1293const_assert_eq!(syncio::zxio::IP_TTL, uapi::IP_TTL);
1294const_assert_eq!(syncio::zxio::IP_HDRINCL, uapi::IP_HDRINCL);
1295const_assert_eq!(syncio::zxio::IP_OPTIONS, uapi::IP_OPTIONS);
1296const_assert_eq!(syncio::zxio::IP_ROUTER_ALERT, uapi::IP_ROUTER_ALERT);
1297const_assert_eq!(syncio::zxio::IP_RECVOPTS, uapi::IP_RECVOPTS);
1298const_assert_eq!(syncio::zxio::IP_RETOPTS, uapi::IP_RETOPTS);
1299const_assert_eq!(syncio::zxio::IP_PKTINFO, uapi::IP_PKTINFO);
1300const_assert_eq!(syncio::zxio::IP_PKTOPTIONS, uapi::IP_PKTOPTIONS);
1301const_assert_eq!(syncio::zxio::IP_MTU_DISCOVER, uapi::IP_MTU_DISCOVER);
1302const_assert_eq!(syncio::zxio::IP_RECVERR, uapi::IP_RECVERR);
1303const_assert_eq!(syncio::zxio::IP_RECVTTL, uapi::IP_RECVTTL);
1304const_assert_eq!(syncio::zxio::IP_RECVTOS, uapi::IP_RECVTOS);
1305const_assert_eq!(syncio::zxio::IP_MTU, uapi::IP_MTU);
1306const_assert_eq!(syncio::zxio::IP_FREEBIND, uapi::IP_FREEBIND);
1307const_assert_eq!(syncio::zxio::IP_IPSEC_POLICY, uapi::IP_IPSEC_POLICY);
1308const_assert_eq!(syncio::zxio::IP_XFRM_POLICY, uapi::IP_XFRM_POLICY);
1309const_assert_eq!(syncio::zxio::IP_PASSSEC, uapi::IP_PASSSEC);
1310const_assert_eq!(syncio::zxio::IP_TRANSPARENT, uapi::IP_TRANSPARENT);
1311const_assert_eq!(syncio::zxio::IP_ORIGDSTADDR, uapi::IP_ORIGDSTADDR);
1312const_assert_eq!(syncio::zxio::IP_RECVORIGDSTADDR, uapi::IP_RECVORIGDSTADDR);
1313const_assert_eq!(syncio::zxio::IP_MINTTL, uapi::IP_MINTTL);
1314const_assert_eq!(syncio::zxio::IP_NODEFRAG, uapi::IP_NODEFRAG);
1315const_assert_eq!(syncio::zxio::IP_CHECKSUM, uapi::IP_CHECKSUM);
1316const_assert_eq!(syncio::zxio::IP_BIND_ADDRESS_NO_PORT, uapi::IP_BIND_ADDRESS_NO_PORT);
1317const_assert_eq!(syncio::zxio::IP_MULTICAST_IF, uapi::IP_MULTICAST_IF);
1318const_assert_eq!(syncio::zxio::IP_MULTICAST_TTL, uapi::IP_MULTICAST_TTL);
1319const_assert_eq!(syncio::zxio::IP_MULTICAST_LOOP, uapi::IP_MULTICAST_LOOP);
1320const_assert_eq!(syncio::zxio::IP_ADD_MEMBERSHIP, uapi::IP_ADD_MEMBERSHIP);
1321const_assert_eq!(syncio::zxio::IP_DROP_MEMBERSHIP, uapi::IP_DROP_MEMBERSHIP);
1322const_assert_eq!(syncio::zxio::IP_UNBLOCK_SOURCE, uapi::IP_UNBLOCK_SOURCE);
1323const_assert_eq!(syncio::zxio::IP_BLOCK_SOURCE, uapi::IP_BLOCK_SOURCE);
1324const_assert_eq!(syncio::zxio::IP_ADD_SOURCE_MEMBERSHIP, uapi::IP_ADD_SOURCE_MEMBERSHIP);
1325const_assert_eq!(syncio::zxio::IP_DROP_SOURCE_MEMBERSHIP, uapi::IP_DROP_SOURCE_MEMBERSHIP);
1326const_assert_eq!(syncio::zxio::IP_MSFILTER, uapi::IP_MSFILTER);
1327const_assert_eq!(syncio::zxio::IP_MULTICAST_ALL, uapi::IP_MULTICAST_ALL);
1328const_assert_eq!(syncio::zxio::IP_UNICAST_IF, uapi::IP_UNICAST_IF);
1329const_assert_eq!(syncio::zxio::IP_RECVRETOPTS, uapi::IP_RECVRETOPTS);
1330const_assert_eq!(syncio::zxio::IP_PMTUDISC_DONT, uapi::IP_PMTUDISC_DONT);
1331const_assert_eq!(syncio::zxio::IP_PMTUDISC_WANT, uapi::IP_PMTUDISC_WANT);
1332const_assert_eq!(syncio::zxio::IP_PMTUDISC_DO, uapi::IP_PMTUDISC_DO);
1333const_assert_eq!(syncio::zxio::IP_PMTUDISC_PROBE, uapi::IP_PMTUDISC_PROBE);
1334const_assert_eq!(syncio::zxio::IP_PMTUDISC_INTERFACE, uapi::IP_PMTUDISC_INTERFACE);
1335const_assert_eq!(syncio::zxio::IP_PMTUDISC_OMIT, uapi::IP_PMTUDISC_OMIT);
1336const_assert_eq!(syncio::zxio::IP_DEFAULT_MULTICAST_TTL, uapi::IP_DEFAULT_MULTICAST_TTL);
1337const_assert_eq!(syncio::zxio::IP_DEFAULT_MULTICAST_LOOP, uapi::IP_DEFAULT_MULTICAST_LOOP);
1338
1339const_assert_eq!(syncio::zxio::IPV6_ADDRFORM, uapi::IPV6_ADDRFORM);
1340const_assert_eq!(syncio::zxio::IPV6_2292PKTINFO, uapi::IPV6_2292PKTINFO);
1341const_assert_eq!(syncio::zxio::IPV6_2292HOPOPTS, uapi::IPV6_2292HOPOPTS);
1342const_assert_eq!(syncio::zxio::IPV6_2292DSTOPTS, uapi::IPV6_2292DSTOPTS);
1343const_assert_eq!(syncio::zxio::IPV6_2292RTHDR, uapi::IPV6_2292RTHDR);
1344const_assert_eq!(syncio::zxio::IPV6_2292PKTOPTIONS, uapi::IPV6_2292PKTOPTIONS);
1345const_assert_eq!(syncio::zxio::IPV6_CHECKSUM, uapi::IPV6_CHECKSUM);
1346const_assert_eq!(syncio::zxio::IPV6_2292HOPLIMIT, uapi::IPV6_2292HOPLIMIT);
1347const_assert_eq!(syncio::zxio::IPV6_NEXTHOP, uapi::IPV6_NEXTHOP);
1348const_assert_eq!(syncio::zxio::IPV6_AUTHHDR, uapi::IPV6_AUTHHDR);
1349const_assert_eq!(syncio::zxio::IPV6_UNICAST_HOPS, uapi::IPV6_UNICAST_HOPS);
1350const_assert_eq!(syncio::zxio::IPV6_MULTICAST_IF, uapi::IPV6_MULTICAST_IF);
1351const_assert_eq!(syncio::zxio::IPV6_MULTICAST_HOPS, uapi::IPV6_MULTICAST_HOPS);
1352const_assert_eq!(syncio::zxio::IPV6_MULTICAST_LOOP, uapi::IPV6_MULTICAST_LOOP);
1353const_assert_eq!(syncio::zxio::IPV6_ROUTER_ALERT, uapi::IPV6_ROUTER_ALERT);
1354const_assert_eq!(syncio::zxio::IPV6_MTU_DISCOVER, uapi::IPV6_MTU_DISCOVER);
1355const_assert_eq!(syncio::zxio::IPV6_MTU, uapi::IPV6_MTU);
1356const_assert_eq!(syncio::zxio::IPV6_RECVERR, uapi::IPV6_RECVERR);
1357const_assert_eq!(syncio::zxio::IPV6_V6ONLY, uapi::IPV6_V6ONLY);
1358const_assert_eq!(syncio::zxio::IPV6_JOIN_ANYCAST, uapi::IPV6_JOIN_ANYCAST);
1359const_assert_eq!(syncio::zxio::IPV6_LEAVE_ANYCAST, uapi::IPV6_LEAVE_ANYCAST);
1360const_assert_eq!(syncio::zxio::IPV6_IPSEC_POLICY, uapi::IPV6_IPSEC_POLICY);
1361const_assert_eq!(syncio::zxio::IPV6_XFRM_POLICY, uapi::IPV6_XFRM_POLICY);
1362const_assert_eq!(syncio::zxio::IPV6_HDRINCL, uapi::IPV6_HDRINCL);
1363const_assert_eq!(syncio::zxio::IPV6_RECVPKTINFO, uapi::IPV6_RECVPKTINFO);
1364const_assert_eq!(syncio::zxio::IPV6_PKTINFO, uapi::IPV6_PKTINFO);
1365const_assert_eq!(syncio::zxio::IPV6_RECVHOPLIMIT, uapi::IPV6_RECVHOPLIMIT);
1366const_assert_eq!(syncio::zxio::IPV6_HOPLIMIT, uapi::IPV6_HOPLIMIT);
1367const_assert_eq!(syncio::zxio::IPV6_RECVHOPOPTS, uapi::IPV6_RECVHOPOPTS);
1368const_assert_eq!(syncio::zxio::IPV6_HOPOPTS, uapi::IPV6_HOPOPTS);
1369const_assert_eq!(syncio::zxio::IPV6_RTHDRDSTOPTS, uapi::IPV6_RTHDRDSTOPTS);
1370const_assert_eq!(syncio::zxio::IPV6_RECVRTHDR, uapi::IPV6_RECVRTHDR);
1371const_assert_eq!(syncio::zxio::IPV6_RTHDR, uapi::IPV6_RTHDR);
1372const_assert_eq!(syncio::zxio::IPV6_RECVDSTOPTS, uapi::IPV6_RECVDSTOPTS);
1373const_assert_eq!(syncio::zxio::IPV6_DSTOPTS, uapi::IPV6_DSTOPTS);
1374const_assert_eq!(syncio::zxio::IPV6_RECVPATHMTU, uapi::IPV6_RECVPATHMTU);
1375const_assert_eq!(syncio::zxio::IPV6_PATHMTU, uapi::IPV6_PATHMTU);
1376const_assert_eq!(syncio::zxio::IPV6_DONTFRAG, uapi::IPV6_DONTFRAG);
1377const_assert_eq!(syncio::zxio::IPV6_RECVTCLASS, uapi::IPV6_RECVTCLASS);
1378const_assert_eq!(syncio::zxio::IPV6_TCLASS, uapi::IPV6_TCLASS);
1379const_assert_eq!(syncio::zxio::IPV6_AUTOFLOWLABEL, uapi::IPV6_AUTOFLOWLABEL);
1380const_assert_eq!(syncio::zxio::IPV6_ADDR_PREFERENCES, uapi::IPV6_ADDR_PREFERENCES);
1381const_assert_eq!(syncio::zxio::IPV6_MINHOPCOUNT, uapi::IPV6_MINHOPCOUNT);
1382const_assert_eq!(syncio::zxio::IPV6_ORIGDSTADDR, uapi::IPV6_ORIGDSTADDR);
1383const_assert_eq!(syncio::zxio::IPV6_RECVORIGDSTADDR, uapi::IPV6_RECVORIGDSTADDR);
1384const_assert_eq!(syncio::zxio::IPV6_TRANSPARENT, uapi::IPV6_TRANSPARENT);
1385const_assert_eq!(syncio::zxio::IPV6_UNICAST_IF, uapi::IPV6_UNICAST_IF);
1386const_assert_eq!(syncio::zxio::IPV6_ADD_MEMBERSHIP, uapi::IPV6_ADD_MEMBERSHIP);
1387const_assert_eq!(syncio::zxio::IPV6_DROP_MEMBERSHIP, uapi::IPV6_DROP_MEMBERSHIP);
1388const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_DONT, uapi::IPV6_PMTUDISC_DONT);
1389const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_WANT, uapi::IPV6_PMTUDISC_WANT);
1390const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_DO, uapi::IPV6_PMTUDISC_DO);
1391const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_PROBE, uapi::IPV6_PMTUDISC_PROBE);
1392const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_INTERFACE, uapi::IPV6_PMTUDISC_INTERFACE);
1393const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_OMIT, uapi::IPV6_PMTUDISC_OMIT);
1394const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_TMP, uapi::IPV6_PREFER_SRC_TMP);
1395const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_PUBLIC, uapi::IPV6_PREFER_SRC_PUBLIC);
1396const_assert_eq!(
1397    syncio::zxio::IPV6_PREFER_SRC_PUBTMP_DEFAULT,
1398    uapi::IPV6_PREFER_SRC_PUBTMP_DEFAULT
1399);
1400const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_COA, uapi::IPV6_PREFER_SRC_COA);
1401const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_HOME, uapi::IPV6_PREFER_SRC_HOME);
1402const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_CGA, uapi::IPV6_PREFER_SRC_CGA);
1403const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_NONCGA, uapi::IPV6_PREFER_SRC_NONCGA);