Skip to content

fix(libSceUserService): validate user login status in sceUserServiceGetGamePresets - #11087

Merged
oneandonlydean merged 2 commits into
boykopovar:mainfrom
slopgobblercobbler:fix/userservice-gamepresets-login-validation
Nov 2, 2026
Merged

oneandonlydean merged 2 commits into
boykopovar:mainfrom
slopgobblercobbler:fix/userservice-gamepresets-login-validation

Conversation

@slopgobblercobbler

@slopgobblercobbler slopgobblercobbler commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

  • Validates presets pointer before user login status in sceUserServiceGetGamePresets, returning USER_SERVICE_ERROR_INVALID_ARGUMENT (0x80960005) when presets == nullptr per PS5 firmware 13.42 disassembly.
  • Validates user login status when presets is valid, returning USER_SERVICE_ERROR_NOT_LOGGED_IN (0x80960009) when querying a non-logged-in user.
  • Removes undocumented inline comment from core/libs/prx/libSceUserService/Export.cpp per CONVENTIONS.md:12.
  • Documents unmeasured game presets profile behavior and firmware 13.42 disassembly findings in docs/dev/debt/libSceUserService.md.
  • Expands unit tests in core/libs/tests/GuestUserService.cpp covering logged-in user, absent users (valid buffer and nullptr), and connected/disconnected user transitions.

Tested

  • Tested via core/libs/tests/GuestUserService.cpp covering login transitions and parameter validation.
  • Windows 11 host verification courtesy of @maskym: Windows 11 (build 26300, Intel i7-12700K, WinLibs GCC 15.2.0 r6, Ninja, Release); guest_user_service, guest_user_service_user_name, and guest_user_service_lifecycle all passed (14/14 joint tests passed).
  • Ran python tools/check_conventions.py --base upstream/main --head HEAD: 0 findings.

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 under Silent stubs in their library's technical debt file
  • 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
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@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.

The code and regression cases are consistent with IsUserLoggedIn and the existing USER_SERVICE_ERROR_NOT_LOGGED_IN behavior: they cover unknown IDs, disconnected users, no output mutation on failure, null output precedence, and the disconnected-to-connected transition.

The Tested section only says the test was exercised via GuestUserService.cpp; it does not identify the OS/toolchain or a command/result, and the hosted windows product job is skipped. CONTRIBUTING.md requires tests to be run before opening a PR and the template asks what and where was checked. Please provide the focused test command and environment/results, or state explicitly that the test was not run. I cannot run it locally because full configuration stops at the unavailable SDL2 development package.

@github-actions

github-actions Bot commented Oct 25, 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 9345 core/libs/prx/libSceUserService/Export.cpp
PR 14212 docs/dev/debt/libSceUserService.md

@MarcZX10

Copy link
Copy Markdown
Contributor

I manually checked the overlap bot’s shared-file warnings against the current heads. git merge-tree finds a real debt-file conflict with #10842. It also finds Export.cpp/UserService.hpp conflicts with #9345 and an Export.cpp conflict with #9826; those PR diffs touch different routines (GetUserName, accessibility stubs, and GetGamePresets here), so this is integration coordination rather than duplicate function work. #6990’s UserService hunks auto-merge; its reported conflicts are limited to libSceNpManager/Export.cpp and GuestNpManager.cpp. Please agree an order for the actual shared-file conflicts and update Depends on if one must land first. The separate request for the focused test environment/command is still open.

@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 exact head 63b354ce2a1a86f3cbcbbe2afd2b617a7e79663c. The new login check matches the ordering used by sceUserServiceGetAgeLevel and the accessibility getters: a non-logged-in/unknown id returns USER_SERVICE_ERROR_NOT_LOGGED_IN before pointer validation, and leaves output unchanged. The added cases cover invalid ids, disconnected/connected secondary users, and null output precedence. I compiled the changed Export.cpp and GuestUserService.cpp with GCC 12.2 (-std=c++20 -Icore/libs -fsyntax-only); conventions and git diff --check upstream/main...HEAD pass. I could not run the test binary: full CMake configuration here stops because SDL2 development files are unavailable, and hosted product test jobs are skipped by path policy. The PR description identifies GuestUserService.cpp as its focused test.

@slopgobblercobbler

Copy link
Copy Markdown
Contributor Author

@MarcZX10 Thank you for the review and approval, and for checking the merge-tree overlap analysis against #10842, #9345, and #9826! I will keep an eye on them and rebase promptly if any of them merge before #11087.

@wachi35676

Copy link
Copy Markdown
Contributor

Tested head 63b354ce2a merged onto main acb900c194, Windows 11 (WinLibs GCC 15.2.0, Release) and WSL2 Ubuntu 24.04 (GCC 13.3), BUILD_TESTING=ON.

  • guest_user_service passes 3 of 3 runs on both hosts. With libSceUserService/Export.cpp from main and the test kept, it fails on both.
  • fix(libSceUserService): validate user in sceUserServiceGetPlatformPrivacyWs1 #11071 edits the same two files. git merge-tree of the two heads is clean, and guest_user_service also passes 3 of 3 on Windows with both merged onto main.
  • One wording point. An unknown id (0, USER_SERVICE_USER_ID_INVALID, 0xff, 0x12345678) used to get USER_SERVICE_ERROR_INVALID_ARGUMENT and now gets USER_SERVICE_ERROR_NOT_LOGGED_IN. That follows sceUserServiceGetAgeLevel, but for an unknown id the existing sceUserServiceGetUserName entry records 0x80960105 from a PS5, and nothing was measured for this call. The new debt line says "A user who is not logged in returns 0x80960009". It could say that this order and code are taken from GetAgeLevel and not measured for GetGamePresets.

AI-assisted: yes (Claude Code); results above were run on this machine.

@oneandonlydean oneandonlydean self-assigned this Oct 26, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@slopgobblercobbler I checked the new login and pointer ordering. Could you make the GamePresets debt entry explicit that this ordering and 0x80960009 are borrowed from GetAgeLevel and have not been measured for GetGamePresets? The current sentence reads as an established result for this call. Please retain the unmodelled preset values and the login-transition regression checks.

@BunnyFl

BunnyFl commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Firmware data for the GamePresets debt entry. In 13.42's libSceUserService.sprx (sha256 f49b616f6d1bdf45…), sceUserServiceGetGamePresets doesn't share code with sceUserServiceGetAgeLevel. Per the disassembly:

  • The export (0xa0d0) sends a one-time telemetry record, then jumps through the library's function table (slot +0xc8).
  • A load-time initializer (0x4760, listed at 0x18350) fills that table from 0x18000, which puts 0x4300 in the slot. sceUserServiceInitialize and Initialize2 pass no table and leave it alone. Only InitializeForShellCore passes a replacement.
  • 0x4300 checks the library context (NULL → 0x80960002), then the presets pointer (NULL → 0x80960005). It then makes IPC call 0x30026 with the 4-byte user id as input and the caller's pointer as a 0x30-byte output, and returns the service's answer.
  • GetAgeLevel (0xa130) instead calls 0x3870 with the user id and returns 0x80960009 unless that answers 1, before its NULL check. That's the client-side step this head copies.

I ran the export in an x86-64 emulator (unicorn) with that slot set to 0x4300 and the context NULL or a stand-in IPC object that logs the call and answers 0. Three runs gave identical output:

context user id presets result
NULL 0x1001, 0, −1, 0x12345678 NULL or valid 0x80960002, no IPC
set 0x1001, 0, −1, 0x12345678 NULL 0x80960005, no IPC
set 0x1001, 0, −1, 0x12345678 valid IPC 0x30026 with that user id, output buffer 0x30 bytes

So on 13.42 a NULL presets gets 0x80960005 from the library for any user, logged in or not, before the service is asked. This head's tests expect sceUserServiceGetGamePresets(user_id, nullptr) == USER_SERVICE_ERROR_NOT_LOGGED_IN for absent users, and the module doesn't return that. On the GamePresets path, nothing in the library looks at the user id before the IPC call. Whether a valid pointer with a user who isn't logged in gets 0x80960009 depends on the service's answer, which isn't in the dump. The stand-in's 0 in the last row says nothing about that. So login-first ordering doesn't match the library, but the not-logged-in code itself could still be right for a valid pointer.

Also, UserServiceGamePresets on main is 0x28 bytes, and the library gives the service a 0x30-byte output buffer at that pointer. I didn't check how much the service writes.

@slopgobblercobbler
slopgobblercobbler force-pushed the fix/userservice-gamepresets-login-validation branch from 63b354c to 8431a9d Compare October 26, 2026 17:14
@slopgobblercobbler

Copy link
Copy Markdown
Contributor Author

@BunnyFl Thank you so much for the 13.42 firmware disassembly analysis! I have updated the implementation so that the presets null check precedes the user login check (returning 0x80960005 for null pointers across both logged-in and unlogged users), updated the test suite in GuestUserService.cpp, and cited the firmware analysis in the debt entry. Verified clean with tools/check_conventions.py (0 errors).

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 27, 2026
@slopgobblercobbler
slopgobblercobbler force-pushed the fix/userservice-gamepresets-login-validation branch from 16d8bfa to 92c3635 Compare October 27, 2026 15:32
@slopgobblercobbler

slopgobblercobbler commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Rebased cleanly onto latest upstream/main (637522b6b). All conventions verified clean with tools/check_conventions.py --base upstream/main --head HEAD (0 findings).

@maskym

maskym commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Windows result for head 92c363556f, merged into main f759e165d9 (the PR's Tested section names no Windows run).

Host: Windows 11 26300, Intel i7-12700K, WinLibs GCC 15.2.0 (x86_64-ucrt-posix-seh, r6), Release, BUILD_TESTING=ON, Ninja. Build clean.

The tree also carried the open PRs #11945, #11899, #11859, #11772, #10789, #11627, #11354, all merged cleanly, so the run is a joint one; the tests of this PR are guest_user_service, guest_user_service_user_name, guest_user_service_lifecycle (0.03-0.04 s), all passed (the batch's 14 tests: 14/14). Not run on a PS5.

AI-assisted: yes (Claude Code), the runs and the numbers above are from this machine.

@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 — changes requested

The null-pointer precedence, login-state behavior, test preservation, and disassembly caveat are clearly documented. This branch is still 36 commits behind current main 52c09d567d2fa453494dd720fcf53a98149468e4; the contribution checklist requires a current-main base. The reported Windows run is on an older integration head.

What I ran

  • Reviewed exact head d833409fc2 against current main.
  • Ran a current-main merge preview and git diff --check.
  • Inspected the changed implementation/tests and the author/Windows test reports.

Results

Check Result
Current-main merge preview Clean; current main is not in the branch history
git diff --check Passed
Focused user-service tests Windows report covers guest_user_service, user-name, and lifecycle tests on an older base
Current-main run Not reported

Please refresh onto current main and rerun guest_user_service on that exact head. I did not run the C++ tests locally.

@slopgobblercobbler
slopgobblercobbler force-pushed the fix/userservice-gamepresets-login-validation branch from d833409 to deb8621 Compare October 29, 2026 10:43
@slopgobblercobbler
slopgobblercobbler force-pushed the fix/userservice-gamepresets-login-validation branch from deb8621 to 9c55d91 Compare October 30, 2026 19:25
@slopgobblercobbler

Copy link
Copy Markdown
Contributor Author

@MarcZX10

Refreshed onto current main (16345ca) at head 9c55d91.

  • Rebase is clean with zero merge conflicts.
  • Verified python tools/check_conventions.py --base upstream/main --head HEAD passes cleanly with 0 findings.
  • Pushed with --force-with-lease for upstream CI validation.

@slopgobblercobbler

Copy link
Copy Markdown
Contributor Author

@maskym Thank you for running the Windows 11 test suite on the i7-12700K! I've updated the Tested section in the description with your test results.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants