Switch System Flaws: Difference between revisions
(13 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
This page is a list of publicly known Switch flaws. | |||
= Hardware = | = Hardware = | ||
Line 464: | Line 464: | ||
|} | |} | ||
== | == BootImagePackage System Modules == | ||
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]]. | Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]]. | ||
Line 972: | Line 972: | ||
| January 2, 2023 | | January 2, 2023 | ||
| October 17, 2023 | | October 17, 2023 | ||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[PSC_services|ovln:snd]] OpenSender unvalidated count | |||
| ovln:snd OpenSender has a count param. This count is used to allocate the specified number of objects in a linked-list for storing the data from Send. If count is 0, the linked-list is left empty, with ptrs to itself within the ISender object. | |||
ISender Send when the above linked-list is empty, runs a switch-statement with <code>(inval>>8)&0xFF</code>. This uses another linked-list where the ptrs are initially {within ISender obj}. | |||
No space is allocated in the ISender obj for the linked-list object-data. Therefore using Send with val 1<<8 or 2<<8 (other values throw error) results in the specified input struct being copied into the ISender obj, which then overwrites heap data OOB. | |||
If for example one used OpenSender again right after the first OpenSender usage, then used Send as described above, this would corrupt the second ISender which includes overwriting the vtable. | |||
If one would use Send twice in a row like this, the second one would use a corrupted linked-list (written from the first Send). If the linked-list ptrs would be valid (no crash triggered) this would allow one to copy the input data to a controlled addr, though it's restricted with the linked-list usage. | |||
Using GetUnreceivedMessageCount afterwards is of no interest. | |||
Besides ovln, the only other allocs on this heap is from IPmModule Initialize. This heap is also used for psc:* services (object allocs). | |||
In theory (untested) it may be possible to also use this to obtain infoleaks, however it would only return the high-u32 of ptrs not the low u32. Essentially, one would trigger object allocations so that ExpHeap has layout: {ISender} -> {RF chunk from freeing an object} -> {module object from IPmModule Initialize}. Then one would use the Send vuln to corrupt the RF chunk, changing the size to a larger value. Then one would trigger an object allocation (probably same object which was previously freed), then another object for overwriting the module object (ISender would work) with ptrs at the target offsets in the module object. Then once IPmModule GetRequest is used, the returned u32s would be the high-u32 from ptrs. Due to alignment requirements with each allocation, it isn't possible to shift the allocations in order to leak ptr low-u32. | |||
[17.0.0+] Now throws an error if the input count for OpenSender is 0. | |||
| [[PSC_services|psc]]-sysmodule heap memory corruption ([[NS_services|ns]]-sysmodule on pre-8.0.0). | |||
| [[17.0.0]] | |||
| [[17.0.0]] | |||
| January 13, 2023 | |||
| October 20, 2023 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[NV_services|nv]] NVGPU_GPU_IOCTL_GET_CHARACTERISTICS Ioctl3 infoleak | |||
| The handler code for NVGPU_GPU_IOCTL_GET_CHARACTERISTICS for Ioctl/Ioctl3 are essentially the same, except for the value used for the max-size clamp: Ioctl uses constant 0xA0, while Ioctl3 uses the outbuf1_size. So if one uses this with Ioctl3 and a large outbuf1, this will memcpy data OOB from the source buffer, hence infoleak. | |||
With [17.0.0+] the second block of csel code which previouly essentially used the clamped size from above, was replaced with code which properly clamps to the max-size constant. | |||
| nvservices-sysmodule infoleak, which allows defeating ASLR. | |||
| [[17.0.0]] | |||
| [[17.0.0]] | |||
| February 25, 2022 | |||
| October 24, 2023 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[Audio_services|audctl]] GetTargetDeviceInfo infoleak | |||
| audctl GetTargetDeviceInfo calls an impl func with a ptr to a stackbuf, then if successful memcpys the 0x100-bytes from that buffer to output. This stackbuf is not memset. This func (after doing various state checks) copies a string to output, other than always writing a NUL-terminator there's no clearing of the buffer. | |||
This will leak audio-sysmodule stack into the output buffer as long as the state/input checks pass (for the remainder of the buffer following the string NUL-terminator). | |||
With [18.0.0+] data is written directly to the outbuf instead of the stack tmpbuf. | |||
| audio-sysmodule infoleak, which allows defeating ASLR. | |||
| [[18.0.0]] | |||
| [[18.0.0]] | |||
| December 24, 2022 | |||
| March 26, 2024 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[Audio_services|audctl]] GetSystemInformationForDebug infoleak / buffer overflow | |||
| audctl GetSystemInformationForDebug calls a func with a 0x1000-byte stack tmpbuf, then afterwards that buffer is memcpy'd into the cmd outbuf. This called func doesn't clear the buffer. This func eventually uses [[BTM_services|btm]] cmd75 with outarray={global ptr} and count=10. Then if the outcount is s32 >=1, it loops through the output using the outcount, without validating it besides the <1 check. Data from that outarray is copied into the array in the func output buffer (tmpbuf above). | |||
With btm comprimised, one could return a large output count and trigger a stack buffer overflow with data following that global array, however exploiting this would be difficult since that data would be uncontrolled (can't directly control it from this cmd at least). | |||
A stack infoleak can be obtained with this as well (assuming the above output array isn't full). | |||
Even though the name has "ForDebug", there's no checks which would trigger an error / return early (this also always returns 0). | |||
[18.0.0+] now clears the output buffer, and also now prints strings into the buffer instead of writing binary data (overflow no longer possible). | |||
| audio-sysmodule infoleak, which allows defeating ASLR. Also audio-sysmodule memory corruption, likely not useful unless there's a way to control the data. | |||
| [[18.0.0]] | |||
| [[18.0.0]] | |||
| December 7, 2022 | |||
| March 27, 2024 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[Migration_services|migration]] nn::migration::savedata::IServer cmd1 buffer overflow | |||
| nn::migration::savedata::IServer cmd1 with [18.0.0-18.0.1] copies data from an array to the output ptr. As the output is an u64 field for the IPC cmd output, this is a field on stack. Hence, if more than 1 entry (8-bytes) are copied a stack buffer overflow will occur. Note that cmd3 loads the same data, except this has a proper output array. | |||
It's unknown whether there's a way to actually control this data with a large enough enough size. | |||
See [[18.1.0]] for the diff/fix. | |||
| [[Migration_services|migration]] stack buffer overflow, only on [18.0.0-18.0.1]. | |||
| [[18.1.0]] | |||
| [[18.1.0]] | |||
| June 11, 2024 | |||
| June 11, 2024 | |||
| [[User:Yellows8|yellows8]] (sysupdate diff) | |||
|- | |||
| [[SSL_services|ssl]] broken RNG | |||
| [[SSL_services|ssl]] uses nn::os::GenerateRandomBytes, but not [[SPL_services|spl]] GenerateRandomBytes. See the RNG entries elsewhere. This is used to seed the NSS global RNG (drbg.c, RNG_GenerateGlobalRandomBytes etc). | |||
If one could somehow determine the data which was returned by nn::os::GenerateRandomBytes during seeding (which is likely difficult), the global RNG would be broken. | |||
With [19.0.0+] nn::os::GenerateRandomBytes usage was replaced with [[SPL_services|spl]] GenerateRandomBytes. | |||
| Breaking [[SSL_services|ssl]] global RNG -> potentially predict RNG data (keys(?)) during TLS comms. | |||
| [[19.0.0]] | |||
| [[19.0.0]] | |||
| December 14, 2021 | |||
| October 8, 2024 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[Audio_services|audren]] uncleared TransferMemory | |||
| audren OpenAudioRenderer uses the input tmem as workmem. The IAudioRenderer dtor doesn't clear the workmem properly. Depending on input params, certain objects stored here have vtables - hence infoleak. | |||
The exact location in the workmem will vary depending on the input params - these objects are dynamically allocated in the workmem. | |||
The following will leak vtables: Sink, Effect. | |||
If the initialization func fails, the tmem is unmapped without clearing it first. It's unknown whether there's a way to actually trigger an infoleak with this however. With [19.0.0+] it's now cleared on failure. | |||
With [19.0.0+] the dtor now clears the workmem when needed. | |||
| Reading leaked data/ptrs from TransferMemory -> defeating ASLR in [[Audio_services|audio]]-sysmodule. | |||
| [[19.0.0]] | |||
| [[19.0.0]] | |||
| December 17, 2022 | |||
| October 13, 2024 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[Audio_services|audren]] UpdateMixes OOB mem-copy | |||
| With nn::audio::server::InfoUpdater::UpdateMixes when nn::audio::server::BehaviorInfo::IsMixInParameterDirtyOnlyUpdateSupported() returns true (requires REV7, which is [7.0.0+]), the mix_id from user input is used without validation as input to <code><nn::audio::server::MixContext::GetInfo(int) const></code>, instead of the counter from the for-loop. This allows one to control the destination MixInfo index which the user-input data is written into. If too large, this will trigger OOB data-copy. Note that the u8 at dest_MixInfo+12 must be non-zero. | |||
Also note that a field is loaded from dest_MixInfo which is used as a splitter_id, so splitters need to be initialized where count is large enough for that id. | |||
With [19.0.0+] after getting the mix_id (loop-index/input) it now does: <code>if (mix_id < 0 || mix_id >= nn::audio::server::MixContext::GetCount()) continue;</code> | |||
| OOB mem-copy in [[Audio_services|audio]]-sysmodule, which for example can be used to overwrite a vtable used immediately after UpdateMixes. | |||
| [[19.0.0]] | |||
| [[19.0.0]] | |||
| December 19, 2022 | |||
| October 13, 2024 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[Bus_services|sasbus]] StartPeriodicReceiveMode infoleak | |||
| StartPeriodicReceiveMode writes a vtable ptr into the mapped tmem at +0. The tmem is mapped RW in the user-process. There is no clearing of tmem during tmem cleanup. Hence, the user-process can read the tmem to obtain a Bus-sysmodule codebin-region infoleak. This vtable-ptr seems to be unused - it's also empty after the first two entries (stubbed incref/decref). | |||
[20.0.0+] Removed the vtable ptr, with data intended for the user-process being moved from tmem+0x8 to +0x0. Also, instead of calling memset, funcs are called for manually clearing tmem. | |||
| Bus-sysmodule infoleak, which allows defeating ASLR. | |||
| [[20.0.0]] | |||
| [[20.0.0]] | |||
| February 22, 2022 | |||
| May 3, 2025 | |||
| [[User:Yellows8|yellows8]] | |||
|- | |||
| [[NFC_services|nfc]] SendCommandByPassThrough buffer overflow | |||
| SendCommandByPassThrough eventually copies the input buffer into a fixed-size heap buffer, without size validation. | |||
This was fixed with [20.0.0+] by clamping the size. | |||
| nfc-sysmodule heap buffer overflow. | |||
| [[20.0.0]] | |||
| [[20.0.0]] | |||
| Late November 2021 | |||
| May 3, 2025 | |||
| [[User:Yellows8|yellows8]] (maybe others?) | |||
|- | |||
| [[HID_services|hidbus]] EnableJoyPollingReceiveMode infoleak | |||
| The tmem initialized by hidbus EnableJoyPollingReceiveMode contains a vtable ptr (tmem+0x10), hence infoleak. With [20.0.0+] the vtable ptr write was removed, and tmem is now memset starting at tmem+0x10 instead of +0x20. | |||
| hid-sysmodule infoleak, which allows defeating ASLR. | |||
| [[20.0.0]] | |||
| [[20.0.0]] | |||
| March 2020 | |||
| May 4, 2025 | |||
| [[User:Yellows8|yellows8]] | | [[User:Yellows8|yellows8]] | ||
|} | |} | ||
Line 1,022: | Line 1,165: | ||
| | | | ||
| Everyone | | Everyone | ||
|- | |||
| Web-applets OpenSSL broken RNG | |||
| [[SPL_services|csrng]] access was added to web-applets with [12.1.0+]. Prior to that, csrng and nn::os::GenerateRandomBytes were not used (besides sdk heap code). | |||
nn::os::GetSystemTick is used to seed the OpenSSL RNG, among other data. Hence, it's probably (?) possible to bruteforce the RNG initial state, allowing predicting RNG output. | |||
The RNG code is wkcRandomNumbersPeer (peer_wkc nro), with the initialization code using GetSystemTick located in the func immediately before wkcGetTickCountPeer. The former is called from wkcOsslRandFilefReadPeer. wkcOsslRandFilefReadPeer is called for seeding the OpenSSL RNG. | |||
With [12.1.0+], wkcRandomNumberPeer/wkcRandomNumbersPeer wrap nn::os::GenerateRandomBytes. wkcCryptographicallyRandomValuesPeer was added which wraps nn::crypto::GenerateCryptographicallyRandomBytes. wkcOsslRandFilefReadPeer now calls nn::crypto::GenerateCryptographicallyRandomBytes instead of wkcRandomNumbersPeer. | |||
| Breaking web-applets OpenSSL RNG -> potentially predict RNG data (keys(?)) during TLS comms. | |||
| [[12.1.0]] | |||
| [[12.1.0]] | |||
| January 28, 2022 | |||
| October 8, 2024 | |||
| [[User:Yellows8|yellows8]], likely (?) others | |||
|} | |} | ||