Skip to main content

starnix_core/vfs/socket/
syscalls.rs

1// Copyright 2021 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::SetSockOptProgramResult;
6use crate::mm::{IOVecPtr, MemoryAccessor, MemoryAccessorExt};
7use crate::security;
8use crate::syscalls::time::TimeSpecPtr;
9use crate::task::{CurrentTask, IpTables, Task, WaitCallback, Waiter};
10use crate::vfs::buffers::{
11    AncillaryData, ControlMsg, UserBuffersInputBuffer, UserBuffersOutputBuffer,
12};
13use crate::vfs::socket::{
14    SA_FAMILY_SIZE, SA_STORAGE_SIZE, Socket, SocketAddress, SocketDomain, SocketFile,
15    SocketMessageFlags, SocketPeer, SocketProtocol, SocketShutdownFlags, SocketType, UnixSocket,
16    resolve_unix_socket_address,
17};
18use crate::vfs::{FdFlags, FdNumber, FileHandle, FsString, LookupContext};
19use starnix_logging::{log_trace, track_stub};
20use starnix_types::augmented::Augmented;
21use starnix_types::time::duration_from_timespec;
22use starnix_types::user_buffer::{UserBuffer, UserBuffers};
23use starnix_uapi::auth::CAP_NET_BIND_SERVICE;
24use starnix_uapi::errors::{EEXIST, EINPROGRESS, Errno};
25use starnix_uapi::file_mode::FileMode;
26use starnix_uapi::math::round_up_to_increment;
27use starnix_uapi::open_flags::OpenFlags;
28use starnix_uapi::user_address::{
29    ArchSpecific, MappingMultiArchUserRef, MultiArchUserRef, UserAddress, UserRef,
30};
31use starnix_uapi::user_value::UserValue;
32use starnix_uapi::vfs::FdEvents;
33use starnix_uapi::{
34    MSG_CTRUNC, MSG_DONTWAIT, MSG_TRUNC, MSG_WAITFORONE, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_CLOEXEC,
35    SOCK_NONBLOCK, UIO_MAXIOV, errno, error, socklen_t, uapi,
36};
37use std::ops::DerefMut;
38
39uapi::check_arch_independent_layout! {
40    socklen_t {}
41}
42
43/// A `msghdr` can be augmented with a `UserBuffer`. In that case, the `UserBuffer` is used for
44/// the I/O, instead of the `iovec` fields from the `msghdr`.
45pub type WithAlternateBuffer<T> = Augmented<T, UserBuffer>;
46pub type MsgHdrPtr = MappingMultiArchUserRef<MsgHdr, uapi::msghdr, uapi::arch32::msghdr>;
47
48#[derive(Debug, Clone)]
49pub struct MsgHdr {
50    pub name: UserAddress,
51    pub name_len: socklen_t,
52    pub iov: IOVecPtr,
53    pub iovlen: UserValue<usize>,
54    pub control: UserAddress,
55    pub control_len: usize,
56    pub flags: u32,
57}
58
59/// A reference to a `msghdr`.
60///
61/// This enum is used to abstract over whether the `msghdr` is in user memory (and needs to be
62/// read) or has been constructed in the kernel. This is used by `io_uring` to provide a buffer
63/// for `recvmsg`.
64#[derive(Debug, Clone)]
65pub enum MsgHdrRef {
66    Ptr(MsgHdrPtr),
67    Value(WithAlternateBuffer<MsgHdr>),
68}
69
70impl From<MsgHdrPtr> for MsgHdrRef {
71    fn from(ptr: MsgHdrPtr) -> Self {
72        Self::Ptr(ptr)
73    }
74}
75
76impl From<WithAlternateBuffer<MsgHdr>> for MsgHdrRef {
77    fn from(value: WithAlternateBuffer<MsgHdr>) -> Self {
78        Self::Value(value)
79    }
80}
81
82pub type MMsgHdrPtr = MappingMultiArchUserRef<MMsgHdr, uapi::mmsghdr, uapi::arch32::mmsghdr>;
83
84pub struct MMsgHdr {
85    hdr: MsgHdr,
86    len: usize,
87}
88
89uapi::arch_map_data! {
90    BidiTryFrom<MsgHdr, msghdr> {
91        name = msg_name;
92        name_len = msg_namelen;
93        iov = msg_iov;
94        iovlen = msg_iovlen;
95        control = msg_control;
96        control_len = msg_controllen;
97        flags = msg_flags;
98    }
99
100    BidiTryFrom<MMsgHdr, mmsghdr> {
101        hdr = msg_hdr;
102        len = msg_len;
103    }
104}
105
106pub type CMsgHdrPtr = MultiArchUserRef<uapi::cmsghdr, uapi::arch32::cmsghdr>;
107
108pub fn sys_socket(
109    current_task: &CurrentTask,
110    domain: u32,
111    socket_type: u32,
112    protocol: u32,
113) -> Result<FdNumber, Errno> {
114    let flags = socket_type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
115    let domain = parse_socket_domain(domain)?;
116    let socket_type = parse_socket_type(domain, socket_type)?;
117    // Should we use parse_socket_protocol here?
118    let protocol = SocketProtocol::from_raw(protocol);
119    let open_flags = socket_flags_to_open_flags(flags);
120    let socket_file = SocketFile::new_socket(
121        current_task,
122        domain,
123        socket_type,
124        open_flags,
125        protocol,
126        /*kernel_private=*/ false,
127    )?;
128
129    let fd_flags = socket_flags_to_fd_flags(flags);
130    let fd = current_task.add_file(socket_file, fd_flags)?;
131    Ok(fd)
132}
133
134fn socket_flags_to_open_flags(flags: u32) -> OpenFlags {
135    OpenFlags::RDWR
136        | if flags & SOCK_NONBLOCK != 0 { OpenFlags::NONBLOCK } else { OpenFlags::empty() }
137}
138
139fn socket_flags_to_fd_flags(flags: u32) -> FdFlags {
140    if flags & SOCK_CLOEXEC != 0 { FdFlags::CLOEXEC } else { FdFlags::empty() }
141}
142
143fn parse_socket_domain(domain: u32) -> Result<SocketDomain, Errno> {
144    SocketDomain::from_raw(domain.try_into().map_err(|_| errno!(EAFNOSUPPORT))?).ok_or_else(|| {
145        track_stub!(TODO("https://fxbug.dev/322875074"), "parse socket domain", domain);
146        errno!(EAFNOSUPPORT)
147    })
148}
149
150fn parse_socket_type(domain: SocketDomain, socket_type: u32) -> Result<SocketType, Errno> {
151    let socket_type = SocketType::from_raw(socket_type & 0xf).ok_or_else(|| {
152        track_stub!(TODO("https://fxbug.dev/322875418"), "parse socket type", socket_type);
153        errno!(EINVAL)
154    })?;
155    // For AF_UNIX, SOCK_RAW sockets are treated as if they were SOCK_DGRAM.
156    Ok(if domain == SocketDomain::Unix && socket_type == SocketType::Raw {
157        SocketType::Datagram
158    } else {
159        socket_type
160    })
161}
162
163fn parse_socket_protocol(
164    domain: SocketDomain,
165    socket_type: SocketType,
166    protocol: u32,
167) -> Result<SocketProtocol, Errno> {
168    let protocol = SocketProtocol::from_raw(protocol);
169    if domain == SocketDomain::Inet {
170        match (socket_type, protocol) {
171            (SocketType::Raw, _) => {
172                // Should we have different behavior error when called by root?
173                return error!(EPROTONOSUPPORT);
174            }
175            (SocketType::Datagram, SocketProtocol::UDP) => (),
176            (SocketType::Datagram, _) => return error!(EPROTONOSUPPORT),
177            (SocketType::Stream, SocketProtocol::TCP) => (),
178            (SocketType::Stream, _) => return error!(EPROTONOSUPPORT),
179            _ => (),
180        }
181    }
182    Ok(protocol)
183}
184
185fn parse_socket_address(
186    task: &Task,
187    user_socket_address: UserAddress,
188    user_address_length: usize,
189) -> Result<SocketAddress, Errno> {
190    if user_address_length < SA_FAMILY_SIZE || user_address_length > SA_STORAGE_SIZE {
191        return error!(EINVAL);
192    }
193
194    let address = task.read_memory_to_vec(user_socket_address, user_address_length)?;
195
196    SocketAddress::from_bytes(address)
197}
198
199fn maybe_parse_socket_address(
200    task: &Task,
201    user_socket_address: UserAddress,
202    user_address_length: usize,
203) -> Result<Option<SocketAddress>, Errno> {
204    if user_address_length > i32::MAX as usize {
205        return error!(EINVAL);
206    }
207    Ok(if user_socket_address.is_null() {
208        None
209    } else {
210        Some(parse_socket_address(task, user_socket_address, user_address_length)?)
211    })
212}
213
214// See "Autobind feature" section of https://man7.org/linux/man-pages/man7/unix.7.html
215fn generate_autobind_address() -> FsString {
216    let mut bytes = [0u8; 4];
217    starnix_crypto::cprng_draw(&mut bytes);
218    let value = u32::from_ne_bytes(bytes) & 0xFFFFF;
219    format!("\0{value:05x}").into()
220}
221
222// Minimum IPv6 sockaddr length before sin6_scope_id (RFC 2133), matching Linux SIN6_LEN_RFC2133.
223const SIN6_LEN_RFC2133: usize = 24;
224
225pub fn sys_bind(
226    current_task: &CurrentTask,
227    fd: FdNumber,
228    user_socket_address: UserAddress,
229    user_address_length: usize,
230) -> Result<(), Errno> {
231    let file = current_task.get_file(fd)?;
232    let socket = Socket::get_from_file(&file)?;
233    let address = parse_socket_address(current_task, user_socket_address, user_address_length)?;
234    if !address.valid_for_domain(socket.domain) {
235        return match socket.domain {
236            SocketDomain::Unix
237            | SocketDomain::Vsock
238            | SocketDomain::Netlink
239            | SocketDomain::Key
240            | SocketDomain::Packet
241            | SocketDomain::Qipcrtr => error!(EINVAL),
242            SocketDomain::Inet => {
243                if user_address_length < std::mem::size_of::<uapi::sockaddr_in>() {
244                    return error!(EINVAL);
245                }
246                if address == SocketAddress::Unspecified {
247                    if let Ok(local_addr) = socket.getsockname() {
248                        if local_addr.maybe_inet_port().unwrap_or(0) != 0 {
249                            return Ok(());
250                        }
251                    }
252                }
253                error!(EAFNOSUPPORT)
254            }
255            SocketDomain::Inet6 => {
256                if user_address_length < SIN6_LEN_RFC2133 {
257                    error!(EINVAL)
258                } else {
259                    error!(EAFNOSUPPORT)
260                }
261            }
262        };
263    }
264    if let Some(port) = address.maybe_inet_port() {
265        // See <https://man7.org/linux/man-pages/man7/ip.7.html>:
266        //
267        //   The port numbers below 1024 are called privileged ports (or
268        //   sometimes: reserved ports).  Only a privileged process (on Linux:
269        //   a process that has the CAP_NET_BIND_SERVICE capability in the
270        //   user namespace governing its network namespace) may bind(2) to
271        //   these sockets.
272        if port != 0 && port < 1024 {
273            security::check_task_capable(current_task, CAP_NET_BIND_SERVICE)
274                .map_err(|_| errno!(EACCES))?;
275        }
276    }
277    security::check_socket_bind_access(current_task, socket, &address)?;
278    match address {
279        SocketAddress::Unspecified => return error!(EINVAL),
280        SocketAddress::Unix(mut name) => {
281            if name.is_empty() {
282                // If the name is empty, then we're supposed to generate an
283                // autobind address, which is always abstract.
284                name = generate_autobind_address();
285            }
286            // If there is a null byte at the start of the sun_path, then the
287            // address is abstract.
288            if name[0] == b'\0' {
289                current_task.running_state().abstract_socket_namespace.bind(
290                    current_task,
291                    name,
292                    socket,
293                )?;
294            } else {
295                let mode = file.node().info().mode;
296                let mode = current_task.fs().apply_umask(mode).with_type(FileMode::IFSOCK);
297                let (parent, basename) = current_task.lookup_parent_at(
298                    &mut LookupContext::default(),
299                    FdNumber::AT_FDCWD,
300                    name.as_ref(),
301                )?;
302
303                parent
304                    .bind_socket(
305                        current_task,
306                        basename,
307                        socket.clone(),
308                        SocketAddress::Unix(name.clone()),
309                        mode,
310                    )
311                    .map_err(|errno| if errno == EEXIST { errno!(EADDRINUSE) } else { errno })?;
312            }
313        }
314        SocketAddress::Vsock { port, .. } => {
315            current_task.running_state().abstract_vsock_namespace.bind(
316                current_task,
317                port,
318                socket,
319            )?;
320        }
321        SocketAddress::Inet(_)
322        | SocketAddress::Inet6(_)
323        | SocketAddress::Netlink(_)
324        | SocketAddress::Packet(_)
325        | SocketAddress::Qipcrtr(_) => socket.bind(current_task, address)?,
326    }
327
328    Ok(())
329}
330
331pub fn sys_listen(current_task: &CurrentTask, fd: FdNumber, backlog: i32) -> Result<(), Errno> {
332    let file = current_task.get_file(fd)?;
333    let socket = Socket::get_from_file(&file)?;
334    socket.listen(current_task, backlog)?;
335    Ok(())
336}
337
338pub fn sys_accept(
339    current_task: &CurrentTask,
340    fd: FdNumber,
341    user_socket_address: UserAddress,
342    user_address_length: UserRef<socklen_t>,
343) -> Result<FdNumber, Errno> {
344    sys_accept4(current_task, fd, user_socket_address, user_address_length, 0)
345}
346
347pub fn sys_accept4(
348    current_task: &CurrentTask,
349    fd: FdNumber,
350    user_socket_address: UserAddress,
351    user_address_length: UserRef<socklen_t>,
352    flags: u32,
353) -> Result<FdNumber, Errno> {
354    let file = current_task.get_file(fd)?;
355    let listening_socket = Socket::get_from_file(&file)?;
356    let accepted_socket =
357        file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
358            listening_socket.accept(current_task)
359        })?;
360
361    if !user_socket_address.is_null() {
362        let address_bytes = accepted_socket.getpeername()?.to_bytes();
363        write_socket_address(
364            current_task,
365            user_socket_address,
366            user_address_length,
367            &address_bytes,
368        )?;
369    }
370
371    let open_flags = socket_flags_to_open_flags(flags);
372    let accepted_socket_file = SocketFile::from_socket(
373        current_task,
374        accepted_socket,
375        open_flags,
376        /* kernel_private= */ false,
377    )?;
378    let listening_socket = SocketFile::get_from_file(&file)?;
379    let accepted_socket = SocketFile::get_from_file(&accepted_socket_file)?;
380    security::socket_accept(current_task, listening_socket, accepted_socket)?;
381    let fd_flags = if flags & SOCK_CLOEXEC != 0 { FdFlags::CLOEXEC } else { FdFlags::empty() };
382    let accepted_fd = current_task.add_file(accepted_socket_file, fd_flags)?;
383    Ok(accepted_fd)
384}
385
386pub fn sys_connect(
387    current_task: &CurrentTask,
388    fd: FdNumber,
389    user_socket_address: UserAddress,
390    user_address_length: usize,
391) -> Result<(), Errno> {
392    let client = current_task.get_file(fd)?;
393    let client = SocketFile::get_from_file(&client)?;
394    let address = parse_socket_address(current_task, user_socket_address, user_address_length)?;
395    let domain = client.socket().domain;
396    if address != SocketAddress::Unspecified && !address.valid_for_domain(domain) {
397        match domain {
398            SocketDomain::Inet => {
399                if user_address_length < std::mem::size_of::<uapi::sockaddr_in>() {
400                    return error!(EINVAL);
401                }
402                return error!(EAFNOSUPPORT);
403            }
404            SocketDomain::Inet6 => {
405                if !(matches!(address, SocketAddress::Inet(_))
406                    && client.socket().socket_type == SocketType::Datagram)
407                {
408                    if user_address_length < SIN6_LEN_RFC2133 {
409                        return error!(EINVAL);
410                    }
411                    return error!(EAFNOSUPPORT);
412                }
413            }
414            SocketDomain::Unix => return error!(EINVAL),
415            _ => {}
416        }
417    }
418    let peer = match address {
419        SocketAddress::Unspecified => SocketPeer::Address(address),
420        SocketAddress::Unix(ref name) => {
421            log_trace!("connect to unix socket named \"{name}\"");
422            if name.is_empty() {
423                return error!(ECONNREFUSED);
424            }
425            SocketPeer::Handle(resolve_unix_socket_address(current_task, name.as_ref())?)
426        }
427        // TODO(https://fxbug.dev/445433238): Connect not available for AF_VSOCK
428        SocketAddress::Vsock { .. } => return error!(ENOSYS),
429        SocketAddress::Inet(ref addr) | SocketAddress::Inet6(ref addr) => {
430            log_trace!("connect to inet socket named {:?}", addr);
431            SocketPeer::Address(address)
432        }
433        SocketAddress::Netlink(_) => SocketPeer::Address(address),
434        SocketAddress::Packet(ref addr) => {
435            log_trace!("connect to packet socket named {:?}", addr);
436            SocketPeer::Address(address)
437        }
438        SocketAddress::Qipcrtr(ref addr) => {
439            log_trace!("connect to qipcrtr socket named {:?}", addr);
440            SocketPeer::Address(address)
441        }
442    };
443    let result = client.connect(current_task, peer.clone());
444
445    if client.file().is_non_blocking() {
446        return result;
447    }
448
449    match result {
450        // EINPROGRESS may be returned for inet sockets when `connect()` is completed
451        // asynchronously.
452        Err(errno) if errno.code == EINPROGRESS => {
453            let waiter = Waiter::new();
454            client.file().wait_async(
455                current_task,
456                &waiter,
457                FdEvents::POLLOUT,
458                WaitCallback::none(),
459            );
460            if !client.file().query_events(current_task)?.contains(FdEvents::POLLOUT) {
461                waiter.wait(current_task)?;
462            }
463            client.connect(current_task, peer)
464        }
465        // TODO(tbodt): Support blocking when the UNIX domain socket queue fills up. This one's
466        // weird because as far as I can tell, removing a socket from the queue does not actually
467        // trigger FdEvents on anything.
468        result => result,
469    }
470}
471
472fn write_socket_address(
473    current_task: &CurrentTask,
474    user_socket_address: UserAddress,
475    user_address_length: UserRef<socklen_t>,
476    address_bytes: &[u8],
477) -> Result<(), Errno> {
478    let capacity = current_task.read_object(user_address_length)?;
479    if capacity > i32::MAX as socklen_t {
480        return error!(EINVAL);
481    }
482    let length = address_bytes.len() as socklen_t;
483    if length > 0 {
484        let actual = std::cmp::min(length, capacity) as usize;
485        current_task.write_memory(user_socket_address, &address_bytes[..actual])?;
486    }
487    current_task.write_object(user_address_length, &length)?;
488    Ok(())
489}
490
491pub fn sys_getsockname(
492    current_task: &CurrentTask,
493    fd: FdNumber,
494    user_socket_address: UserAddress,
495    user_address_length: UserRef<socklen_t>,
496) -> Result<(), Errno> {
497    let file = current_task.get_file(fd)?;
498    let socket = Socket::get_from_file(&file)?;
499    security::check_socket_getsockname_access(current_task, socket)?;
500    let address_bytes = socket.getsockname()?.to_bytes();
501
502    write_socket_address(current_task, user_socket_address, user_address_length, &address_bytes)?;
503
504    Ok(())
505}
506
507pub fn sys_getpeername(
508    current_task: &CurrentTask,
509    fd: FdNumber,
510    user_socket_address: UserAddress,
511    user_address_length: UserRef<socklen_t>,
512) -> Result<(), Errno> {
513    let file = current_task.get_file(fd)?;
514    let socket = Socket::get_from_file(&file)?;
515    security::check_socket_getpeername_access(current_task, socket)?;
516    let address_bytes = socket.getpeername()?.to_bytes();
517
518    write_socket_address(current_task, user_socket_address, user_address_length, &address_bytes)?;
519
520    Ok(())
521}
522
523pub fn sys_socketpair(
524    current_task: &CurrentTask,
525    domain: u32,
526    socket_type: u32,
527    protocol: u32,
528    user_sockets: UserRef<[FdNumber; 2]>,
529) -> Result<(), Errno> {
530    let flags = socket_type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
531    let domain = parse_socket_domain(domain)?;
532    if !matches!(domain, SocketDomain::Unix | SocketDomain::Inet) {
533        return error!(EAFNOSUPPORT);
534    }
535    let socket_type = parse_socket_type(domain, socket_type)?;
536    let _protocol = parse_socket_protocol(domain, socket_type, protocol)?;
537    if domain != SocketDomain::Unix {
538        return error!(EOPNOTSUPP);
539    }
540    let open_flags = socket_flags_to_open_flags(flags);
541
542    let (left, right) = UnixSocket::new_pair(current_task, domain, socket_type, open_flags)?;
543
544    let fd_flags = socket_flags_to_fd_flags(flags);
545    // TODO: Eventually this will need to allocate two fd numbers (each of which could
546    // potentially fail), and only populate the fd numbers (which can't fail) if both allocations
547    // succeed.
548    let left_fd = current_task.add_file(left, fd_flags)?;
549    let right_fd = current_task.add_file(right, fd_flags)?;
550
551    let fds = [left_fd, right_fd];
552    log_trace!("socketpair -> [{:#x}, {:#x}]", fds[0].raw(), fds[1].raw());
553    current_task.write_object(user_sockets, &fds)?;
554
555    Ok(())
556}
557
558fn read_iovec_from_msghdr(
559    current_task: &CurrentTask,
560    message_header: WithAlternateBuffer<&MsgHdr>,
561) -> Result<UserBuffers, Errno> {
562    if let WithAlternateBuffer::WithAux(_, b) = message_header {
563        return Ok(UserBuffers::from_buf([b]));
564    }
565    let iovec_count = message_header.iovlen;
566
567    // In `CurrentTask::read_iovec()` the same check fails with `EINVAL`. This works for all
568    // syscalls that use `iovec`, except `sendmsg()` and `recvmsg()`, which need to fail with
569    // EMSGSIZE.
570    if iovec_count.raw() > UIO_MAXIOV as usize {
571        return error!(EMSGSIZE);
572    }
573
574    current_task.read_iovec(message_header.iov, iovec_count)
575}
576
577fn recvmsg_internal(
578    current_task: &CurrentTask,
579    file: &FileHandle,
580    user_message_header: &mut MsgHdrRef,
581    flags: u32,
582    deadline: Option<zx::MonotonicInstant>,
583) -> Result<usize, Errno> {
584    let mut message_header = match *user_message_header {
585        MsgHdrRef::Ptr(ptr) => current_task.read_multi_arch_object(ptr)?.into(),
586        MsgHdrRef::Value(ref value) => value.clone(),
587    };
588    let result =
589        recvmsg_internal_with_header(current_task, file, message_header.as_mut(), flags, deadline)?;
590    match *user_message_header {
591        MsgHdrRef::Ptr(ptr) => {
592            current_task.write_multi_arch_object(ptr, message_header.extract())?;
593        }
594        MsgHdrRef::Value(ref mut value) => {
595            *value.deref_mut() = message_header.extract();
596        }
597    }
598    Ok(result)
599}
600
601fn recvmsg_internal_with_header(
602    current_task: &CurrentTask,
603    file: &FileHandle,
604    mut message_header: WithAlternateBuffer<&mut MsgHdr>,
605    flags: u32,
606    deadline: Option<zx::MonotonicInstant>,
607) -> Result<usize, Errno> {
608    let iovec = read_iovec_from_msghdr(current_task, message_header.as_unmut())?;
609
610    let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
611    let socket_ops = file.downcast_file::<SocketFile>().unwrap();
612    let info = socket_ops.recvmsg(
613        current_task,
614        file,
615        &mut UserBuffersOutputBuffer::unified_new(current_task, iovec)?,
616        flags,
617        deadline,
618    )?;
619
620    message_header.flags = 0;
621
622    let cmsg_buffer_size = message_header.control_len;
623
624    let mut cmsg_bytes_written = 0;
625    let header_size = CMsgHdrPtr::size_of_object_for(current_task);
626
627    for ancillary_data in info.ancillary_data {
628        if ancillary_data.total_size(current_task) == 0 {
629            // Skip zero-byte ancillary data on the receiving end. Not doing this trips this
630            // assert:
631            // https://cs.android.com/android/platform/superproject/+/master:system/libbase/cmsg.cpp;l=144;drc=15ec2c7a23cda814351a064a345a8270ed8c83ab
632            continue;
633        }
634
635        // Calculate the offset where the current message will be written, after alignment.
636        let aligned_offset = cmsg_align(current_task, cmsg_bytes_written)?;
637        let space_available = cmsg_buffer_size.saturating_sub(aligned_offset);
638
639        if space_available < header_size {
640            // Can't fit the header, so stop trying to write.
641            message_header.flags |= MSG_CTRUNC;
642            break;
643        }
644
645        let conversion = ancillary_data.into_bytes(current_task, flags, space_available)?;
646
647        if conversion.truncated {
648            message_header.flags |= MSG_CTRUNC;
649        }
650
651        assert!(aligned_offset + conversion.bytes.len() <= cmsg_buffer_size);
652        // Write the message at the aligned offset.
653        current_task.write_memory((message_header.control + aligned_offset)?, &conversion.bytes)?;
654        // Update the total bytes written to the end of this message.
655        cmsg_bytes_written = std::cmp::min(
656            cmsg_align(current_task, aligned_offset + conversion.bytes.len())?,
657            cmsg_buffer_size,
658        );
659    }
660
661    message_header.control_len = cmsg_bytes_written;
662
663    let msg_name = message_header.name;
664    if !msg_name.is_null() {
665        if message_header.name_len > i32::MAX as u32 {
666            return error!(EINVAL);
667        }
668        let bytes = info.address.map(|a| a.to_bytes()).unwrap_or_else(|| vec![]);
669        let num_bytes = std::cmp::min(message_header.name_len as usize, bytes.len());
670        message_header.name_len = bytes.len() as u32;
671        if num_bytes > 0 {
672            current_task.write_memory(msg_name, &bytes[..num_bytes])?;
673        }
674    }
675
676    if socket_ops.socket.socket_type != SocketType::Stream && info.bytes_read != info.message_length
677    {
678        message_header.flags |= MSG_TRUNC;
679    }
680
681    if flags.contains(SocketMessageFlags::TRUNC)
682        && socket_ops.socket.socket_type != SocketType::Stream
683    {
684        Ok(info.message_length)
685    } else {
686        Ok(info.bytes_read)
687    }
688}
689
690pub fn sys_recvmsg(
691    current_task: &CurrentTask,
692    fd: FdNumber,
693    user_message_header: MsgHdrPtr,
694    flags: u32,
695) -> Result<usize, Errno> {
696    recvmsg_impl(current_task, fd, &mut user_message_header.into(), flags)
697}
698
699/// Implementation of `recvmsg`.
700///
701/// This function is used by `sys_recvmsg`, but can also be called from other parts of the kernel
702/// that need to override the `iovec` from the `msghdr`. For example, when using `io_uring` with
703/// ring buffers.
704pub fn recvmsg_impl(
705    current_task: &CurrentTask,
706    fd: FdNumber,
707    user_message_header: &mut MsgHdrRef,
708    flags: u32,
709) -> Result<usize, Errno> {
710    let file = current_task.get_file(fd)?;
711    if !file.node().is_sock() {
712        return error!(ENOTSOCK);
713    }
714    recvmsg_internal(current_task, &file, user_message_header, flags, None)
715}
716
717pub fn sys_recvmmsg(
718    current_task: &CurrentTask,
719    fd: FdNumber,
720    user_mmsgvec: MMsgHdrPtr,
721    vlen: u32,
722    mut flags: u32,
723    user_timeout: TimeSpecPtr,
724) -> Result<usize, Errno> {
725    let file = current_task.get_file(fd)?;
726    if !file.node().is_sock() {
727        return error!(ENOTSOCK);
728    }
729
730    if vlen > UIO_MAXIOV {
731        return error!(EINVAL);
732    }
733
734    let deadline = if user_timeout.is_null() {
735        None
736    } else {
737        let ts = current_task.read_multi_arch_object(user_timeout)?;
738        Some(zx::MonotonicInstant::after(duration_from_timespec(ts)?))
739    };
740
741    let mut index = 0usize;
742    while index < vlen as usize {
743        let current_ptr = user_mmsgvec.at(index)?;
744        let mut current_mmsghdr = current_task.read_multi_arch_object(current_ptr)?;
745        match recvmsg_internal_with_header(
746            current_task,
747            &file,
748            (&mut current_mmsghdr.hdr).into(),
749            flags,
750            deadline,
751        ) {
752            Err(error) => {
753                if index == 0 {
754                    return Err(error);
755                }
756                break;
757            }
758            Ok(bytes_read) => {
759                current_mmsghdr.len = bytes_read;
760                current_task.write_multi_arch_object(current_ptr, current_mmsghdr)?;
761            }
762        }
763        index += 1;
764        if flags & MSG_WAITFORONE != 0 {
765            flags |= MSG_DONTWAIT;
766        }
767    }
768    Ok(index)
769}
770
771pub fn sys_recvfrom(
772    current_task: &CurrentTask,
773    fd: FdNumber,
774    user_buffer: UserAddress,
775    buffer_length: usize,
776    flags: u32,
777    user_src_address: UserAddress,
778    user_src_address_length: UserRef<socklen_t>,
779) -> Result<usize, Errno> {
780    let file = current_task.get_file(fd)?;
781    if !file.node().is_sock() {
782        return error!(ENOTSOCK);
783    }
784
785    let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
786    let socket_ops = file.downcast_file::<SocketFile>().unwrap();
787    let info = socket_ops.recvmsg(
788        current_task,
789        &file,
790        &mut UserBuffersOutputBuffer::unified_new_at(current_task, user_buffer, buffer_length)?,
791        flags,
792        None,
793    )?;
794
795    if !user_src_address.is_null() {
796        let bytes = info.address.map(|a| a.to_bytes()).unwrap_or_else(|| vec![]);
797        write_socket_address(current_task, user_src_address, user_src_address_length, &bytes)?;
798    }
799
800    if flags.contains(SocketMessageFlags::TRUNC)
801        && socket_ops.socket.socket_type != SocketType::Stream
802    {
803        Ok(info.message_length)
804    } else {
805        Ok(info.bytes_read)
806    }
807}
808
809fn sendmsg_internal(
810    current_task: &CurrentTask,
811    file: &FileHandle,
812    user_message_header: MsgHdrPtr,
813    flags: u32,
814) -> Result<usize, Errno> {
815    let message_header = current_task.read_multi_arch_object(user_message_header)?;
816    sendmsg_internal_with_header(current_task, file, &message_header, flags)
817}
818
819fn sendmsg_internal_with_header(
820    current_task: &CurrentTask,
821    file: &FileHandle,
822    message_header: &MsgHdr,
823    flags: u32,
824) -> Result<usize, Errno> {
825    if message_header.name_len > i32::MAX as u32 {
826        return error!(EINVAL);
827    }
828    if message_header.control_len > 20480 {
829        return error!(ENOBUFS);
830    }
831    let dest_address = maybe_parse_socket_address(
832        current_task,
833        message_header.name,
834        message_header.name_len as usize,
835    )?;
836    let iovec = read_iovec_from_msghdr(current_task, message_header.into())?;
837
838    let mut next_message_offset: usize = 0;
839    let mut ancillary_data = Vec::new();
840    let header_size = CMsgHdrPtr::size_of_object_for(current_task);
841    loop {
842        let space = message_header.control_len.saturating_sub(next_message_offset);
843        if space < header_size {
844            break;
845        }
846        let cmsg_ref =
847            CMsgHdrPtr::new(current_task, (message_header.control + next_message_offset)?);
848        let cmsg = current_task.read_multi_arch_object(cmsg_ref)?;
849        // If the message header is not long enough to fit the required fields of the
850        // control data, return EINVAL.
851        if (cmsg.cmsg_len as usize) < header_size {
852            return error!(EINVAL);
853        }
854
855        let data_size = std::cmp::min(cmsg.cmsg_len as usize - header_size, space);
856        let next_data_offset = next_message_offset + header_size;
857        let data = current_task
858            .read_memory_to_vec((message_header.control + next_data_offset)?, data_size)?;
859        next_message_offset += cmsg_align(current_task, header_size + data.len())?;
860        let data = AncillaryData::from_cmsg(
861            current_task,
862            ControlMsg::new(cmsg.cmsg_level, cmsg.cmsg_type, data),
863        )?;
864        if data.total_size(current_task) == 0 {
865            continue;
866        }
867        ancillary_data.push(data);
868    }
869
870    let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EOPNOTSUPP))?;
871    let socket_ops = file.downcast_file::<SocketFile>().unwrap();
872    if dest_address.is_some()
873        && socket_ops.socket.domain == SocketDomain::Inet
874        && socket_ops.socket.socket_type != SocketType::Stream
875        && (message_header.name_len as usize) < std::mem::size_of::<uapi::sockaddr_in>()
876    {
877        return error!(EINVAL);
878    }
879    socket_ops.sendmsg(
880        current_task,
881        file,
882        &mut UserBuffersInputBuffer::unified_new(current_task, iovec)?,
883        dest_address,
884        ancillary_data,
885        flags,
886    )
887}
888
889pub fn sys_sendmsg(
890    current_task: &CurrentTask,
891    fd: FdNumber,
892    user_message_header: MsgHdrPtr,
893    flags: u32,
894) -> Result<usize, Errno> {
895    let file = current_task.get_file(fd)?;
896    if !file.node().is_sock() {
897        return error!(ENOTSOCK);
898    }
899    sendmsg_internal(current_task, &file, user_message_header, flags)
900}
901
902pub fn sys_sendmmsg(
903    current_task: &CurrentTask,
904    fd: FdNumber,
905    user_mmsgvec: MMsgHdrPtr,
906    mut vlen: u32,
907    flags: u32,
908) -> Result<usize, Errno> {
909    let file = current_task.get_file(fd)?;
910    if !file.node().is_sock() {
911        return error!(ENOTSOCK);
912    }
913
914    // vlen is capped at UIO_MAXIOV.
915    if vlen > UIO_MAXIOV {
916        vlen = UIO_MAXIOV;
917    }
918
919    let mut index = 0usize;
920    while index < vlen as usize {
921        let current_ptr = user_mmsgvec.at(index)?;
922        let mut current_mmsghdr = current_task.read_multi_arch_object(current_ptr)?;
923        match sendmsg_internal_with_header(current_task, &file, &current_mmsghdr.hdr, flags) {
924            Err(error) => {
925                if index == 0 {
926                    return Err(error);
927                }
928                break;
929            }
930            Ok(bytes_read) => {
931                current_mmsghdr.len = bytes_read;
932                current_task.write_multi_arch_object(current_ptr, current_mmsghdr)?;
933            }
934        }
935        index += 1;
936    }
937    Ok(index)
938}
939
940pub fn sys_sendto(
941    current_task: &CurrentTask,
942    fd: FdNumber,
943    user_buffer: UserAddress,
944    user_buffer_length: usize,
945    flags: u32,
946    user_dest_address: UserAddress,
947    user_dest_address_length: socklen_t,
948) -> Result<usize, Errno> {
949    let file = current_task.get_file(fd)?;
950    if !file.node().is_sock() {
951        return error!(ENOTSOCK);
952    }
953
954    let dest_address = maybe_parse_socket_address(
955        current_task,
956        user_dest_address,
957        user_dest_address_length as usize,
958    )?;
959    let mut data =
960        UserBuffersInputBuffer::unified_new_at(current_task, user_buffer, user_buffer_length)?;
961
962    let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EOPNOTSUPP))?;
963    let socket_file = file.downcast_file::<SocketFile>().unwrap();
964    if dest_address.is_some()
965        && socket_file.socket.domain == SocketDomain::Inet
966        && socket_file.socket.socket_type != SocketType::Stream
967        && (user_dest_address_length as usize) < std::mem::size_of::<uapi::sockaddr_in>()
968    {
969        return error!(EINVAL);
970    }
971    socket_file.sendmsg(current_task, &file, &mut data, dest_address, vec![], flags)
972}
973
974pub fn sys_getsockopt(
975    current_task: &CurrentTask,
976    fd: FdNumber,
977    level: u32,
978    optname: u32,
979    user_optval: UserAddress,
980    user_optlen: UserRef<socklen_t>,
981) -> Result<(), Errno> {
982    let file = current_task.get_file(fd)?;
983    let socket = Socket::get_from_file(&file)?;
984
985    let optlen = current_task.read_object(user_optlen)? as usize;
986    let optval_buffer_len = optlen;
987    let mut optval = current_task.read_memory_to_vec(user_optval, optlen as usize)?;
988
989    let result = if socket.domain.is_inet() && IpTables::can_handle_getsockopt(level, optname) {
990        current_task.kernel().iptables().getsockopt(current_task, socket, optname, optval.clone())
991    } else {
992        socket.getsockopt(current_task, level, optname, optlen as u32)
993    };
994
995    // Even if `getsockopt()` above returned an error we still need to run
996    // the eBPF program - it may handle the error.
997    let (optlen, error) = match result {
998        Ok(new_optval) => {
999            // Linux getsockopt allows the user to pass a buffer smaller than the option's
1000            // actual size, in which case the kernel truncates the returned value to fit
1001            // the buffer and returns success.
1002            //
1003            // On the other hand, if the option is smaller than the user provided buffer,
1004            // the eBPF program can still use the entire user allocated buffer if needed.
1005            let len = std::cmp::min(new_optval.len(), optval.len());
1006            optval[..len].copy_from_slice(&new_optval[..len]);
1007            (len, None)
1008        }
1009        Err(e) => (optlen, Some(e)),
1010    };
1011
1012    let root_cgroup = current_task.kernel().ebpf_state.attachments.root_cgroup();
1013    let (optval, optlen) = root_cgroup.run_getsockopt_prog(
1014        current_task,
1015        level,
1016        optname,
1017        optval,
1018        optlen,
1019        error,
1020        socket,
1021    )?;
1022
1023    assert!(optlen <= optval_buffer_len);
1024    current_task.write_memory(user_optval, &optval[..optlen])?;
1025    current_task.write_object(user_optlen, &(optlen as u32))?;
1026
1027    Ok(())
1028}
1029
1030pub fn sys_setsockopt(
1031    current_task: &CurrentTask,
1032    fd: FdNumber,
1033    level: u32,
1034    optname: u32,
1035    user_optval: UserAddress,
1036    optlen: socklen_t,
1037) -> Result<(), Errno> {
1038    let file = current_task.get_file(fd)?;
1039    let socket = Socket::get_from_file(&file)?;
1040
1041    let user_opt = UserBuffer { address: user_optval, length: optlen as usize };
1042
1043    // Run eBPF program if any.
1044    let root_cgroup = current_task.kernel().ebpf_state.attachments.root_cgroup();
1045    let optval = match root_cgroup.run_setsockopt_prog(
1046        current_task,
1047        level,
1048        optname,
1049        user_opt.into(),
1050        socket,
1051    ) {
1052        SetSockOptProgramResult::Allow(value) => value,
1053        SetSockOptProgramResult::Fail(errno) => return Err(errno),
1054        SetSockOptProgramResult::Bypass => return Ok(()), // The option was handled by eBPF.
1055    };
1056
1057    if socket.domain.is_inet() && IpTables::can_handle_setsockopt(level, optname) {
1058        current_task.kernel().iptables().setsockopt(current_task, socket, optname, optval)
1059    } else {
1060        socket.setsockopt(current_task, level, optname, optval)
1061    }
1062}
1063
1064pub fn sys_shutdown(current_task: &CurrentTask, fd: FdNumber, how: u32) -> Result<(), Errno> {
1065    let file = current_task.get_file(fd)?;
1066    let socket = Socket::get_from_file(&file)?;
1067    let how = match how {
1068        SHUT_RD => SocketShutdownFlags::READ,
1069        SHUT_WR => SocketShutdownFlags::WRITE,
1070        SHUT_RDWR => SocketShutdownFlags::READ | SocketShutdownFlags::WRITE,
1071        _ => return error!(EINVAL),
1072    };
1073    socket.shutdown(current_task, how)?;
1074    Ok(())
1075}
1076
1077pub fn cmsg_align(current_task: &CurrentTask, value: usize) -> Result<usize, Errno> {
1078    let alignment = if current_task.is_arch32() { 4 } else { 8 };
1079    round_up_to_increment(value, alignment)
1080}
1081
1082// Syscalls for arch32 usage
1083#[cfg(target_arch = "aarch64")]
1084mod arch32 {
1085    use crate::task::CurrentTask;
1086    use crate::vfs::FdNumber;
1087    use starnix_uapi::errors::Errno;
1088    use starnix_uapi::user_address::UserAddress;
1089
1090    pub use super::{
1091        sys_accept as sys_arch32_accept, sys_accept4 as sys_arch32_accept4,
1092        sys_bind as sys_arch32_bind, sys_getpeername as sys_arch32_getpeername,
1093        sys_getsockname as sys_arch32_getsockname, sys_getsockopt as sys_arch32_getsockopt,
1094        sys_listen as sys_arch32_listen, sys_recvfrom as sys_arch32_recvfrom,
1095        sys_recvmmsg as sys_arch32_recvmmsg, sys_recvmsg as sys_arch32_recvmsg,
1096        sys_sendmsg as sys_arch32_sendmsg, sys_sendto as sys_arch32_sendto,
1097        sys_setsockopt as sys_arch32_setsockopt, sys_shutdown as sys_arch32_shutdown,
1098        sys_socketpair as sys_arch32_socketpair,
1099    };
1100
1101    pub fn sys_arch32_send(
1102        current_task: &CurrentTask,
1103        fd: FdNumber,
1104        user_buffer: UserAddress,
1105        user_buffer_length: usize,
1106        flags: u32,
1107    ) -> Result<usize, Errno> {
1108        super::sys_sendto(
1109            current_task,
1110            fd,
1111            user_buffer,
1112            user_buffer_length,
1113            flags,
1114            Default::default(),
1115            Default::default(),
1116        )
1117    }
1118
1119    pub fn sys_arch32_recv(
1120        current_task: &CurrentTask,
1121        fd: FdNumber,
1122        user_buffer: UserAddress,
1123        buffer_length: usize,
1124        flags: u32,
1125    ) -> Result<usize, Errno> {
1126        super::sys_recvfrom(
1127            current_task,
1128            fd,
1129            user_buffer,
1130            buffer_length,
1131            flags,
1132            Default::default(),
1133            Default::default(),
1134        )
1135    }
1136}
1137
1138#[cfg(target_arch = "aarch64")]
1139pub use arch32::*;
1140
1141#[cfg(test)]
1142mod tests {
1143    use super::*;
1144    use crate::testing::spawn_kernel_and_run;
1145    use starnix_uapi::{AF_INET, AF_UNIX, SOCK_STREAM};
1146
1147    #[::fuchsia::test]
1148    async fn test_socketpair_invalid_arguments() {
1149        spawn_kernel_and_run(async |current_task| {
1150            assert_eq!(
1151                sys_socketpair(
1152                    current_task,
1153                    AF_INET as u32,
1154                    SOCK_STREAM,
1155                    0,
1156                    UserRef::new(UserAddress::default())
1157                ),
1158                error!(EPROTONOSUPPORT)
1159            );
1160            assert_eq!(
1161                sys_socketpair(
1162                    current_task,
1163                    AF_UNIX as u32,
1164                    7,
1165                    0,
1166                    UserRef::new(UserAddress::default())
1167                ),
1168                error!(EINVAL)
1169            );
1170            assert_eq!(
1171                sys_socketpair(
1172                    current_task,
1173                    AF_UNIX as u32,
1174                    SOCK_STREAM,
1175                    0,
1176                    UserRef::new(UserAddress::default())
1177                ),
1178                error!(EFAULT)
1179            );
1180        })
1181        .await;
1182    }
1183
1184    #[::fuchsia::test]
1185    fn test_generate_autobind_address() {
1186        let address = generate_autobind_address();
1187        assert_eq!(address.len(), 6);
1188        assert_eq!(address[0], 0);
1189        for byte in address[1..].iter() {
1190            match byte {
1191                b'0'..=b'9' | b'a'..=b'f' => {
1192                    // Ok.
1193                }
1194                bad => {
1195                    panic!("bad byte: {bad}");
1196                }
1197            }
1198        }
1199    }
1200}