Merge pull request #9727 from KernelPanicNT/fix/net-reject-unsupported-flags

fix(libSceNet): reject the flags and names the module rejects
This commit is contained in:
Adrià authored and GitHub committed 2026-10-26 00:07:35 +01:00
commit b76f08cf33
3 files changed
+40 -8

No files matched your search

+4 -8
View File
@@ -1787,8 +1787,7 @@ int APS5_VABI sceNetGetSockInfo6(std::int32_t s, NetSockInfo6* info, std::uint32
}
int APS5_VABI sceNetEpollCreate(const char* name, int flags) {
(void)name;
(void)flags;
if (!name || flags != 0) return fail(NET_EINVAL);
std::lock_guard lk(g_mutex);
const int id = g_next_epoll++;
g_epolls.insert(id);
@@ -2074,8 +2073,7 @@ int APS5_VABI sceNetEtherStrton(const char* text, NetEtherAddr* address) {
}
int APS5_VABI sceNetGetMacAddress(NetEtherAddr* addr, int flags) {
(void)flags;
if (addr == nullptr) {
if (addr == nullptr || flags != 0) {
return fail(NET_EINVAL);
}
// Keep guest identity stable without exposing the host adapter address.
@@ -2088,7 +2086,7 @@ int APS5_VABI sceNetGetMacAddress(NetEtherAddr* addr, int flags) {
int APS5_VABI sceNetResolverCreate(const char* name, int memid, int flags) {
(void)name;
(void)memid;
(void)flags;
if (flags != 0) return fail(NET_EINVAL);
std::lock_guard lk(g_mutex);
const int id = g_next_resolver++;
g_resolvers[id] = {};
@@ -2148,9 +2146,7 @@ int lookup_ipv4(int rid, const char* hostname, const char* func, std::vector<std
}
int APS5_VABI sceNetResolverStartNtoa(int rid, const char* hostname, void* addr, int timeout, int retry, int flags) {
(void)timeout;
(void)retry;
(void)flags;
if (timeout < 0 || retry < 0 || (static_cast<unsigned>(flags) & 0xfffefffeu) != 0) return fail(NET_EINVAL);
if (!hostname || !addr) return fail(NET_EINVAL);
std::vector<std::uint32_t> addresses;
if (const int error = lookup_ipv4(rid, hostname, __func__, addresses)) return error;
+35
View File
@@ -505,6 +505,40 @@ static void CheckEmptyEpoll() {
}
}
static void CheckRejectedArguments() {
Require(Failed(sceNetEpollCreate(nullptr, 0), 22));
for (const int flags : {1, 0x10000, -1}) Require(Failed(sceNetEpollCreate("rejected-epoll", flags), 22));
std::array<std::uint8_t, 6> untouched{};
untouched.fill(0xA5);
NetEtherAddr mac{};
std::memcpy(mac.data, untouched.data(), untouched.size());
for (const int flags : {1, 0x10000, -1}) {
Require(Failed(sceNetGetMacAddress(&mac, flags), 22));
Require(std::memcmp(mac.data, untouched.data(), untouched.size()) == 0);
}
Require(Failed(sceNetGetMacAddress(nullptr, 1), 22));
for (const int flags : {1, 0x10000, -1}) Require(Failed(sceNetResolverCreate("rejected-resolver", 0, flags), 22));
std::array<std::uint8_t, 4> ipv4{};
const int resolver = sceNetResolverCreate("rejected-ntoa", 0, 0);
Require(resolver >= 0);
Require(sceNetResolverAbort(resolver, 1) == 0);
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), -1, 1, 0), 22));
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, -1, 0), 22));
for (const int flags : {2, 0x20000, 0x10003, static_cast<int>(0x80000000u), -1})
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, flags), 22));
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, 0), 4));
Require(sceNetResolverDestroy(resolver) == 0);
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), -1, 0, 0), 22));
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 0, -1, 0), 22));
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 0, 0, 2), 22));
for (const int flags : {0, 1, 0x10000, 0x10001})
Require(Failed(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 0, 0, flags), 9));
}
static void CheckDontWait() {
constexpr int DontWait = 0x80;
constexpr int Peek = 0x2;
@@ -1864,6 +1898,7 @@ int main() {
CheckNetMemory();
CheckNetstat();
CheckEmptyEpoll();
CheckRejectedArguments();
CheckDontWait();
CheckAddressText(2, "127.0.0.1");
CheckAddressText(2, "255.255.255.255");
+1
View File
@@ -54,6 +54,7 @@
- [sceNetResolverStartNtoa6](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) resolves a host name to its first IPv6 address through the host resolver (`getaddrinfo` with `AF_INET6`) and writes the 16-byte address; the `(rid, hostname, addr, timeout, retry, flags)` signature follows `sceNetResolverStartNtoa`. A name with no IPv6 address fails with `RESOLVER_ENODNS` (`0x804101E1`) like a failed lookup; whether the console returns IPv4-mapped addresses instead is not verified. Timeout and retry are ignored as in `sceNetResolverStartNtoa`, and any nonzero flags throw because their meaning for this call is not known. Unverified on hardware.
- [sceNetInetPton](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) - an IPv6 conversion with a null `dst` returns `NET_EINVAL` here, where it crashed a payload process on a PS5 (firmware 13.60). On that PS5 and on PS4 firmware 10.71 an IPv4 address ends at the first space, tab, LF, VT, FF or CR and the rest is ignored (`"1.2.3.4 x"` converts), and a failed conversion leaves the destination and `sceNetErrnoLoc` unchanged. On the PS5 the dotted IPv4 part of IPv6 text is read the same way (`"::ffff:1.2.3.4 x"` converts, `"::ffff:01.2.3.4"` fails), and an IPv4 conversion with a null `dst` returns 1 or 0 without writing. Leading whitespace, any other trailing byte (`0x01`, `0xa0`) and whitespace after hexadecimal IPv6 text fail
- [sceNetInetPton, sceNetInetNtop](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) convert IPv6 text with libkernel's [inet_pton and inet_ntop](../../../core/libs/prx/libkernel/Socket/src/AddressConversion.cpp), so they take the same FreeBSD 11.4 text forms; beyond the PS5 measurements in the entry above, these are unverified on a console. IPv4 text keeps the host conversion. The checks and errors before the conversion are libSceNet's own and unchanged
- [sceNetResolverStartNtoa](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) ignores flag bits 0x1 and 0x10000 and does not apply the timeout or retry count: every lookup runs once, synchronously, through the host resolver. What those two bits do on a console is not known; the sceNetResolverAbort entry above gives shadPS4's names for them. A negative timeout or retry and any other flag bit fail with `EINVAL` before anything else is checked, as [prosper's reading of the libSceNet module](https://github.com/mattias800/prosper/blob/6c09a34a092a00898fcead5f855200ca7c368cd2/prosper/src/hle/net/hle_net.cpp#L579-L587) gives
- [sceNetDhcpStart, sceNetAddrConfig6Start, sceNetDuplicateIpStart and sceNetInfoDumpStart](../../../core/libs/prx/libSceNet/Export.cpp) - argument widths and callback ABI are recovered. Address callbacks receive user data, a 32-bit event and a 32-bit error. DHCP configuration is mutable; the 512-byte IPv6 configuration is read-only. Their complete field layouts remain unknown. The two 32-bit thread parameters are stored but not consumed by this firmware thread wrapper, so their original names and units are unconfirmed. Information-dump options contain flags, an interval in seconds and a 64-byte path. All four exports remain unimplemented.
- [sceNetSetDnsInfo, sceNetSetDns6Info and sceNetGetDns6Info](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) - the resolver still uses the host's DNS servers; setters only store servers for the getters. Without an IPv6 override, the getter reports none. Counts follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/0918faa0255e9816b795b62c9b09eaea51a1bc5e/src/core/libraries/net/net.cpp), not hardware measurements. All four DNS calls' initialization and argument errors match a reported [firmware 13.42 module probe](https://github.com/boykopovar/AnyPS5/pull/9506#issuecomment-6390574180): ENOTINIT first, then EINVAL for nonzero flags, null getter outputs or zero primary servers; null setters clear the override. Setters use a checked guest read and return EFAULT for unreadable non-null inputs, an AnyPS5 safety measure absent from the probed module.