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