Skip to content

Fix wasip1 accept(NULL) crash and emulated mmap leak on pread failure - #866

Merged
alexcrichton merged 6 commits into
WebAssembly:mainfrom
SebTardif:fix/accept-null-and-mmap-leak
Aug 12, 2026
Merged

Fix wasip1 accept(NULL) crash and emulated mmap leak on pread failure#866
alexcrichton merged 6 commits into
WebAssembly:mainfrom
SebTardif:fix/accept-null-and-mmap-leak

Conversation

@SebTardif

@SebTardif SebTardif commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Two small correctness fixes in wasip1 accept/accept4 and emulated mmap.

Problem

  1. wasip1 accept: After a successful __wasi_sock_accept, both accept and accept4 always wrote through addr / *addrlen. POSIX allows both to be NULL when the peer address is unused, so accept(fd, NULL, NULL) null-dereferences. wasip2/p3 already allow both-null via __wasilibc_sockaddr_validate.

  2. Emulated mmap: File-backed mmap allocates a header+body block, then fills it with pread. On pread error it returned MAP_FAILED without freeing that allocation.

Change

  • accept-wasip1.c: only fill the sockaddr when both addr and addrlen are non-NULL.
  • mman/mman.c: on pread failure, free the allocation and restore errno.

Validation

  • Suite tests (this PR):
    • test/src/sockets-accept-null-addr.caccept/accept4 with NULL peer address (plus a non-null control path). Registered for wasip2/p3 NETWORK and for wasip1 (non-V8) so accept-wasip1.c is exercised.
    • test/src/mmap-pread-fail.c — emulated mmap: O_WRONLY pread failure returns MAP_FAILED, survives 256×1MiB fail iterations without OOMing, then MAP_ANON still works. Linked with -lwasi-emulated-mman.
  • Host red-green for both control-flow classes (null-write crash vs both-null guard; free-on-fail vs leak growth).
  • clang-format on touched C sources.

Origin

Related

wasip1 accept/accept4 always wrote the peer sockaddr after a successful
sock_accept. POSIX allows both addr and addrlen to be NULL when the
caller does not need the peer address; the write path null-dereferenced
in that case. Guard the fill the same way wasip2/p3 do via
__wasilibc_sockaddr_validate (both-null is allowed).

Emulated mmap allocates a header+body block, then on non-MAP_ANON
paths fills it with pread. On pread error it returned MAP_FAILED without
freeing that allocation. Free the block and preserve errno.

Host red-green: null memset crashes without the accept guard; free+errno
path drops the allocation and keeps EIO.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
@alexcrichton

Copy link
Copy Markdown
Collaborator

Thanks! Can you write tests for these fixes?

Add suite tests for the WebAssembly#866 fixes:

- sockets-accept-null-addr: accept/accept4 with NULL peer address
  (and a non-null control path). Registered for wasip2/p3 NETWORK
  suite and for wasip1 (non-V8) so accept-wasip1.c is exercised.
- mmap-pread-fail: file-backed emulated mmap with O_WRONLY pread
  failure returns MAP_FAILED, survives leak-stress iterations, and
  still allows MAP_ANON afterward.

Host red-green for both control-flow classes remains a local check;
these tests make the regressions visible in the wasi-libc CI matrix.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
@SebTardif

Copy link
Copy Markdown
Contributor Author

@alexcrichton Thanks, good catch. The first push only had host-side red/green for the control-flow classes (null memset vs both-null guard; free-on-pread-fail vs leak growth), not suite tests. That was insufficient.

Pushed tests in 6059055:

  • test/src/sockets-accept-null-addr.c covers accept/accept4 with NULL, NULL, plus a non-null control path. Registered under the wasip2/p3 NETWORK suite and also for wasip1 (non-V8) so CI exercises accept-wasip1.c when the engine supports sockets.
  • test/src/mmap-pread-fail.c covers emulated mmap on an O_WRONLY fd: must return MAP_FAILED with errno set; 256x1MiB failing maps must not exhaust memory; MAP_ANON still works afterward. Built with -lwasi-emulated-mman.

Sorry for the gap on the first version.

sockets-accept-null-addr timed out in CI: nonblocking connect was not
waited on before send, so send failed with ENOTCONN (errno 53) and recv
hung until the 10s CTest timeout.

Match sockets-select-connecting-rw.c: select for writability and check
SO_ERROR before accept and send.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
The sockets suite is intentionally disabled for wasip1. Registering a
single NETWORK accept test there can hang or fail under preview1 engines
and does not match existing CI policy. Keep sockets-accept-null-addr on
wasip2/p3 (where NETWORK tests already run); wasip1 accept-wasip1.c is
still covered by the same source change and host red-green.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Comment thread test/CMakeLists.txt Outdated
Comment thread test/CMakeLists.txt Outdated
The sockets suite is skipped for preview1, so registering
sockets-accept-null-addr only in that block never exercised
accept-wasip1.c. Register the same NETWORK case for wasip1
(non-V8) as well. Drop CMake comment-per-test notes.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
wasip1 exports accept/accept4 but not socket, bind, listen, or
connect, and SO_ERROR is p2/p3-only in the headers. Registering
sockets-accept-null-addr for preview1 fails the C compile
(-Werror implicit declarations). Keep the NETWORK case on
wasip2/p3 only.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
@alexcrichton
alexcrichton merged commit 85d6701 into WebAssembly:main Aug 12, 2026
36 checks passed
@SebTardif
SebTardif deleted the fix/accept-null-and-mmap-leak branch August 12, 2026 22:50
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.

2 participants