Skip to content

fix(libSceNet): close a libkernel socket through sceNetSocketClose - #6140

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
milescoviello:fix/net-close-kernel-socket
Oct 18, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
milescoviello:fix/net-close-kernel-socket

Conversation

@milescoviello

Copy link
Copy Markdown
Contributor

What

MXGP 26: The Official Game (PPSA30839) opens TCP sockets with libkernel's socket(), then closes them with sceNetSocketClose. sceNetSocketClose only looked in libSceNet's own socket table, so it failed every one of those closes with SCE_NET_ERROR_EBADF (0x80410109), and the host socket stayed open. On the console, libSceNet's calls and libkernel's socket calls work on the same kernel sockets.

Now, when sceNetSocketClose gets a descriptor that libSceNet doesn't own but libkernel has open as a socket (GuestSocketIsOpen_nid_no_patch), it closes it through libkernel's close(). Any other descriptor still fails with EBADF, as before.

The fallback runs after g_mutex is released. libkernel's close() first asks libSceNet's registered socket closer, and that closer takes g_mutex.

guest_sce_net gains a check:

  • it opens a TCP socket with libkernel's socket() and closes it with sceNetSocketClose;
  • libkernel no longer reports the socket open;
  • a second sceNetSocketClose fails with EBADF.

Tested

Ubuntu 24.04, GCC 13.3 (CI's compiler), Release with CI's configure flags, on main eea428c:

  • guest_sce_net aborts with main's Export.cpp and passes with the change.
  • All 376 guest_* tests pass.
  • tools/check_conventions.py --base upstream/main passes.
  • PPSA30839 relinked with --to-intel, 90 s, every libSceNet socket call traced under gdb:
    • On main, sceNetSocketClose returns 0x80410109 for descriptors 7, 9 and 11. 7 and 9 came from libkernel's socket(2, 1, 0).
    • With this change, all three return 0.
    • Its sceNetSetsockopt(11, IPPROTO_TCP, TCP_NODELAY) still fails with EBADF. Setting options on a libkernel socket through libSceNet is a separate change, and feat(libkernel): answer TCP_NODELAY, SO_NOSIGPIPE and SO_NBIO on a guest socket #5565 covers TCP_NODELAY on libkernel sockets.

Not checked on a console.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 5836 core/libs/prx/libSceNet/Export.cpp
core/libs/tests/GuestSceNet.cpp
PR 6044 core/libs/tests/GuestSceNet.cpp
PR 6138 core/libs/tests/GuestSceNet.cpp
PR 7201 core/libs/prx/libSceNet/Export.cpp

@adriadam10

Copy link
Copy Markdown
Collaborator

Checked build and ctest (guest_sce_net passes; it fails when Export.cpp is reverted), the lock ordering (fallback runs after g_mutex is released) and the EBADF path for descriptors neither library owns; merging.

MXGP 26 (PPSA30839) opens TCP sockets with libkernel's socket() and
later closes them with sceNetSocketClose. libSceNet only looked in its
own socket table, so every one of those closes failed with
SCE_NET_ERROR_EBADF and the host socket stayed open. On the console both
calls work on the same kernel sockets.

A descriptor libSceNet does not own but libkernel has open as a socket
is now closed through libkernel's close(). Anything else still fails
with EBADF. The fallback runs after g_mutex is released, because
libkernel's close() first asks libSceNet's socket closer, which takes it.

guest_sce_net closes a libkernel TCP socket with sceNetSocketClose,
checks that libkernel no longer has it open, and checks that a second
close fails with EBADF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@milescoviello
milescoviello force-pushed the fix/net-close-kernel-socket branch from 1c65051 to 8b81fa0 Compare October 17, 2026 18:33
@milescoviello

Copy link
Copy Markdown
Contributor Author

@adriadam10, I rebased this onto main e383833 earlier today, as part of rebasing my older PRs. The head moved from 1c65051 to 8b81fa0 and the patch is unchanged (git range-diff shows =). In case your merge didn't go through: after the rebase, guest_sce_net passes 3 of 3 and ^guest_ passes 409 of 409.

AI-assisted: yes (Claude Code)

@oneandonlydean oneandonlydean self-assigned this Oct 18, 2026
@oneandonlydean
oneandonlydean merged commit 029cc57 into boykopovar:main Oct 18, 2026
8 checks passed
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Merged while @adriadam10 is away: the review passed and full CI is green on this head.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants