Skip to content

Route sendmsg/recvmsg via shared host_iov helper#64

Merged
jserv merged 1 commit into
mainfrom
host-syscall
May 31, 2026
Merged

Route sendmsg/recvmsg via shared host_iov helper#64
jserv merged 1 commit into
mainfrom
host-syscall

Conversation

@jserv
Copy link
Copy Markdown
Contributor

@jserv jserv commented May 31, 2026

sys_sendmsg and sys_recvmsg resolved each guest iov entry with guest_ptr_bound() and clamped the entry's length to the contiguous prefix when the guest VA crossed a host-side discontinuity (primary slab to guest_mapping / guest_overflow region, or between two distinct mappings). The loop then continued populating host_iov[i+1..] at full requested length, so the host sendmsg(2) placed bytes from iov[i+1] on the wire where the truncated tail of iov[i] belonged, and recvmsg(2) scattered received bytes into the wrong guest buffer past a truncated entry. The case only fires when a guest iov entry straddles two distinct host mappings; the typical single-region iov masked it in tests.

Hoist the already-correct build_host_iov helper from src/syscall/io.c into src/syscall/internal.h as host_iov_prepare and the wrapper host_iov_prepare_msg, together with host_iov_buf_t and the SYSCALL_IOV_MAX / SYSCALL_IOV_STACK_MAX constants. host_iov_prepare keeps the strict readv/writev contract (rejects iovcnt <= 0); host_iov_prepare_msg short-circuits iovcnt == 0 for ancillary-only sendmsg/recvmsg payloads. Replace the duplicated inline iov build loops in src/syscall/net-msg.c with the shared call. Side effects: lifts the per-call iovcnt cap from 64 to SYSCALL_IOV_MAX (1024) and drops roughly 80 lines of duplicated logic.

The shared helper truncates at the first non-contiguous iov entry and zeros every subsequent entry, so the host call returns a POSIX-compliant short I/O instead of mis-aligning the wire data.


Summary by cubic

Fixes misaligned I/O in sendmsg/recvmsg when a guest iovec crosses non‑contiguous host mappings by routing both calls through a shared host_iov helper. Lifts the iov cap to 1024 and removes duplicated logic.

  • Bug Fixes

    • Truncate at the first non‑contiguous iov entry and zero the rest so the host returns a POSIX short I/O instead of misplacing data.
    • Cap msg_iovlen at SYSCALL_IOV_MAX before int narrowing; allow iovcnt == 0 for ancillary‑only messages.
  • Refactors

    • Hoisted build_host_iov into host_iov_prepare/host_iov_prepare_msg in src/syscall/internal.h with host_iov_buf_t, host_iov_free, and shared SYSCALL_IOV_MAX/SYSCALL_IOV_STACK_MAX.
    • Replaced inline iov loops in src/syscall/net-msg.c; raised per‑call cap from 64 to 1024; removed ~80 lines.
    • Added a test to keep strict readv/writev/pwritev2 behavior: zero iovcnt stays -EINVAL and does not move the file offset.

Written for commit 7a98c58. Summary will update on new commits.

Review in cubic

@jserv jserv requested a review from Max042004 May 31, 2026 13:00
@jserv jserv changed the title Route sendmsg/recvmsg vi shared host_iov helper Route sendmsg/recvmsg via shared host_iov helper May 31, 2026
sys_sendmsg and sys_recvmsg resolved each guest iov entry with
guest_ptr_bound() and clamped the entry's length to the contiguous
prefix when the guest VA crossed a host-side discontinuity (primary slab
to guest_mapping / guest_overflow region, or between two distinct
mappings). The loop then continued populating host_iov[i+1..] at full
requested length, so the host sendmsg(2) placed bytes from iov[i+1] on
the wire where the truncated tail of iov[i] belonged, and recvmsg(2)
scattered received bytes into the wrong guest buffer past a truncated
entry. The case only fires when a guest iov entry straddles two distinct
host mappings; the typical single-region iov masked it in tests.

Hoist the already-correct build_host_iov helper from src/syscall/io.c
into src/syscall/internal.h as host_iov_prepare and the wrapper
host_iov_prepare_msg, together with host_iov_buf_t and SYSCALL_IOV_{MAX,
STACK_MAX} constants. host_iov_prepare keeps the strict readv/writev
contract (rejects iovcnt <= 0); host_iov_prepare_msg short-circuits
iovcnt == 0 for ancillary-only sendmsg/recvmsg payloads. Replace the
duplicated inline iov build loops in src/syscall/net-msg.c with the
shared call. Side effects: lifts the per-call iovcnt cap from 64 to
SYSCALL_IOV_MAX (1024) and drops roughly 80 lines of duplicated logic.

The shared helper truncates at the first non-contiguous iov entry and
zeros every subsequent entry, so the host call returns a POSIX-compliant
short I/O instead of mis-aligning the wire data.
cubic-dev-ai[bot]

This comment was marked as resolved.

@jserv jserv merged commit 1569ca2 into main May 31, 2026
4 checks passed
@jserv jserv deleted the host-syscall branch May 31, 2026 14:39
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.

3 participants