Skip to main content

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