Skip to content

fix(libSceNpAuth): return INVALID_ARGUMENT from async poll and wait for unwritable pointers - #13985

Merged
oneandonlydean merged 6 commits into
boykopovar:mainfrom
pushkarreddyy:fix/npauth-poll-wait-efault
Nov 5, 2026
Merged

oneandonlydean merged 6 commits into
boykopovar:mainfrom
pushkarreddyy:fix/npauth-poll-wait-efault

Conversation

@pushkarreddyy

Copy link
Copy Markdown
Contributor

What

sceNpAuthPollAsync and sceNpAuthWaitAsync in libSceNpAuth directly dereference the caller's result output pointer without verifying memory write accessibility. If an unwritable or unmapped guest address is passed, the process halts on memory violation instead of returning ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT (0x80550301).

This PR:

  1. Validates result in sceNpAuthPollAsync and sceNpAuthWaitAsync using GuestCopyOut_nid_no_patch.
  2. Returns ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT (0x80550301) if writing the request status to guest memory fails.
  3. Adds test coverage in core/libs/tests/GuestNpAuth.cpp asserting ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT on invalid output pointers in both poll and wait.
  4. Documents memory validation fallback in docs/dev/debt/libSceNpAuth.md.

Closes #13980

Tested

ctest --test-dir build -R GuestNpAuth -V passes.
python tools/check_conventions.py --base origin/main reports 0 findings and 0 errors.

Checklist

  • Code follows the project style: no comments, conventional commits, exports match PS5 headers.
  • All new and existing tests pass.
  • Any and all debt documented in docs/dev/debt/libSceNpAuth.md.
  • Depends on: none
  • AI-assisted: yes
  • Unblocks: none

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed — looks good

At head 735af9208028310c03b761cf5c8fbeffee748570, the new guarded-copy failures return ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT, consistent with the existing null-output checks, and the regression assertions cover both APIs (Export.cpp, GuestNpAuth.cpp). Hosted Windows, conventions, library portability, intake, labels, eligibility, and report checks passed. The author reports the focused CTest passed; I did not run a local build or test, and product CI jobs were skipped.

@github-actions github-actions Bot added the fix error Closes an issue (Fixes #N) label Oct 31, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@pushkarreddyy reviewed at 735af92080. Both functions write the same 4-byte int as before through a checked copy; a failed copy leaves the request alone (only sceNpAuthDeleteRequest erases it, and the polled flag is set before the copy), so a retry with a good pointer still returns the result; the null check stays first, and the code is the one the functions already return for a null pointer. Requests:

  1. In both functions the copy-out runs while g_requestMutex is held, the mutex every request call takes, so a slow copy (on Linux a process_vm_writev system call) holds all other NpAuth requests. Please read it->second.result inside the lock and call GuestCopyOut_nid_no_patch after the lock is released.
  2. The debt entry says the functions "return ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT on null or unwritable result pointers". Please add that the code for a non-null unmapped pointer is a host-safety fallback and not measured on a console, and that the first sceNpAuthPollAsync call returns the running status without looking at the pointer, as before.
  3. The new test calls each function with a bad pointer after the request has finished, but not that the result is still available afterwards. Please add a good-pointer sceNpAuthWaitAsync after the failed call and require the same result.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-checked — new head, changes requested

At head 735af9208028310c03b761cf5c8fbeffee748570 against base 73f4f7e06e4f210a8c6570e335fd654dc0a86134, the implementation’s first-poll path returns NP_POLL_ASYNC_RUNNING before it attempts the result copy, so the debt entry overstates the invalid-pointer behavior.

What I ran

I inspected the exact PR source and test sequence, the existing review thread, and the no-build precheck for this head. git diff --check, conventions/template validation, and the current-base merge preview passed. Hosted Windows passed; Linux and specialized product jobs were skipped. Environment: Linux x86_64, Python 3.11.2, GCC 12.2.0. I did not build or run tests locally.

python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 13985
gh pr diff 13985 -R boykopovar/AnyPS5
gh pr checks 13985 -R boykopovar/AnyPS5

Findings

Blocking

The debt entry says sceNpAuthPollAsync and sceNpAuthWaitAsync return ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT on null or unwritable result pointers. For a processed async request’s first non-null PollAsync call, the implementation sets polled and returns NP_POLL_ASYNC_RUNNING before calling GuestCopyOut_nid_no_patch; invalid request state also returns its request-state error before any copy. Narrow the debt statement to the paths that actually attempt to write the result, and record that the unmapped-pointer result is a host-safety fallback rather than a console measurement (poll implementation, debt entry).

Non-blocking

The test checks both bad-pointer errors but does not retry with a valid output pointer afterward. A follow-up sceNpAuthWaitAsync assertion would verify that a failed copy leaves the result available, as the current implementation appears to do.

Not verified

I did not build or run the focused test locally. The Windows CI job passed; the Linux and specialized product jobs were skipped.

To get this to a good state

Narrow the debt entry to the result-copy paths and distinguish the host pointer-safety fallback from measured console behavior. I will rerun the same relevant checks on the updated head.

@pushkarreddyy

Copy link
Copy Markdown
Contributor Author

@oneandonlydean Thanks for the thorough review!

All three requests have been addressed:

  1. In 69f992e113, g_requestMutex is released before calling GuestCopyOut_nid_no_patch in both sceNpAuthPollAsync and sceNpAuthWaitAsync, reading it->second.result under the lock and copying out afterwards to avoid holding the mutex across the system call.
  2. In c81f0b70cc, updated the debt entry in docs/dev/debt/libSceNpAuth.md to document that ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT on a non-null unmapped pointer is an unmeasured host-safety fallback and that the initial poll call returns the running status without reading the pointer.
  3. In cdf2e6aa35, updated core/libs/tests/GuestNpAuth.cpp to call sceNpAuthWaitAsync with a good pointer after the invalid-pointer calls and assert that the finished result (signedOut) remains available.

@pushkarreddyy

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Thanks for the review!

The findings you noted have been fully resolved in head c81f0b70cc (which passed all hosted CI checks, including Windows in 2m41s):

  1. Debt Clarification: In c81f0b70cc, docs/dev/debt/libSceNpAuth.md was narrowed to document that ORBIS_NP_AUTH_ERROR_INVALID_ARGUMENT for non-null unmapped pointers is an unmeasured host-safety fallback on result-copy paths, and that the initial poll returns NP_POLL_ASYNC_RUNNING without reading the pointer.
  2. Result Availability Assertion: In cdf2e6aa35, core/libs/tests/GuestNpAuth.cpp was updated to perform a good-pointer sceNpAuthWaitAsync call following the invalid-pointer calls and require the same finished result (signedOut).
  3. Lock Scope: In 69f992e113, g_requestMutex is released before calling GuestCopyOut_nid_no_patch in both sceNpAuthPollAsync and sceNpAuthWaitAsync.

@pushkarreddyy

Copy link
Copy Markdown
Contributor Author

Hi @oneandonlydean,

All review feedback across the recent pull requests (#13950, #13953, #13956, #13960, #13968, #13970, #13974, #13979, #13985) has been addressed with atomic commits, pre-verified against conventions (0 findings), and is passing 100% of CI checks.

We have a number of older PRs that have been thoroughly reviewed, verified across platforms, and have been waiting for final maintainer verification and merge:

Whenever you have a moment, could you please take a look to verify and merge the approved ones? Thank you very much for your time and continued guidance!

@pushkarreddyy
pushkarreddyy force-pushed the fix/npauth-poll-wait-efault branch from c81f0b7 to c0c64df Compare November 1, 2026 06:25
@pushkarreddyy

Copy link
Copy Markdown
Contributor Author

Hi @bunbeans2-arch @jotitadev,

If you have a moment to test on Windows or Linux, could you run the focused test for libSceNpAuth?

ctest --test-dir build -R '^guest_np_auth' --output-on-failure

We recently updated GuestNpAuth.cpp with a retry verification assertion after an unwritable pointer call, per reviewer feedback from @MarcZX10. A machine test log would be very helpful. Thank you!

@bunbeans2-arch

Copy link
Copy Markdown
Contributor

A Windows run with GCC 16: Windows 11 Pro 10.0.22631, i9-9900K, MSYS2 UCRT64 GCC 16.1.0, Release, this PR (c0c64df082) merged into main 1f2c1da.

  • ✅ With this PR: guest_np_auth passed 5 of 5.
  • ❌ Same tree with only Export.cpp put back to main (this PR's test kept): it crashed with an access violation (0xc0000005) inside libSceNpAuth.prx in 5 of 5 runs.
  • ✅ main 1f2c1da alone (its own tests and source): the same test passed 3 of 3.

Looks good on Windows, no more segfaults at login 😄👍

AI-assisted: yes (Claude Code)

@pushkarreddyy
pushkarreddyy force-pushed the fix/npauth-poll-wait-efault branch 2 times, most recently from af6c6fd to 13758cb Compare November 2, 2026 02:21
@pushkarreddyy

Copy link
Copy Markdown
Contributor Author

Hi @MarcZX10,

The request retry verification and mutex release before copying out the result were added, and @bunbeans2-arch kindly tested the suite on Windows 11 with GCC 16.1.0 (MSYS2 UCRT64, Release), confirming 5/5 passed with the patch and 5/5 crashed in negative control.

The branch has also been cleanly rebased onto latest origin/main (head 13758cbef3) with 0 convention findings. Ready for your review.

@pushkarreddyy
pushkarreddyy force-pushed the fix/npauth-poll-wait-efault branch 3 times, most recently from b61d98a to f69e9c6 Compare November 3, 2026 15:35
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ AMD GPU test: passed

PR head f69e9c6 merged onto main 4f41f4c · tested 2026-11-03 15:59 UTC · 15 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 1,139 passed · 6 failed (0 new, 4 also fail on main, 2 unstable on main) · 6 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 1,151 of 3,811 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (547 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.1 s, ⚠️ agc_driver_lazy_resolved_abi 62.3 s, ⚠️ agc_driver_image_sample_unnormalized 59.6 s, ⚠️ agc_driver_sample_multisample_target 46.9 s, ⚠️ public_headers 43.7 s
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 7 of the last 9 main runs
agc_driver_store_over_untracked: failed in 1 of the last 9 main runs
Failing on main too (4, not counted against this PR)
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_multisample_depth
agc_driver_submit_progress
Validation IDs already present on main (4 IDs in 468 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (468 tests): agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, agc_driver_bindless_images, and 460 more
VUID-vkCmdCopyImage-srcImage-01548 (8 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth, agc_driver_stencil_null_feedback, agc_driver_stencil_plane_memory
VUID-vkCmdCopyImage-srcImage-01551 (8 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth, agc_driver_stencil_null_feedback, agc_driver_stencil_plane_memory
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_srgb8_color_target
Skipped (6)
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
Reproduce
git fetch origin f69e9c615ffd17e718e8c44a2e84b0a380327d29 4f41f4c375f5abb487dbd184fbc150f31994d762
git checkout 4f41f4c375f5abb487dbd184fbc150f31994d762 && git merge --no-ff f69e9c615ffd17e718e8c44a2e84b0a380327d29
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@pushkarreddyy
pushkarreddyy force-pushed the fix/npauth-poll-wait-efault branch 2 times, most recently from 2ddb4b1 to 6f0ce5f Compare November 4, 2026 17:42
@pushkarreddyy
pushkarreddyy force-pushed the fix/npauth-poll-wait-efault branch from 6f0ce5f to 31733f5 Compare November 5, 2026 12:36
@oneandonlydean oneandonlydean self-assigned this Nov 5, 2026
@oneandonlydean
oneandonlydean dismissed MarcZX10’s stale review November 5, 2026 23:01

Addressed at 31733f5: the debt entry now limits INVALID_ARGUMENT to non-null unmapped pointers as a host-safety fallback (console unmeasured) and says the first sceNpAuthPollAsync returns running status without reading the pointer; GuestNpAuth.cpp retries with a valid pointer after the failed calls and requires the same result.

@oneandonlydean
oneandonlydean merged commit 90e7727 into boykopovar:main Nov 5, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs fix error Closes an issue (Fixes #N) prx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(libSceNpAuth): return INVALID_ARGUMENT from async poll and wait for unwritable pointers

5 participants