Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(udp): use libc::recvmmsg on Android x86 #1964

Closed
wants to merge 1 commit into from

Conversation

mxinden
Copy link
Contributor

@mxinden mxinden commented Aug 10, 2024

On x86-32, socketcall() was historically the only entry point for
the sockets API. However, starting in Linux 4.3, direct system
calls are provided on x86-32 for the sockets API.

https://man7.org/linux/man-pages/man2/socketcall.2.html

Androids x86 even goes as far as automatically dispatching advanced socket calls (e.g. socket or recvmmsg) through socketcall in its Bionic libc:

For example, socket() syscall on i386 actually becomes:
socketcall(__NR_socket, 1, *(rest of args on stack)).

https://android.googlesource.com/platform/bionic/+/refs/tags/android-vts-14.0_r5/libc/SYSCALLS.TXT#19

In addition Android enables seccomp filtering since Android 8:

https://android-developers.googleblog.com/2017/07/seccomp-filter-in-android-o.html

Currently quinn-udp calls recvmmsg directly on Android x86:

quinn/quinn-udp/src/unix.rs

Lines 447 to 448 in c0b1e28

let ret =
libc::syscall(libc::SYS_recvmmsg, sockfd, msgvec, vlen, flags, timeout) as libc::c_int;

A direct recvmmsg through libc::syscall(libc::SYS_recvmmsg does not trigger the automatic Android x86 Bionic libc dispatch logic through socketcall, but instead calls the unimplemented recvmmsg syscall. Instead of triggering a libc::ENOSYS, seccomp disallows the call, thus leading to a panic of the application.

This commit changes quinn-udp to use libc::recvmmsg on Android x86, thus leveraging Bionic's automatic dispatch of recvmmsg through socketcall.

Note that this commit only uses libc::recvmmsg on Android x86, not any other Android or Linux variant. Thus quinn-udp would still support missing libc::recvmmsg on those systems. See #1504.


Fixes #1947.

Problem itself and fix reproducible on Firefox CI. See e.g. latest CI run startup-x86.

Still unable to reproduce via #1950. I assume this is due to still using a 64bit toolchain when testing x86.

//CC @link2xt following up on #1504, this might be of interest for you.

> On x86-32, socketcall() was historically the only entry point for
> the sockets API.  However, starting in Linux 4.3, direct system
> calls are provided on x86-32 for the sockets API.

https://man7.org/linux/man-pages/man2/socketcall.2.html

Androids x86 even goes as far as automatically dispatching advanced socket
calls (e.g. `socket` or `recvmmsg`) through `socketcall` in its Bionic libc:

> For example, socket() syscall on i386 actually becomes:
> socketcall(__NR_socket, 1, *(rest of args on stack)).

https://android.googlesource.com/platform/bionic/+/refs/tags/android-vts-14.0_r5/libc/SYSCALLS.TXT#19

In addition Android enables seccomp filtering since Android 8:

https://android-developers.googleblog.com/2017/07/seccomp-filter-in-android-o.html

Currently `quinn-udp` calls `recvmmsg` directly on Android x86:

``` rust
let ret = libc::syscall(libc::SYS_recvmmsg, sockfd, msgvec, vlen, flags, timeout) as libc::c_int;
```

https://github.com/quinn-rs/quinn/blob/c0b1e281e3167d4f4c8496082cb1117c4a270ad8/quinn-udp/src/unix.rs#L447-L448

A direct `recvmmsg` through `libc::syscall(libc::SYS_recvmmsg` does not trigger
the automatic Android x86 Bionic libc dispatch logic through `socketcall`, but
instead calls the unimplemented `recvmmsg` syscall. Instead of triggering a
`libc::ENOSYS`, seccomp disallows the call, thus leading to a panic of the
application.

This commit changes `quinn-udp` to use `libc::recvmmsg` on Android x86, thus
leveraging Bionic's automatic dispatch of `recvmmsg` through `socketcall`.

Note that this commit only uses `libc::recvmmsg` on Android x86, not any other
Android or Linux variant. Thus quinn-udp would still support missing
`libc::recvmmsg` on those systems. See
quinn-rs#1504.
@djc
Copy link
Member

djc commented Aug 10, 2024

Thanks! If you'd like a release with this, please add a commit that bumps the version number

// through `socketcall` and is thus disallowed by seccomp.
#[cfg(all(target_os = "android", target_arch = "x86"))]
{
let ret = libc::recvmmsg(sockfd, msgvec, vlen, flags, timeout) as libc::c_int;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks identical to the *BSD call above. Should we fold them together?

@mxinden
Copy link
Contributor Author

mxinden commented Aug 14, 2024

Alternative implementation in #1966. Let me know which way forward you prefer.

@mxinden
Copy link
Contributor Author

mxinden commented Sep 3, 2024

Closing here since #1966 is merged and released. Thanks for taking a look!

@mxinden mxinden closed this Sep 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

recvmmsg is disallowed by seccomp on Android x86
3 participants