Do not forward fw 5.02 AppContent RPCs to an older service #1

Merged
sparky3387 merged 1 commit from fix/appcontent-fw502-rpc-hang into main 2026-08-21 03:39:46 -05:00
sparky3387 commented 2026-08-19 20:22:37 -05:00 (Migrated from github.com)

Forwarding an unsupported AppContent RPC to the firmware's SceAppContent service hangs the console. app_rpc_invoke is a synchronous IPMI invoke with no timeout, so a command the running firmware does not implement never completes: the calling thread blocks forever and the watchdog reboots. There is no error to detect and no way to probe for support, because an unsupported command hangs rather than returning.

Three commands arrived with fw 5.02 and hang on anything older:

RPC Function
0x20010 sceAppContentDownloadDataGetBlockSize
0x20023 sceAppContentDownload2Shrink
0x20024 sceAppContentDownload2Expand

They are part of one feature: a third download-data area (/download2) plus its block-size query.

Reproduced on Call of Duty MW2 (PPSA23012) on fw 4.03, which calls Download2Expand during first-run setup and reboots the console.

Measured on fw 4.03: SceShellCore contains no download2 string in any casing, and its download-data subsystem is numbered 0 and 1 only (SceFsckDownloaddata0/1, UnMountDownloadData()/1(), process_download_data.cpp and process_download_data_1.cpp). The area is never provisioned and the service has no handler for these commands.

The fix

Gate the three commands on the running firmware and answer locally with SCE_APP_CONTENT_ERROR_NOT_SUPPORTED when it predates 5.02. Callers already handle that code — it is one of the codes the service's own result mapper passes through verbatim rather than folding to INTERNAL.

compiled_sdk_version() cannot be used for this. It returns SCE_PROSPERO_SDK_VERSION, a build-time constant describing the SDK the module was compiled against, so it cannot tell one console from another and a gate built on it silently does nothing.

sceKernelGetProsperoSystemSwVersion is used instead. It exists on every firmware from 1.00 onward, so a single binary stays correct on old and new alike with no build matrix. It is not declared by any public SDK header and is missing from the SDK's libkernel_stub_weak.a, so the out-param shape was read off fw 4.03's libkernel_sys and a link stub is generated the same way this project already generates one for libSceLibcInternal. libkernel.sprx does export the symbol, so only the stub was missing. ps5-payload-sdk declares it the same way.

Failing to read the version counts as absent: answering locally costs a graceful NOT_SUPPORTED that callers handle, while forwarding costs an unrecoverable reboot.

Also in this change

The comments on Download2Shrink/Download2Expand described the argument as an opaque download-data handle. It is a size in MiB passed by value — confirmed from the caller, which computes it arithmetically and never dereferences it. Corrected.

*blockSize is deliberately left unwritten on refusal: a negative Sce error means out-params are not read, which is the firmware's own contract.

Only libSceAppContent links the new stub; the other two modules do not call the version API.

No version bump is included — release numbering left to you.

Forwarding an unsupported AppContent RPC to the firmware's `SceAppContent` service hangs the console. `app_rpc_invoke` is a synchronous IPMI invoke with no timeout, so a command the running firmware does not implement never completes: the calling thread blocks forever and the watchdog reboots. There is no error to detect and no way to probe for support, because an unsupported command hangs rather than returning. Three commands arrived with fw 5.02 and hang on anything older: | RPC | Function | |---|---| | `0x20010` | `sceAppContentDownloadDataGetBlockSize` | | `0x20023` | `sceAppContentDownload2Shrink` | | `0x20024` | `sceAppContentDownload2Expand` | They are part of one feature: a third download-data area (`/download2`) plus its block-size query. **Reproduced** on Call of Duty MW2 (PPSA23012) on fw 4.03, which calls `Download2Expand` during first-run setup and reboots the console. **Measured on fw 4.03:** `SceShellCore` contains no `download2` string in any casing, and its download-data subsystem is numbered 0 and 1 only (`SceFsckDownloaddata0/1`, `UnMountDownloadData()`/`1()`, `process_download_data.cpp` and `process_download_data_1.cpp`). The area is never provisioned and the service has no handler for these commands. ### The fix Gate the three commands on the **running** firmware and answer locally with `SCE_APP_CONTENT_ERROR_NOT_SUPPORTED` when it predates 5.02. Callers already handle that code — it is one of the codes the service's own result mapper passes through verbatim rather than folding to `INTERNAL`. `compiled_sdk_version()` cannot be used for this. It returns `SCE_PROSPERO_SDK_VERSION`, a build-time constant describing the SDK the module was compiled against, so it cannot tell one console from another and a gate built on it silently does nothing. `sceKernelGetProsperoSystemSwVersion` is used instead. It exists on every firmware from 1.00 onward, so a single binary stays correct on old and new alike with no build matrix. It is not declared by any public SDK header and is missing from the SDK's `libkernel_stub_weak.a`, so the out-param shape was read off fw 4.03's `libkernel_sys` and a link stub is generated the same way this project already generates one for `libSceLibcInternal`. `libkernel.sprx` does export the symbol, so only the stub was missing. ps5-payload-sdk declares it the same way. Failing to read the version counts as **absent**: answering locally costs a graceful `NOT_SUPPORTED` that callers handle, while forwarding costs an unrecoverable reboot. ### Also in this change The comments on `Download2Shrink`/`Download2Expand` described the argument as an opaque download-data handle. It is a size in MiB passed by value — confirmed from the caller, which computes it arithmetically and never dereferences it. Corrected. `*blockSize` is deliberately left unwritten on refusal: a negative Sce error means out-params are not read, which is the firmware's own contract. Only `libSceAppContent` links the new stub; the other two modules do not call the version API. No version bump is included — release numbering left to you.
Sign in to join this conversation.
No description provided.