Changes

Line 1: Line 1: −
Exploits are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of publicly known Switch system flaws.
+
This page is a list of publicly known Switch flaws.
    
= Hardware =
 
= Hardware =
Line 445: Line 445:  
| February 2019
 
| February 2019
 
| [[User:TuxSH|TuxSH]]
 
| [[User:TuxSH|TuxSH]]
 +
|-
 +
| Kernel RWX identity mapping never unmapped
 +
| During init, the kernel binary is identity-mapped as RWX at 0x80060000; this is necessary to facilitate the transitionary period while the MMU is being enabled but mappings for e.g. KASLR are not yet determined, and also to enable smooth MMU enable transition during wake-from-sleep.
 +
 +
However, the identity mapping was never unmapped, and thus the whole kernel code bin remained permanently mapped as RWX for all kernel threads (any thread which does not have an owner process and thus uses the KSupervisorPageTable TTBR0).
 +
 +
Thus, any theoretical exploit which would give kernel memory corruption or ROP under a kernel thread would allow making use of this mapping to modify kernel text + bypass KASLR.
 +
 +
This was fixed in [[16.0.0]] by unmapping the identity-mapping during init, and re identity-mapping only the very first page of kernel .text as R-X (for use by wake-from-sleep), which fixes the shellcode problem and mostly fixes the ROP problem, since this page mostly lacks interesting gadgets.
 +
| In theory, with another exploitable kernel memory corruption (or ROP under kernel thread) bug: bypassing KASLR + modifying kernel .text.
 +
 +
However, no such bugs are known.
 +
| [[16.0.0]]
 +
| [[16.0.0]]
 +
| Summer 2018
 +
| February 2023
 +
| Everyone
 
|}
 
|}
   −
== FIRM-package System Modules ==
+
== 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 894: Line 911:  
| November 9, 2022
 
| November 9, 2022
 
| [[User:Hexkyz|hexkyz]]
 
| [[User:Hexkyz|hexkyz]]
 +
|-
 +
| [[Bluetooth_Driver_services|bluetooth]] WriteGattCharacteristic/WriteGattDescriptor stack buffer overflow regression
 +
| Originally btdrv WriteGattCharacteristic/WriteGattDescriptor (bt service LeClientWriteCharacteristic/LeClientWriteDescriptor are the same) validated the input buffer size. However the size check was removed with [12.0.0+] (which was also when bluetooth was refactored), hence stack buffer overflow. Anything with btdrv/bt services access can trigger it. While this is intended to require a BLE connection, it seems to be possible to trigger the buffer overflow without any BLE connection by passing ConnectionHandle=0xFFFFFFFF (handle not tested on hardware).
 +
| Bluetooth-sysmodule stack buffer overflow on [12.0.0-15.0.1], with data from BLE IPC cmds.
 +
| [[16.0.0]]
 +
| [[16.0.0]]
 +
| December 10, 2021
 +
| February 23, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[JIT_services|JIT]] usability issues
 +
| CreateJitEnvironment will enter infinite-loops using nn::jitsrv::detail::AslrAllocator::GetAslrRegion when either of the input CodeMemory sizes are zero. Also the second CodeMemory is useless for the user-process since the second addr returned by GetCodeAddress is a dup of the first one, set during state init by CreateJitEnvironment.
 +
With [14.0.0+] size=0 is now properly handled, and also the state for the second addr from GetCodeAddress is now properly initialized.
 +
| Minor usability issues, not useful for exploitation (size=0 will cause jit-sysmodule to hang in a loop).
 +
| [[14.0.0]]
 +
| [[14.0.0]]
 +
| October 1, 2020
 +
| February 26, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[USB_services|usbhs]] uninitialized IClientEpSession
 +
| usbhs IClientIfSession OpenUsbEp creates an IClientEpSession object. The allocated object from ExpHeap is not memset, only select fields are cleared. The rest of initialization is done by PopulateRing - however the user-process could skip using that if wanted (official sw always uses it).
 +
 +
ShareReportRing maps tmem and writes the ring buffer/count field into object state. PopulateRing also eventually initializes these fields, with the buffer being allocated from ExpHeap instead of tmem. These fields are not cleared during object creation from OpenUsbEp.
 +
 +
GetXferReport after validating the cmd input, just uses object state assuming it was initialized. This runs code which is the same as the user-process code handling the tmem ringbuf.
 +
 +
Therefore, by skipping using PopulateRing and then using GetXferReport the sysmodule will use an uninitialized ringbuf ptr, and an uninitialized count field. If one could control these fields by doing ExpHeap allocations prior to OpenUsbEp so that {target fields} would be located at {IClientEpSession ring fields}, then one could read usb-sysmodule memory at the target buffer address.
 +
 +
See [[USB_services#ShareReportRing|here]] for ringbuf format. The sysmodule will Abort if read_index is >= {ring count field from object state}. Otherwise it copies an entry from that index to output, and updates read_index.
 +
 +
This is probably tricky to abuse as the ringbuf ptr has to be valid, and {see above} (likewise for write_index when the report-ringbuf-writing func runs).
 +
 +
PostBufferAsync/BatchBufferAsync also use seperate object ring fields which are left uninitialized from OpenUsbEp. Targeting this would be tricky with the ring restrictions - this would allow writing data to a ring addr however.
 +
 +
Pre-4.0.0 (only 2.0.0 checked) is not affected by these. The ring fields in the object are cleared during object creation (no memset of the entire object however). GetXferReport would null-deref if PopulateRing was skipped. PostBufferAsync/BatchBufferAsync will throw an error if PopulateRing was skipped. Pre-4.0.0 also has different ring handling as well.
 +
 +
[16.0.0+] The IClientEpSession init func now clears the remaining previously uninitialized fields. The cmds using the ring fields still don't check for NULL, so using GetXferReport/PostBufferAsync/BatchBufferAsync without PopulateRing will just trigger null-deref. Even if the ptr were somehow valid but ring-count field was left at 0, this would then Abort due to: <code>if (ring_count <= index_loaded_from_ringptr) <Abort></code>
 +
| [4.0.0-15.0.1] If one can trigger using {target values} as the unintialized fields: memory reads from the target addr with GetXferReport, and memory R/W with PostBufferAsync/BatchBufferAsync. This requires access to usb:hs, and an usb device must be connected which is not being used by {other sessions}. If successful, this might (?) result in usb-sysmodule compromise.
 +
| [[16.0.0]]
 +
| [[16.0.0]]
 +
| January 30, 2023
 +
| February 26, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[NS_services|ns]] RequestMoveApplicationEntity/EstimateSizeToMove buffer overflow
 +
| ns RequestMoveApplicationEntity eventually calls a func which: Loops through the input buffer. If any entry has value 6, it will call another func to copy data from state to output safely (uses the max_count param). Otherwise, it copies the input buffer to an outbuf (located on caller's stack) without any size validation (inlined memcpy), even though there is a max_count param.
 +
 +
Additional memwrites are also done to the above outbuf following the initial memcopy. This can be avoided if the buffer doesn't contain bytes with values 3-6 (if using values in that range is really needed, the cmd input StorageId param can be set to the required value so that the specified value doesn't trigger the memwrite). Value 6 shouldn't be used anyway (see above).
 +
 +
ns EstimateSizeToMove first calls the same func which does the copy above (outbuf is also located on stack), then it calls another func. Hence, same vuln here.
 +
 +
By corrupting just the first byte of x29 with EstimateSizeToMove, one can obtain infoleaks. This method with x29 essentially only works with [15.0.0+]. Pre-15.0.0 would require a different method with partial overwrite of retaddr, however it's unknown whether this would actually work for infoleak (would require [12.0.0+] for the stack layout change).
 +
With EstimateSizeToMove where x29 is overwritten, the output u64 is the leaked ptr (can be codebin-region). Note that the cmd has to return Result=0 for this to work. x29 is used to load the value which is copied to the cmdreply rawdata.
 +
 +
As of [17.0.0+] an error is thrown if the input array count is larger than 8 (size of the stack dst-array).
 +
| ns-sysmodule stack buffer overflow, allowing ns infoleak+ROP.
 +
| [[17.0.0]]
 +
| [[17.0.0]]
 +
| January 2, 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]]
 
|}
 
|}