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