Switch System Flaws
Jump to navigation
Jump to search
System Flaws are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of known and public Switch System Flaws.
List of Switch System Flaws
Hardware
Summary | Description | Fixed with hardware model/revision | Newest hardware model/revision this flaw was checked for | Timeframe this was discovered | Public disclosure timeframe | Discovered by |
---|---|---|---|---|---|---|
GMMU DMA attack | The Switch's GPU includes a separate MMU (GMMU) that is allowed to bypass the system's IOMMU (SMMU). By accessing the GPU's MMIO region and manipulating the page table entires in the GMMU an attacker can read/write any portion of the DRAM except memory carveouts. | None | 4.1.0 | Summer 2017 | December 28, 2017 | hexkyz, SciresM and qlutoo |
System software
Stage 1 Bootloader
Summary | Description | Successful exploitation result | Fixed in system version | Last system version this flaw was checked for | Timeframe this was discovered | Public disclosure timeframe | Discovered by |
---|---|---|---|---|---|---|---|
Null-dereference in panic() | The Switch's stage 1 bootloader, on panic(), clears the stack and then attempts to clear the Security Engine. However, it does so by dereferencing a pointer to the SE in .bss (initially NULL), and this pointer doesn't get initialized until partway into the bootloader's main() after several functions that might panic() are called. Thus, a panic() caused prior to SE initialization would result in the SE pointer still being NULL when dereferenced. This would cause a data abort, causing the bootloader to clear the stack and then try to clear the security engine...dereferencing NULL again, over and over in a loop.
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic(). |
Infinite clear-the-stack-then-data-abort loop very early in boot, before SBK/other keyslots are cleared. Probably useless for anything more interesting. | 3.0.0 | 3.0.0 | Early July, 2017 | July 30, 2017 | Everyone who diff'd 2.3.0 and 3.0.0 Package1 |
TrustZone
Summary | Description | Successful exploitation result | Fixed in system version | Last system version this flaw was checked for | Timeframe this was discovered | Public disclosure timeframe | Discovered by |
---|---|---|---|---|---|---|---|
No public ARM TrustZone exploits |
Kernel
Summary | Description | Successful exploitation result | Fixed in system version | Last system version this flaw was checked for | Timeframe this was discovered | Public disclosure timeframe | Discovered by |
---|---|---|---|---|---|---|---|
Syscall Infoleaks | Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0. | Nothing really. | Unfixed | 2.0.0 | ? | ||
GetLastThreadInfo UAF | GetLastThreadInfo syscall gets last-scheduled-KThread pointer from KScheduler object. This pointer is not reference counted, and can be pointing to a freed KThread. | Nothing. There is a theoretical race that might leak from a KThread from a different process, but it's impossible to trigger practically. | Unfixed | 15 October | 17 October | plutoo | |
Bad irq_id check in CreateInterruptEvent | CreateInterruptEvent syscall is designed to work only for irq_id >= 32. All irq_ids < 32 are "per-core" and reserved for kernel use (watchdog/scheduling/core communications).
On 1.0.0 you could supply irq_id < 32 and it would write outside the SharedIrqs table. |
You can register irq's in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless. | 2.0.0 | 2.0.0 | ~October | 17 October | qlutoo |
FIRM-package System Modules
Summary | Description | Successful exploitation result | Fixed in system version | Last system version this flaw was checked for | Timeframe this was discovered | Public disclosure timeframe | Discovered by |
---|---|---|---|---|---|---|---|
Service access control bypass (sm:h, smhax, probably other names) | Prior to 3.0.1, the service manager (sm) built-in system module treats a user as though it has full permissions if the user creates a new "sm:" port session but bypasses initialization. This is due to the other sm commands skipping the service ACL check for Pids <= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.
In 3.0.1, sm returns error code 0x415 if Initialize has not been called yet. |
Acquiring, registering, and unregistering arbitrary services | 3.0.1 | 3.0.1 | May 2017 | August 17, 2017 | Everyone |
Overly permissive SPL service | The concept behind the switch's Secure Monitor is that all cryptographic keydata is located in userspace, but stored as "access keys" encrypted with "keks" that never leave TrustZone. The spl ("security processor liaison"?) service serves as an interface between the rest of the system and the secure monitor. Prior to 4.0.0, spl exposed only a single service "spl:", which provided all TrustZone wrapper functions to all sysmodules with access to it. Thus anyone with access to the spl: service (via smhax or by pwning a sysmodule with access) could do crypto with any access keys they knew.
This was fixed in 4.0.0 by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs. |
Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module's access keys to decrypt their console's SSL certificate private key without having to pwn the SSL sysmodule. | 4.0.0 | 4.0.0 | Summer 2017 (after smhax was discovered). | December 23, 2017 | Everyone |
System Modules
Summary | Description | Successful exploitation result | Fixed in system version | Last system version this flaw was checked for | Timeframe this was discovered | Public disclosure timeframe | Discovered by |
---|---|---|---|---|---|---|---|
Out-of-bounds array read for BCAT_Content_Container secret-data index | The BCAT_Content_Container secret-data index is not validated at all. This is handled before the RSA-signature(?) is ever used. Since the field is an u8, a total of 0x800-bytes relative to the array start can be accessed.
This is not useful since the string loaded from this array is only involved with key-generation. |
Unknown | 2.0.0 | August 4, 2017 | August 6, 2017 | Shiny Quagsire, Yellows8 (independently) | |
OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names) | Prior to 3.0.0, pl:u (Shared Font services implemented in the NS sysmodule) service commands 1,2,3 took in a signed 32-bit index and returned that index of an array but did not check that index at all. This allowed for an arbitrary read within a 34-bit range (33-bit signed) from NS .bss. In 3.0.0, sending out of range indexes causes error code 0x60A to be returned. | Dumping full NS .text, .rodata and .data, infoleak, etc | 3.0.0 | 3.0.0 | April 2017 | On exploit's fix in 3.0.0 | qlutoo, Reswitched team (independently) |
Unchecked domain ID in common IPC code | Prior to 2.0.0, object IDs in domain messages are not bounds checked. This out-of-bounds read could be exploited to brute-force ASLR and get PC control in some services that support domain messages. | 2.0.0 | 2.0.0 | ~July 2017 | 20 July 2017 | hthh |