<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://switchbrew.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rei</id>
	<title>Nintendo Switch Brew - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://switchbrew.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rei"/>
	<link rel="alternate" type="text/html" href="https://switchbrew.org/wiki/Special:Contributions/Rei"/>
	<updated>2026-04-07T15:52:01Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6934</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6934"/>
		<updated>2019-05-21T19:05:32Z</updated>

		<summary type="html">&lt;p&gt;Rei: only being fair&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Exploits are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of publicly known Switch system flaws.&lt;br /&gt;
&lt;br /&gt;
For userland applications/applets flaws see [[Switch_Userland_Flaws|here]]. &lt;br /&gt;
&lt;br /&gt;
= System flaws =&lt;br /&gt;
== Hardware == &lt;br /&gt;
Flaws in this category pertain to the underlying hardware that powers the Switch.&lt;br /&gt;
&lt;br /&gt;
This includes components shared across Tegra based devices such as the [[TSEC]], the [[Security_Engine|Security Engine]], the [[GPU]] and so on.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| CVE-2018-6242 (leveraged by the ShofEL2 and Fusée Gelée exploits)&lt;br /&gt;
| The USB software stack provided inside the boot instruction rom (IROM/bootROM) contains a copy operation whose length can be controlled by an attacker. By carefully constructing a USB control request, an attacker can leverage this vulnerability to copy the contents of an attacker-controlled buffer over the active execution stack, gaining control of the Boot and Power Management processor (BPMP) before any lock-outs or privilege reductions occur. This execution can then be used to exfiltrate secrets and to load arbitrary code onto the main CPU Complex (CCPLEX) &amp;quot;application processors&amp;quot; at the highest possible level of privilege (typically as the TrustZone Secure Monitor at PL3/EL3).&lt;br /&gt;
| Unknown (Tegra186 and Tegra214)&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| January 2018&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| [[User:Shuffle2|shuffle2]] and fail0verflow (originally),&amp;lt;br&amp;gt; [[User:Ktemkin|ktemkin]] and ReSwitched Team (independently),&amp;lt;br&amp;gt; [[User:Naehrwert|naehrwert]] (independently),&amp;lt;br&amp;gt; [[User:Hexkyz|hexkyz]] (independently),&amp;lt;br&amp;gt; st4rk with [[User:Shinyquagsire23|Shiny Quagsire]] and Dazzozo (independently),&amp;lt;br&amp;gt; and many others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
&lt;br /&gt;
[5.0.0+] Works around this hardware flaw by using memory pool partitioning. You can no longer escalate into sysmodules with GPU DMA because all their memory is allocated using heap that&#039;s carved out.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
&lt;br /&gt;
This also bypasses the SBK protection of the bootROM: indeed, at warmboot, bootROM will always clear keyslot 0xE to prevent malicious code from saving the SBK. Moving the SBK to another keyslot in the saved context renders this protection moot.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
| Security Engine keyslots vulnerable to partial overwrite attack&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 security engine supports writing keyslot data to the engine with syntax as follows: &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_ADDR = (keyslot &amp;lt;&amp;lt; 4) | (dword_index_in_keyslot); &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_DATA = readle32(key, dword_index_in_keyslot * 4); &lt;br /&gt;
&lt;br /&gt;
However, the Security Engine flushes writes to the internal key tables immediately when AES_KEYTABLE_DATA is written -- this allows one to overwrite a single dword of a key at a time, and thus brute force the contents of keyslots in time (2^32 * 8) = 2^35 instead of 2^256.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Theorized Summer 2017 due to suggestive syntax, confirmed April 9, 2018&lt;br /&gt;
| April 9, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], almost surely others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| Poor validation of bootrom SDRAM configuration parameters leads to arbitrary writes in bootrom&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 bootrom supports saving SDRAM parameters to scratch registers, and using the saved configuration to enable DRAM during warmboot.&lt;br /&gt;
&lt;br /&gt;
The code that parses these parameters does if (params-&amp;gt;EmcBctSpareN) *params-&amp;gt;EmcBctSpareN = params-&amp;gt;EmcBctSpareNPlusOne for most N, without validating either the address or value written to it.&lt;br /&gt;
There are other arbitrary writes in this code, as well (e.g. BootromPatch parameters intended for patching MISC registers do not check a relative offset to 0x7000000, etc).&lt;br /&gt;
&lt;br /&gt;
This allows a user with access to the PMC registers (via pre-sleep bpmp execution, or otherwise) to gain arbitrary bootrom code execution.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| 2017&lt;br /&gt;
| December 16, 2018&lt;br /&gt;
| Everyone (independently).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Bootloader ===&lt;br /&gt;
Flaws in this category pertain to any bootloader component such as the [[Package1#Package1ldr|package1ldr]], the [[Package1#Section_1|NX bootloader]] or the [[Package1#Section_0|warmboot binary]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;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&#039;t get initialized until partway into the bootloader&#039;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. &lt;br /&gt;
The BPMP doesn&#039;t have an active MPU and the bus won&#039;t data abort on an invalid address, so no exception will be entered: it&#039;ll end up overwriting some exception vectors with NULL before halting.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Some exception vectors overwritten with NULL, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  maconstack (TSEC firmware leaves MAC on the stack)&lt;br /&gt;
|  Package1ldr loads a firmware blob into TSEC early on boot. This piece of code runs on the TSEC in Authenticated Mode and has the sole purpose of generating the per-console TSEC key (see [[Cryptosystem]]).&lt;br /&gt;
&lt;br /&gt;
As a way to mitigate attacks, the TSEC firmware blob is split into 3 stages: [[TSEC_Firmware#Boot|Boot]] which is unencrypted and unsigned, [[TSEC_Firmware#KeygenLdr|KeygenLdr]] which is unencrypted but signed and [[TSEC_Firmware#Keygen|Keygen]] which is encrypted and signed.&lt;br /&gt;
Boot loads a static pre-generated signature into the Falcon&#039;s CPU crypto registers, loads KeygenLdr into the Falcon&#039;s CODE region and jumps to it. Execution will proceed into KeygenLdr in Heavy Secure Mode if, and only if, the loaded signature matches the one Falcon calculates internally for KeygenLdr.&lt;br /&gt;
&lt;br /&gt;
Among various things, KeygenLdr will attempt to do a &amp;quot;backwards&amp;quot; security check by calculating a CMAC over Boot and comparing it with a known hash stored in the TSEC firmware&#039;s key data (a small buffer stored after Boot&#039;s code). If the hashes don&#039;t match, execution aborts.&lt;br /&gt;
&lt;br /&gt;
KeygenLdr stores the calculated Boot&#039;s CMAC in the stack, but forgets to clear it. Since the stack is located in Falcon&#039;s DATA region, loading the TSEC firmware blob and dumping the DATA region afterwards (via MMIO) will reveal the calculated hash.&lt;br /&gt;
This allows using KeygenLdr as an oracle to generate a valid CMAC for arbitrary Boot code. Replacing the CMAC in the TSEC firmware&#039;s key data region results in KeygenLdr accepting any Boot code, thus rendering this security measure useless.&lt;br /&gt;
&lt;br /&gt;
Additionally, since signed Falcon code can&#039;t be revoked without an hardware revision, an attacker can always reuse the flawed KeygenLdr code even if a fix is issued.&lt;br /&gt;
|  Running TSEC firmware&#039;s KeygenLdr in a user controlled environment.&lt;br /&gt;
|  None&lt;br /&gt;
|  [[5.0.2]]&lt;br /&gt;
|  January 2018&lt;br /&gt;
|  April 29, 2018&lt;br /&gt;
|  Everyone  (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  Stack smash in TSEC firmware&#039;s KeygenLdr&lt;br /&gt;
|  Given that we can control the [[TSEC_Firmware#Key_data|key data]] (which is not authenticated) and the [[TSEC_Firmware#Boot|Boot]] blob (see &amp;quot;maconstack&amp;quot;), as well as the fact Non-secure and Heavy Secure code share the same stack, we can use this to attack KeygenLdr. KeygenLdr uses memcpy to copy over a payload to DMEM to verify it, which can be abused to smash the stack (in DMEM) and write over the return address of said function.&lt;br /&gt;
|  ROP under KeygenLdr in Heavy Secure mode.&lt;br /&gt;
|  None&lt;br /&gt;
|  [[8.0.1]]&lt;br /&gt;
|  Early 2018&lt;br /&gt;
|  May 21, 2019&lt;br /&gt;
|  Everyone (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  pk1ldrhax&lt;br /&gt;
|  Package1ldr decrypts and verifies the keyblob inside of the current BCT in order to get the package1 key, and then uses the package1 key to decrypt package1. It then validates package1 before jumping to it by checking the PK11 magic number, and that the section sizes sum to the expected size (and are individually less than the expected size). &lt;br /&gt;
&lt;br /&gt;
However, package1ldr does not actually validate the package1 key against a fixed vector (much like kernel9loader forgot to do so on the 3ds). This would normally not matter, as keyblobs are validated -- however, with bootrom code execution one can dump SBK and forge keyblobs, and thus control the package1 key. &lt;br /&gt;
&lt;br /&gt;
Thus (&#039;&#039;&#039;in theory, but not in practice due to the size of the brute force required&#039;&#039;&#039;) one can replace the package1 key with garbage, causing package1 to decrypt into garbage, and hope that this garbage passes validation checks and that package1ldr jumping into the garbage will do something useful.&lt;br /&gt;
&lt;br /&gt;
This was fixed incidentally in [[6.2.0]], as pk1ldr does not use keyblob data to decrypt package1 any more.&lt;br /&gt;
&lt;br /&gt;
|  With a large enough brute force: arbitrary package1 code execution from coldboot.&lt;br /&gt;
&lt;br /&gt;
However, a usable brute force is on the order of &amp;gt;= ~2^80, so &#039;&#039;&#039;this is almost certainly not actually usable in any meaningful context&#039;&#039;&#039;.&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  Early 2017 (as soon as plaintext package1ldr was first dumped)&lt;br /&gt;
|  November 20, 2018&lt;br /&gt;
|  Everyone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package1#Section_2|Secure Monitor]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  Missed BPMP Exception Vector Writes&lt;br /&gt;
|  Starting in [[2.0.0]], the BPMP is asleep at runtime, and is turned on by TrustZone during [[SMC|smcCpuSuspend]] in order to initiate the deep sleep process. When it does so, it is held in RESET, and TrustZone attempts to write to the BPMP exception vectors at 0x6000F200 to register EVP_RESET = lp0_entry_fw_crt0, and all other EVPs to a function that simply reboots. However, while they successfully write EVP_RESET, they miss all the other vectors, accidentally writing to the 0x6000F004-0x6000F020 region instead of the 0x6000F204-0x6000F220 region they want to write to. This results in all the exception vectors for the BPMP other than RESET being &amp;quot;undefined&amp;quot; (attacker controlled).&lt;br /&gt;
&lt;br /&gt;
With some way of causing an exception vector to be taken at the right time, this would give pre-sleep code execution (and thus arbitrary TrustZone code execution, via the security engine flaw). However, none of the abort vectors are really triggerable, and interrupts are disabled for the BPMP when it is taken out of reset. Thus, this is useless in practice.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by writing to the correct registers.&lt;br /&gt;
|  Theoretically: Arbitrary TrustZone code execution. In practice: Useless.&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  January, 2018&lt;br /&gt;
|  February 23, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]], [[User:Naehrwert|naehrwert]], [[User:Hexkyz|hexkyz]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  TSEC has access to the secure kernel carveout &lt;br /&gt;
|  TrustZone is responsible for managing security carveouts to prevent DMA controllers from accessing the carveout which contains the kernel, sysmodules, and other critical operating system data.&lt;br /&gt;
&lt;br /&gt;
Until [[8.0.0]], the list of devices that could access the carveout included the TSEC. However, the TSEC can bypass the SMMU when in authenticated mode by writing to a certain register. Thus, pwning nvservices would allow one to take over the TSEC, and use it to write to normally protected mmio/memory.&lt;br /&gt;
&lt;br /&gt;
In [[8.0.0]], this was fixed by removing TSEC access, and adding TSECB access (TSECB cannot bypass the SMMU).&lt;br /&gt;
| With access to the TSEC mmio (nvservices ROP) and code execution in TSEC Heavy Secure mode, kernel code execution, probably.&lt;br /&gt;
| [[8.0.0]]&lt;br /&gt;
| [[8.0.0]]&lt;br /&gt;
| 2017 (when TrustZone code plaintext was first obtained).&lt;br /&gt;
| April 15, 2019&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|  deja vu (insufficient system state validation on suspend leads to pre-sleep BPMP code execution)&lt;br /&gt;
|  Jamais Vu was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry, since gaining pre-sleep code execution on the BPMP compromises the system.&lt;br /&gt;
&lt;br /&gt;
However, the state validation performed by Nintendo&#039;s Secure Monitor was insufficient to prevent pre-sleep execution from being obtained.&lt;br /&gt;
&lt;br /&gt;
Prior to [[6.0.0]], one could use a DMA controller that had access to IRAM and was not held in reset (there were multiple) to race TrustZone&#039;s writes to the BPMP firmware in IRAM, and thus overwrite Nintendo&#039;s firmware with an attacker&#039;s to gain pre-sleep code execution.&lt;br /&gt;
&lt;br /&gt;
[[6.0.0]] addressed this by performing TrustZone state MAC writes and locking PMC scratch *before* turning on the BPMP, fixing the original Jamais Vu exploit entirely. In addition, the BPMP firmware in TrustZone&#039;s .rodata is now memcmp&#039;d to the actual data after it is written to IRAM. This mitigates race attacks that modify the firmware.&lt;br /&gt;
&lt;br /&gt;
However, Nintendo both forgot to validate the BPMP exception vectors after writing them, and forgot to hold in reset a DMA controller that can write to the BPMP&#039;s exception vectors.&lt;br /&gt;
&lt;br /&gt;
AHB-DMA is not blacklisted by kernel mapping whitelist (Nintendo probably forgot it, because the TX1 TRM does not really document that it&#039;s present, although the MMIO works as documented in older (Tegra 3 and before) TRMs).&lt;br /&gt;
&lt;br /&gt;
Thus, with kernel code execution (or some other way of accessing AHB-DMA, e.g. nspwn on &amp;lt;= 4.1.0, TSEC hax, or other arbitrary mmio access flaws), one can DMA to the BPMP&#039;s exception vectors as they are written, causing TrustZone to start the BPMP executing an attacker&#039;s firmware at a different location than TrustZone intends/validates.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[8.0.0]] by blocking AHB-DMA arbitration and verifying it is held in reset during suspend, and thus there are no more devices that can write to the relevant MMIO at the right time.&lt;br /&gt;
&lt;br /&gt;
|  Arbitrary TrustZone/BootROM code execution, by using either the original Jamais Vu flaw (prior to [[6.0.0]] or a warmboot bootrom exploit (any firmware where pre-sleep execution can be gained).&lt;br /&gt;
|  [[8.0.0]]&lt;br /&gt;
|  [[8.0.0]]&lt;br /&gt;
|  December 2017&lt;br /&gt;
|  April 15, 2019&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]] and ktemkin,  [[User:Naehrwert|naehrwert]] (independently), almost certainly others (independently)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package2#Section_0|HorizonOS Kernel]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| svcWaitSynchronization/svcReplyAndReceive bad cleanup on error&lt;br /&gt;
| If there is a page fault when fetching handles from the userspace array, it cleans up by dereferencing all objects despite having only loaded first N. Allows the attacker to make arbitrary decrefs on any kernel synchronization object, and thus can be used to get UAF. Haven&#039;t actually been tried on real HW though, but should work (tm).&lt;br /&gt;
| Kernel code execution&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| 24 April&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
| Potential [[SVC|svcWaitForAddress]] thread use-after-free&lt;br /&gt;
| Between [[4.0.0]], where svcWaitForAddress was introduced, and [[7.0.0]], there was a second intrusive rbtree node in KThread for the WaitForAddress tree (the key being (address, priority), sorted lexicographically). Unlike the WaitProcessWideKeyAtomic tree, the kernel forgot to reinsert the WaitForAddress node when the thread&#039;s priority changed (priority inheritance and/or SetPriority), breaking the rbtree invariants; and since the kernel walks through the entire tree to remove intrusive nodes, you could cause threads to stay in the tree even after their deletion.&lt;br /&gt;
&lt;br /&gt;
[[7.0.0]] fixed the issue by using the same intrusive node for both trees. The thread/node knows which tree it is in, and the latter is correctly updated when thread priority changes.&lt;br /&gt;
| It unluckily didn&#039;t look exploitable&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| July 2018&lt;br /&gt;
| February 2019&lt;br /&gt;
| [[User:TuxSH|TuxSH]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) 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 &amp;quot;spl:&amp;quot;, 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. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders (like expLDR): dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| nspwn&lt;br /&gt;
| fsp-ldr command 0 &amp;quot;MountCode&amp;quot; takes in a Content Path (retrieved from NCM by Loader), and returns an IFileSystem for the resulting ExeFS. These content paths, are normally NCAs, but MountCode also supports a number of other formats, including &amp;quot;.nsp&amp;quot; -- which is just a PFS0.&lt;br /&gt;
&lt;br /&gt;
When a path ending in &amp;quot;.nsp&amp;quot; is parsed by MountCode, the PFS0 is treated as a raw ExeFS. Because there is no NCA header, the ACID signatures are not validated -- and because there are no other signatures in a PFS0, this results in no signature checking happening at all.&lt;br /&gt;
&lt;br /&gt;
The actual .nsp handling is eventually done by {content mounting function} called by MountCode and other FS commands.&lt;br /&gt;
&lt;br /&gt;
Thus, by placing an ExeFS (NSOs + &amp;quot;main.npdm&amp;quot;) and setting one&#039;s desired title ID to &amp;quot;@Sdcard:/some_title.nsp&amp;quot; or &amp;quot;@User:/some_title.nsp&amp;quot; etc one can launch arbitrary unsigned code, with arbitrary unsigned NPDMs.&lt;br /&gt;
&lt;br /&gt;
This appears to have been fixed by only allowing .nsp when the input fstype==7 for the internal content-mounting function, returning 0x2EE202 otherwise.&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: Arbitrary code execution with full system privileges.&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| Late 2017&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single null-byte stack overflow in Loader ContentPath parsing&lt;br /&gt;
| Previously, loader content path parsing looked like this, where path_from_lr was up to 0x300 bytes and not necessarily null-terminated:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300] = {0};&lt;br /&gt;
  strcat(nca_path, path_from_lr);&lt;br /&gt;
  for (int i = 0; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Thus, a content path of the maximum length (0x300 bytes) would result in strcat writing a NULL terminator past the end of the nca_path buffer.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[6.0.0]], the new code looks like this:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300];&lt;br /&gt;
  strncpy(nca_path, path_from_lr, sizeof(nca_path));&lt;br /&gt;
  for (int i = 0; i  &amp;lt; sizeof(nca_path) &amp;amp;&amp;amp; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: single null-byte stack overflow in Loader. Maybe (but probably not) loader code execution.&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| September 2, 2018&lt;br /&gt;
| September 19, 2018&lt;br /&gt;
| SciresM&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
Flaws in this category pertain to any non-built-in system module.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| 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.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  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.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], ReSwitched Team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|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.&lt;br /&gt;
|&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|-&lt;br /&gt;
| expLDR (sysmodule handle table exhaustion)&lt;br /&gt;
| Most sysmodules share common template code to handle IPC control messages. The command DuplicateSession (type 5 command 2)&#039;s template code will abort() if it fails to duplicate a session&#039;s handle for the requester. Because many sysmodules have limited handle table size (smaller than the browser/other entrypoints), repeatedly requesting to duplicate one&#039;s session will cause the sysmodule to run out of handle table space and abort, causing the service to release all its handles cleanly.&lt;br /&gt;
| Sysmodule crashes.  Most usefully, crashing ldr allows access to fsp-ldr and crashing pm allows access to fsp-pr. Useless after [[4.0.0]], which mitigated a number of single-session service access issues.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| [[4.1.0]]&lt;br /&gt;
| 24 June 2017&lt;br /&gt;
| 8 March 2018&lt;br /&gt;
| [[User:daeken|daeken]]&lt;br /&gt;
|-&lt;br /&gt;
| Transfer Memory leak in nvservices system module&lt;br /&gt;
| The nvservices sysmodule does not clear most of its transfer memory prior to release.&lt;br /&gt;
| The calling process can read key bits of memory, including breaking ASLR (by revealing the image base) and exposing the address of other transfer memory to set up attacks. More details here: [https://daeken.svbtle.com/nintendo-switch-nvservices-info-leak transfermeme (nvservices info leak)] by [[User:daeken|daeken]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| June 2017&lt;br /&gt;
| 16 October 2018&lt;br /&gt;
| [[User:qlutoo|qlutoo]] and [[User:hexkyz|hexkyz]],&lt;br /&gt;
[[User:daeken|daeken]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
| OOB write in audio system module&lt;br /&gt;
| Prior to [[2.0.0]], the [[Audio_services#audout:u|AppendAudioOutBuffer]] and [[Audio_services#audin:u|AppendAudioInBuffer]] IPC commands would blindly increment the appended buffers&#039; count while using said count value as an index to where the user data should be copied into. This resulted in an 0x28 bytes, user controlled, out-of-bounds memory write into the [[Audio_services|audio]] sysmodule&#039;s memory space.&lt;br /&gt;
Combined with the [[Audio_services#audout:u|GetReleasedAudioOutBuffer]] or [[Audio_services#audin:u|GetReleasedAudioInBuffer]] commands, this could also be used as an 8 byte infoleak.&lt;br /&gt;
&lt;br /&gt;
In [[2.0.0]], the commands now return error code 0x1099 if the number of unreleased buffers exceeds 0x1F.&lt;br /&gt;
| Code execution under audio sysmodule&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| November 2, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| nvhax (memory corruption in nvservices system module)&lt;br /&gt;
| Prior to [[6.2.0]], the [[NV_services|nvservices]] ioctl [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] would take a single &amp;quot;pwarpstate&amp;quot; argument which would be interpreted by nvservices as a memory pointer for writing 2 &amp;quot;warpstate&amp;quot; structs (one for each Streaming Multiprocessor).&lt;br /&gt;
This resulted in nvservices attempting to blindly memcpy into this user supplied address and trigger a crash. However, if paired with an infoleak, this could be used to arbitrarily write 0x30 bytes anywhere in nvservices&#039; memory space.&lt;br /&gt;
Additionally, the &amp;quot;warpstate&amp;quot; struct itself was never initialized, which means nvservices would leak the 0x30 bytes from the stack. By invoking other ioctls it was also possible to partially control the stack contents and achieve a usable arbitrary memory write primitive.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] now takes 2 inline &amp;quot;warpstate&amp;quot; structs instead of a &amp;quot;pwarpstate&amp;quot; pointer, thus effectively avoiding the bad memcpy.&lt;br /&gt;
| Code execution under nvservices sysmodule&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 5, 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]]&lt;br /&gt;
|-&lt;br /&gt;
| Infoleak in nvservices system module&lt;br /&gt;
| The [[NV_services|nvservices]] ioctl [[NV_services#NVMAP_IOC_ALLOC|NVMAP_IOC_ALLOC]] takes an optional argument &amp;quot;addr&amp;quot; which allows the calling process to pass a pointer to user allocated memory for backing a nvmap object. If &amp;quot;addr&amp;quot; is left as 0, nvservices uses the transfer memory region (donated by the user during initialization) instead, when allocating memory for the nvmap object.&lt;br /&gt;
By design, freeing the nvmap object by calling the ioctl [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] returns, in its &amp;quot;refcount&amp;quot; argument, the user address previously supplied if the reference count reaches 0.&lt;br /&gt;
However, prior to [[6.2.0]], the case where the transfer memory region is used to allocate the nvmap object was not taken into account, thus resulting in [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] leaking back an address from within the transfer memory region mapped in nvservices&#039; memory space.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] no longer returns the address when the transfer memory region is used instead of user supplied memory.&lt;br /&gt;
| Combined with other vulnerabilities: Defeating ASLR in nvservices sysmodule.&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6932</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6932"/>
		<updated>2019-05-21T18:19:13Z</updated>

		<summary type="html">&lt;p&gt;Rei: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Exploits are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of publicly known Switch system flaws.&lt;br /&gt;
&lt;br /&gt;
For userland applications/applets flaws see [[Switch_Userland_Flaws|here]]. &lt;br /&gt;
&lt;br /&gt;
= System flaws =&lt;br /&gt;
== Hardware == &lt;br /&gt;
Flaws in this category pertain to the underlying hardware that powers the Switch.&lt;br /&gt;
&lt;br /&gt;
This includes components shared across Tegra based devices such as the [[TSEC]], the [[Security_Engine|Security Engine]], the [[GPU]] and so on.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| CVE-2018-6242 (leveraged by the ShofEL2 and Fusée Gelée exploits)&lt;br /&gt;
| The USB software stack provided inside the boot instruction rom (IROM/bootROM) contains a copy operation whose length can be controlled by an attacker. By carefully constructing a USB control request, an attacker can leverage this vulnerability to copy the contents of an attacker-controlled buffer over the active execution stack, gaining control of the Boot and Power Management processor (BPMP) before any lock-outs or privilege reductions occur. This execution can then be used to exfiltrate secrets and to load arbitrary code onto the main CPU Complex (CCPLEX) &amp;quot;application processors&amp;quot; at the highest possible level of privilege (typically as the TrustZone Secure Monitor at PL3/EL3).&lt;br /&gt;
| Unknown (Tegra186 and Tegra214)&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| January 2018&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| [[User:Shuffle2|shuffle2]] and fail0verflow (originally),&amp;lt;br&amp;gt; [[User:Ktemkin|ktemkin]] and ReSwitched Team (independently),&amp;lt;br&amp;gt; [[User:Naehrwert|naehrwert]] (independently),&amp;lt;br&amp;gt; [[User:Hexkyz|hexkyz]] (independently),&amp;lt;br&amp;gt; st4rk with [[User:Shinyquagsire23|Shiny Quagsire]] and Dazzozo (independently),&amp;lt;br&amp;gt; and many others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
&lt;br /&gt;
[5.0.0+] Works around this hardware flaw by using memory pool partitioning. You can no longer escalate into sysmodules with GPU DMA because all their memory is allocated using heap that&#039;s carved out.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
&lt;br /&gt;
This also bypasses the SBK protection of the bootROM: indeed, at warmboot, bootROM will always clear keyslot 0xE to prevent malicious code from saving the SBK. Moving the SBK to another keyslot in the saved context renders this protection moot.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
| Security Engine keyslots vulnerable to partial overwrite attack&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 security engine supports writing keyslot data to the engine with syntax as follows: &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_ADDR = (keyslot &amp;lt;&amp;lt; 4) | (dword_index_in_keyslot); &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_DATA = readle32(key, dword_index_in_keyslot * 4); &lt;br /&gt;
&lt;br /&gt;
However, the Security Engine flushes writes to the internal key tables immediately when AES_KEYTABLE_DATA is written -- this allows one to overwrite a single dword of a key at a time, and thus brute force the contents of keyslots in time (2^32 * 8) = 2^35 instead of 2^256.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Theorized Summer 2017 due to suggestive syntax, confirmed April 9, 2018&lt;br /&gt;
| April 9, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], almost surely others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| Poor validation of bootrom SDRAM configuration parameters leads to arbitrary writes in bootrom&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 bootrom supports saving SDRAM parameters to scratch registers, and using the saved configuration to enable DRAM during warmboot.&lt;br /&gt;
&lt;br /&gt;
The code that parses these parameters does if (params-&amp;gt;EmcBctSpareN) *params-&amp;gt;EmcBctSpareN = params-&amp;gt;EmcBctSpareNPlusOne for most N, without validating either the address or value written to it.&lt;br /&gt;
There are other arbitrary writes in this code, as well (e.g. BootromPatch parameters intended for patching MISC registers do not check a relative offset to 0x7000000, etc).&lt;br /&gt;
&lt;br /&gt;
This allows a user with access to the PMC registers (via pre-sleep bpmp execution, or otherwise) to gain arbitrary bootrom code execution.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| 2017&lt;br /&gt;
| December 16, 2018&lt;br /&gt;
| Everyone (independently).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Bootloader ===&lt;br /&gt;
Flaws in this category pertain to any bootloader component such as the [[Package1#Package1ldr|package1ldr]], the [[Package1#Section_1|NX bootloader]] or the [[Package1#Section_0|warmboot binary]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;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&#039;t get initialized until partway into the bootloader&#039;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. &lt;br /&gt;
The BPMP doesn&#039;t have an active MPU and the bus won&#039;t data abort on an invalid address, so no exception will be entered: it&#039;ll end up overwriting some exception vectors with NULL before halting.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Some exception vectors overwritten with NULL, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  TSEC firmware compromises itself&lt;br /&gt;
|  Package1ldr loads a firmware blob into TSEC early on boot. This piece of code runs on the TSEC in Authenticated Mode and has the sole purpose of generating the per-console TSEC key (see [[Cryptosystem]]).&lt;br /&gt;
&lt;br /&gt;
As a way to mitigate attacks, the TSEC firmware blob is split into 3 stages: [[TSEC#Stage_0|Stage 0]] which is unencrypted and unsigned, [[TSEC#Stage_1|Stage 1]] which is unencrypted but signed and [[TSEC#Stage_2|Stage 2]] which is encrypted and signed.&lt;br /&gt;
Stage 0 loads a static pre-generated signature into the Falcon&#039;s CPU crypto registers, loads Stage 1 into the Falcon&#039;s CODE region and jumps to it. Execution will proceed into Stage 1 in Authenticated Mode if, and only if, the loaded signature matches the one Falcon calculates internally for Stage 1.&lt;br /&gt;
&lt;br /&gt;
Among various things, Stage 1 will attempt to do a &amp;quot;backwards&amp;quot; security check by calculating a CMAC over Stage 0 and comparing it with a known hash stored in the TSEC firmware&#039;s key data (a small buffer stored after Stage 0&#039;s code). If the hashes don&#039;t match, execution aborts.&lt;br /&gt;
&lt;br /&gt;
Stage 1 stores the calculated Stage 0&#039;s CMAC in the stack, but forgets to clear it. Since the stack is located in Falcon&#039;s DATA region, loading the TSEC firmware blob and dumping the DATA region afterwards (via MMIO) will reveal the calculated hash.&lt;br /&gt;
This allows using Stage 1 as an oracle to generate a valid CMAC for arbitrary Stage 0 code. Replacing the CMAC in the TSEC firmware&#039;s key data region results in Stage 1 accepting any Stage 0 code, thus rendering this security measure useless.&lt;br /&gt;
&lt;br /&gt;
Additionally, since signed Falcon code can&#039;t be revoked without an hardware revision, an attacker can always reuse the flawed Stage 1 code even if a fix is issued.&lt;br /&gt;
|  Running TSEC firmware&#039;s Stage 1 in a user controlled environment. Mostly useless, but may aid in side-channel attacks.&lt;br /&gt;
|  None&lt;br /&gt;
|  [[5.0.2]]&lt;br /&gt;
|  January 2018&lt;br /&gt;
|  April 29, 2018&lt;br /&gt;
|  [[User:Hexkyz|hexkyz]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  Keygenldr compromise&lt;br /&gt;
|  Given that we can control keyarea data (since its not authenticated) and boot (as mentioned in another exploit), as well as the fact NS and HS code share the same stack, we can use this to attack keygenldr. In keygenldr, theres a function that uses memcpy to copy over a payload to DMEM to verify it. These can be abused to smash the stack (which is also in DMEM) and write over the return addr of said function.&lt;br /&gt;
|  ROP under keygenldr during HS mode.&lt;br /&gt;
|  None&lt;br /&gt;
|  [[8.0.1]]&lt;br /&gt;
|  Spring 2019 (Earlier for some)&lt;br /&gt;
|  Spring 2019&lt;br /&gt;
|  [[User:Rei|Reisyukaku]] and [[User:Govanify|Govanify]]/ [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]].&lt;br /&gt;
|-&lt;br /&gt;
|  pk1ldrhax&lt;br /&gt;
|  Package1ldr decrypts and verifies the keyblob inside of the current BCT in order to get the package1 key, and then uses the package1 key to decrypt package1. It then validates package1 before jumping to it by checking the PK11 magic number, and that the section sizes sum to the expected size (and are individually less than the expected size). &lt;br /&gt;
&lt;br /&gt;
However, package1ldr does not actually validate the package1 key against a fixed vector (much like kernel9loader forgot to do so on the 3ds). This would normally not matter, as keyblobs are validated -- however, with bootrom code execution one can dump SBK and forge keyblobs, and thus control the package1 key. &lt;br /&gt;
&lt;br /&gt;
Thus (&#039;&#039;&#039;in theory, but not in practice due to the size of the brute force required&#039;&#039;&#039;) one can replace the package1 key with garbage, causing package1 to decrypt into garbage, and hope that this garbage passes validation checks and that package1ldr jumping into the garbage will do something useful.&lt;br /&gt;
&lt;br /&gt;
This was fixed incidentally in [[6.2.0]], as pk1ldr does not use keyblob data to decrypt package1 any more.&lt;br /&gt;
&lt;br /&gt;
|  With a large enough brute force: arbitrary package1 code execution from coldboot.&lt;br /&gt;
&lt;br /&gt;
However, a usable brute force is on the order of &amp;gt;= ~2^80, so &#039;&#039;&#039;this is almost certainly not actually usable in any meaningful context&#039;&#039;&#039;.&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  Early 2017 (as soon as plaintext package1ldr was first dumped)&lt;br /&gt;
|  November 20, 2018&lt;br /&gt;
|  Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package1#Section_2|Secure Monitor]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  Missed BPMP Exception Vector Writes&lt;br /&gt;
|  Starting in [[2.0.0]], the BPMP is asleep at runtime, and is turned on by TrustZone during [[SMC|smcCpuSuspend]] in order to initiate the deep sleep process. When it does so, it is held in RESET, and TrustZone attempts to write to the BPMP exception vectors at 0x6000F200 to register EVP_RESET = lp0_entry_fw_crt0, and all other EVPs to a function that simply reboots. However, while they successfully write EVP_RESET, they miss all the other vectors, accidentally writing to the 0x6000F004-0x6000F020 region instead of the 0x6000F204-0x6000F220 region they want to write to. This results in all the exception vectors for the BPMP other than RESET being &amp;quot;undefined&amp;quot; (attacker controlled).&lt;br /&gt;
&lt;br /&gt;
With some way of causing an exception vector to be taken at the right time, this would give pre-sleep code execution (and thus arbitrary TrustZone code execution, via the security engine flaw). However, none of the abort vectors are really triggerable, and interrupts are disabled for the BPMP when it is taken out of reset. Thus, this is useless in practice.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by writing to the correct registers.&lt;br /&gt;
|  Theoretically: Arbitrary TrustZone code execution. In practice: Useless.&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  January, 2018&lt;br /&gt;
|  February 23, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]], [[User:Naehrwert|naehrwert]], [[User:Hexkyz|hexkyz]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
|  TSEC has access to the secure kernel carveout &lt;br /&gt;
|  TrustZone is responsible for managing security carveouts to prevent DMA controllers from accessing the carveout which contains the kernel, sysmodules, and other critical operating system data.&lt;br /&gt;
&lt;br /&gt;
Until [[8.0.0]], the list of devices that could access the carveout included the TSEC. However, the TSEC can bypass the SMMU when in authenticated mode by writing to a certain register. Thus, pwning nvservices would allow one to take over the TSEC, and use it to write to normally protected mmio/memory.&lt;br /&gt;
&lt;br /&gt;
In [[8.0.0]], this was fixed by removing TSEC access, and adding TSECB access (TSECB cannot bypass the SMMU).&lt;br /&gt;
| With access to the TSEC mmio (nvservices ROP) and code execution in TSEC Heavy Secure mode, kernel code execution, probably.&lt;br /&gt;
| [[8.0.0]]&lt;br /&gt;
| [[8.0.0]]&lt;br /&gt;
| 2017 (when TrustZone code plaintext was first obtained).&lt;br /&gt;
| April 15, 2019&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|  deja vu (insufficient system state validation on suspend leads to pre-sleep BPMP code execution)&lt;br /&gt;
|  Jamais Vu was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry, since gaining pre-sleep code execution on the BPMP compromises the system.&lt;br /&gt;
&lt;br /&gt;
However, the state validation performed by Nintendo&#039;s Secure Monitor was insufficient to prevent pre-sleep execution from being obtained.&lt;br /&gt;
&lt;br /&gt;
Prior to [[6.0.0]], one could use a DMA controller that had access to IRAM and was not held in reset (there were multiple) to race TrustZone&#039;s writes to the BPMP firmware in IRAM, and thus overwrite Nintendo&#039;s firmware with an attacker&#039;s to gain pre-sleep code execution.&lt;br /&gt;
&lt;br /&gt;
[[6.0.0]] addressed this by performing TrustZone state MAC writes and locking PMC scratch *before* turning on the BPMP, fixing the original Jamais Vu exploit entirely. In addition, the BPMP firmware in TrustZone&#039;s .rodata is now memcmp&#039;d to the actual data after it is written to IRAM. This mitigates race attacks that modify the firmware.&lt;br /&gt;
&lt;br /&gt;
However, Nintendo both forgot to validate the BPMP exception vectors after writing them, and forgot to hold in reset a DMA controller that can write to the BPMP&#039;s exception vectors.&lt;br /&gt;
&lt;br /&gt;
AHB-DMA is not blacklisted by kernel mapping whitelist (Nintendo probably forgot it, because the TX1 TRM does not really document that it&#039;s present, although the MMIO works as documented in older (Tegra 3 and before) TRMs).&lt;br /&gt;
&lt;br /&gt;
Thus, with kernel code execution (or some other way of accessing AHB-DMA, e.g. nspwn on &amp;lt;= 4.1.0, TSEC hax, or other arbitrary mmio access flaws), one can DMA to the BPMP&#039;s exception vectors as they are written, causing TrustZone to start the BPMP executing an attacker&#039;s firmware at a different location than TrustZone intends/validates.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[8.0.0]] by blocking AHB-DMA arbitration and verifying it is held in reset during suspend, and thus there are no more devices that can write to the relevant MMIO at the right time.&lt;br /&gt;
&lt;br /&gt;
|  Arbitrary TrustZone/BootROM code execution, by using either the original Jamais Vu flaw (prior to [[6.0.0]] or a warmboot bootrom exploit (any firmware where pre-sleep execution can be gained).&lt;br /&gt;
|  [[8.0.0]]&lt;br /&gt;
|  [[8.0.0]]&lt;br /&gt;
|  December 2017&lt;br /&gt;
|  April 15, 2019&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]] and ktemkin,  [[User:Naehrwert|naehrwert]] (independently), almost certainly others (independently)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package2#Section_0|HorizonOS Kernel]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| svcWaitSynchronization/svcReplyAndReceive bad cleanup on error&lt;br /&gt;
| If there is a page fault when fetching handles from the userspace array, it cleans up by dereferencing all objects despite having only loaded first N. Allows the attacker to make arbitrary decrefs on any kernel synchronization object, and thus can be used to get UAF. Haven&#039;t actually been tried on real HW though, but should work (tm).&lt;br /&gt;
| Kernel code execution&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| 24 April&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
| Potential [[SVC|svcWaitForAddress]] thread use-after-free&lt;br /&gt;
| Between [[4.0.0]], where svcWaitForAddress was introduced, and [[7.0.0]], there was a second intrusive rbtree node in KThread for the WaitForAddress tree (the key being (address, priority), sorted lexicographically). Unlike the WaitProcessWideKeyAtomic tree, the kernel forgot to reinsert the WaitForAddress node when the thread&#039;s priority changed (priority inheritance and/or SetPriority), breaking the rbtree invariants; and since the kernel walks through the entire tree to remove intrusive nodes, you could cause threads to stay in the tree even after their deletion.&lt;br /&gt;
&lt;br /&gt;
[[7.0.0]] fixed the issue by using the same intrusive node for both trees. The thread/node knows which tree it is in, and the latter is correctly updated when thread priority changes.&lt;br /&gt;
| It unluckily didn&#039;t look exploitable&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| July 2018&lt;br /&gt;
| February 2019&lt;br /&gt;
| [[User:TuxSH|TuxSH]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) 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 &amp;quot;spl:&amp;quot;, 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. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders (like expLDR): dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| nspwn&lt;br /&gt;
| fsp-ldr command 0 &amp;quot;MountCode&amp;quot; takes in a Content Path (retrieved from NCM by Loader), and returns an IFileSystem for the resulting ExeFS. These content paths, are normally NCAs, but MountCode also supports a number of other formats, including &amp;quot;.nsp&amp;quot; -- which is just a PFS0.&lt;br /&gt;
&lt;br /&gt;
When a path ending in &amp;quot;.nsp&amp;quot; is parsed by MountCode, the PFS0 is treated as a raw ExeFS. Because there is no NCA header, the ACID signatures are not validated -- and because there are no other signatures in a PFS0, this results in no signature checking happening at all.&lt;br /&gt;
&lt;br /&gt;
The actual .nsp handling is eventually done by {content mounting function} called by MountCode and other FS commands.&lt;br /&gt;
&lt;br /&gt;
Thus, by placing an ExeFS (NSOs + &amp;quot;main.npdm&amp;quot;) and setting one&#039;s desired title ID to &amp;quot;@Sdcard:/some_title.nsp&amp;quot; or &amp;quot;@User:/some_title.nsp&amp;quot; etc one can launch arbitrary unsigned code, with arbitrary unsigned NPDMs.&lt;br /&gt;
&lt;br /&gt;
This appears to have been fixed by only allowing .nsp when the input fstype==7 for the internal content-mounting function, returning 0x2EE202 otherwise.&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: Arbitrary code execution with full system privileges.&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| Late 2017&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single null-byte stack overflow in Loader ContentPath parsing&lt;br /&gt;
| Previously, loader content path parsing looked like this, where path_from_lr was up to 0x300 bytes and not necessarily null-terminated:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300] = {0};&lt;br /&gt;
  strcat(nca_path, path_from_lr);&lt;br /&gt;
  for (int i = 0; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Thus, a content path of the maximum length (0x300 bytes) would result in strcat writing a NULL terminator past the end of the nca_path buffer.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[6.0.0]], the new code looks like this:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300];&lt;br /&gt;
  strncpy(nca_path, path_from_lr, sizeof(nca_path));&lt;br /&gt;
  for (int i = 0; i  &amp;lt; sizeof(nca_path) &amp;amp;&amp;amp; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: single null-byte stack overflow in Loader. Maybe (but probably not) loader code execution.&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| September 2, 2018&lt;br /&gt;
| September 19, 2018&lt;br /&gt;
| SciresM&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
Flaws in this category pertain to any non-built-in system module.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| 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.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  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.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], ReSwitched Team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|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.&lt;br /&gt;
|&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|-&lt;br /&gt;
| expLDR (sysmodule handle table exhaustion)&lt;br /&gt;
| Most sysmodules share common template code to handle IPC control messages. The command DuplicateSession (type 5 command 2)&#039;s template code will abort() if it fails to duplicate a session&#039;s handle for the requester. Because many sysmodules have limited handle table size (smaller than the browser/other entrypoints), repeatedly requesting to duplicate one&#039;s session will cause the sysmodule to run out of handle table space and abort, causing the service to release all its handles cleanly.&lt;br /&gt;
| Sysmodule crashes.  Most usefully, crashing ldr allows access to fsp-ldr and crashing pm allows access to fsp-pr. Useless after [[4.0.0]], which mitigated a number of single-session service access issues.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| [[4.1.0]]&lt;br /&gt;
| 24 June 2017&lt;br /&gt;
| 8 March 2018&lt;br /&gt;
| [[User:daeken|daeken]]&lt;br /&gt;
|-&lt;br /&gt;
| Transfer Memory leak in nvservices system module&lt;br /&gt;
| The nvservices sysmodule does not clear most of its transfer memory prior to release.&lt;br /&gt;
| The calling process can read key bits of memory, including breaking ASLR (by revealing the image base) and exposing the address of other transfer memory to set up attacks. More details here: [https://daeken.svbtle.com/nintendo-switch-nvservices-info-leak transfermeme (nvservices info leak)] by [[User:daeken|daeken]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| June 2017&lt;br /&gt;
| 16 October 2018&lt;br /&gt;
| [[User:qlutoo|qlutoo]] and [[User:hexkyz|hexkyz]],&lt;br /&gt;
[[User:daeken|daeken]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
| OOB write in audio system module&lt;br /&gt;
| Prior to [[2.0.0]], the [[Audio_services#audout:u|AppendAudioOutBuffer]] and [[Audio_services#audin:u|AppendAudioInBuffer]] IPC commands would blindly increment the appended buffers&#039; count while using said count value as an index to where the user data should be copied into. This resulted in an 0x28 bytes, user controlled, out-of-bounds memory write into the [[Audio_services|audio]] sysmodule&#039;s memory space.&lt;br /&gt;
Combined with the [[Audio_services#audout:u|GetReleasedAudioOutBuffer]] or [[Audio_services#audin:u|GetReleasedAudioInBuffer]] commands, this could also be used as an 8 byte infoleak.&lt;br /&gt;
&lt;br /&gt;
In [[2.0.0]], the commands now return error code 0x1099 if the number of unreleased buffers exceeds 0x1F.&lt;br /&gt;
| Code execution under audio sysmodule&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| November 2, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]], probably others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| nvhax (memory corruption in nvservices system module)&lt;br /&gt;
| Prior to [[6.2.0]], the [[NV_services|nvservices]] ioctl [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] would take a single &amp;quot;pwarpstate&amp;quot; argument which would be interpreted by nvservices as a memory pointer for writing 2 &amp;quot;warpstate&amp;quot; structs (one for each Streaming Multiprocessor).&lt;br /&gt;
This resulted in nvservices attempting to blindly memcpy into this user supplied address and trigger a crash. However, if paired with an infoleak, this could be used to arbitrarily write 0x30 bytes anywhere in nvservices&#039; memory space.&lt;br /&gt;
Additionally, the &amp;quot;warpstate&amp;quot; struct itself was never initialized, which means nvservices would leak the 0x30 bytes from the stack. By invoking other ioctls it was also possible to partially control the stack contents and achieve a usable arbitrary memory write primitive.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] now takes 2 inline &amp;quot;warpstate&amp;quot; structs instead of a &amp;quot;pwarpstate&amp;quot; pointer, thus effectively avoiding the bad memcpy.&lt;br /&gt;
| Code execution under nvservices sysmodule&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 5, 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]]&lt;br /&gt;
|-&lt;br /&gt;
| Infoleak in nvservices system module&lt;br /&gt;
| The [[NV_services|nvservices]] ioctl [[NV_services#NVMAP_IOC_ALLOC|NVMAP_IOC_ALLOC]] takes an optional argument &amp;quot;addr&amp;quot; which allows the calling process to pass a pointer to user allocated memory for backing a nvmap object. If &amp;quot;addr&amp;quot; is left as 0, nvservices uses the transfer memory region (donated by the user during initialization) instead, when allocating memory for the nvmap object.&lt;br /&gt;
By design, freeing the nvmap object by calling the ioctl [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] returns, in its &amp;quot;refcount&amp;quot; argument, the user address previously supplied if the reference count reaches 0.&lt;br /&gt;
However, prior to [[6.2.0]], the case where the transfer memory region is used to allocate the nvmap object was not taken into account, thus resulting in [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] leaking back an address from within the transfer memory region mapped in nvservices&#039; memory space.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] no longer returns the address when the transfer memory region is used instead of user supplied memory.&lt;br /&gt;
| Combined with other vulnerabilities: Defeating ASLR in nvservices sysmodule.&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6251</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6251"/>
		<updated>2019-02-19T13:31:45Z</updated>

		<summary type="html">&lt;p&gt;Rei: small oversight&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Exploits are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of publicly known Switch system flaws.&lt;br /&gt;
&lt;br /&gt;
For userland applications/applets flaws see [[Switch_Userland_Flaws|here]]. &lt;br /&gt;
&lt;br /&gt;
= System flaws =&lt;br /&gt;
== Hardware == &lt;br /&gt;
Flaws in this category pertain to the underlying hardware that powers the Switch.&lt;br /&gt;
&lt;br /&gt;
This includes components shared across Tegra based devices such as the [[TSEC]], the [[Security_Engine|Security Engine]], the [[GPU]] and so on.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| CVE-2018-6242 (leveraged by the ShofEL2 and Fusée Gelée exploits)&lt;br /&gt;
| The USB software stack provided inside the boot instruction rom (IROM/bootROM) contains a copy operation whose length can be controlled by an attacker. By carefully constructing a USB control request, an attacker can leverage this vulnerability to copy the contents of an attacker-controlled buffer over the active execution stack, gaining control of the Boot and Power Management processor (BPMP) before any lock-outs or privilege reductions occur. This execution can then be used to exfiltrate secrets and to load arbitrary code onto the main CPU Complex (CCPLEX) &amp;quot;application processors&amp;quot; at the highest possible level of privilege (typically as the TrustZone Secure Monitor at PL3/EL3).&lt;br /&gt;
| Unknown (Tegra186 and Tegra214)&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| January 2018&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| [[User:Shuffle2|shuffle2]] and fail0verflow (originally),&amp;lt;br&amp;gt; [[User:Ktemkin|ktemkin]] and ReSwitched Team (independently),&amp;lt;br&amp;gt; [[User:Naehrwert|naehrwert]] (independently),&amp;lt;br&amp;gt; [[User:Hexkyz|hexkyz]] (independently),&amp;lt;br&amp;gt; st4rk with [[User:Shinyquagsire23|Shiny Quagsire]] and Dazzozo (independently),&amp;lt;br&amp;gt; and many others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
&lt;br /&gt;
[5.0.0+] Works around this hardware flaw by using memory pool partitioning. You can no longer escalate into sysmodules with GPU DMA because all their memory is allocated using heap that&#039;s carved out.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
&lt;br /&gt;
This also bypasses the SBK protection of the bootROM: indeed, at warmboot, bootROM will always clear keyslot 0xE to prevent malicious code from saving the SBK. Moving the SBK to another keyslot in the saved context renders this protection moot.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
| Security Engine keyslots vulnerable to partial overwrite attack&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 security engine supports writing keyslot data to the engine with syntax as follows: &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_ADDR = (keyslot &amp;lt;&amp;lt; 4) | (dword_index_in_keyslot); &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_DATA = readle32(key, dword_index_in_keyslot * 4); &lt;br /&gt;
&lt;br /&gt;
However, the Security Engine flushes writes to the internal key tables immediately when AES_KEYTABLE_DATA is written -- this allows one to overwrite a single dword of a key at a time, and thus brute force the contents of keyslots in time (2^32 * 8) = 2^35 instead of 2^256.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Theorized Summer 2017 due to suggestive syntax, confirmed April 9, 2018&lt;br /&gt;
| April 9, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], almost surely others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| Poor validation of bootrom SDRAM configuration parameters leads to arbitrary writes in bootrom&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 bootrom supports saving SDRAM parameters to scratch registers, and using the saved configuration to enable DRAM during warmboot.&lt;br /&gt;
&lt;br /&gt;
The code that parses these parameters does if (params-&amp;gt;EmcBctSpareN) *params-&amp;gt;EmcBctSpareN = params-&amp;gt;EmcBctSpareNPlusOne for most N, without validating either the address or value written to it.&lt;br /&gt;
There are other arbitrary writes in this code, as well (e.g. BootromPatch parameters intended for patching MISC registers do not check a relative offset to 0x7000000, etc).&lt;br /&gt;
&lt;br /&gt;
This allows a user with access to the PMC registers (via pre-sleep bpmp execution, or otherwise) to gain arbitrary bootrom code execution.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| 2017&lt;br /&gt;
| December 16, 2018&lt;br /&gt;
| Everyone (independently).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Bootloader ===&lt;br /&gt;
Flaws in this category pertain to any bootloader component such as the [[Package1#Package1ldr|package1ldr]], the [[Package1#Section_1|NX bootloader]] or the [[Package1#Section_0|warmboot binary]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;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&#039;t get initialized until partway into the bootloader&#039;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. &lt;br /&gt;
The BPMP doesn&#039;t have an active MPU and the bus won&#039;t data abort on an invalid address, so no exception will be entered: it&#039;ll end up overwriting some exception vectors with NULL before halting.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Some exception vectors overwritten with NULL, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  TSEC firmware compromises itself&lt;br /&gt;
|  Package1ldr loads a firmware blob into TSEC early on boot. This piece of code runs on the TSEC in Authenticated Mode and has the sole purpose of generating the per-console TSEC key (see [[Cryptosystem]]).&lt;br /&gt;
&lt;br /&gt;
As a way to mitigate attacks, the TSEC firmware blob is split into 3 stages: [[TSEC#Stage_0|Stage 0]] which is unencrypted and unsigned, [[TSEC#Stage_1|Stage 1]] which is unencrypted but signed and [[TSEC#Stage_2|Stage 2]] which is encrypted and signed.&lt;br /&gt;
Stage 0 loads a static pre-generated signature into the Falcon&#039;s CPU crypto registers, loads Stage 1 into the Falcon&#039;s CODE region and jumps to it. Execution will proceed into Stage 1 in Authenticated Mode if, and only if, the loaded signature matches the one Falcon calculates internally for Stage 1.&lt;br /&gt;
&lt;br /&gt;
Among various things, Stage 1 will attempt to do a &amp;quot;backwards&amp;quot; security check by calculating a CMAC over Stage 0 and comparing it with a known hash stored in the TSEC firmware&#039;s key data (a small buffer stored after Stage 0&#039;s code). If the hashes don&#039;t match, execution aborts.&lt;br /&gt;
&lt;br /&gt;
Stage 1 stores the calculated Stage 0&#039;s CMAC in the stack, but forgets to clear it. Since the stack is located in Falcon&#039;s DATA region, loading the TSEC firmware blob and dumping the DATA region afterwards (via MMIO) will reveal the calculated hash.&lt;br /&gt;
This allows using Stage 1 as an oracle to generate a valid CMAC for arbitrary Stage 0 code. Replacing the CMAC in the TSEC firmware&#039;s key data region results in Stage 1 accepting any Stage 0 code, thus rendering this security measure useless.&lt;br /&gt;
&lt;br /&gt;
Additionally, since signed Falcon code can&#039;t be revoked without an hardware revision, an attacker can always reuse the flawed Stage 1 code even if a fix is issued.&lt;br /&gt;
|  Running TSEC firmware&#039;s Stage 1 in a user controlled environment. Mostly useless, but may aid in side-channel attacks.&lt;br /&gt;
|  None&lt;br /&gt;
|  [[5.0.2]]&lt;br /&gt;
|  January 2018&lt;br /&gt;
|  April 29, 2018&lt;br /&gt;
|  [[User:Hexkyz|hexkyz]], Reisyukaku, probably others.&lt;br /&gt;
|-&lt;br /&gt;
|  pk1ldrhax&lt;br /&gt;
|  Package1ldr decrypts and verifies the keyblob inside of the current BCT in order to get the package1 key, and then uses the package1 key to decrypt package1. It then validates package1 before jumping to it by checking the PK11 magic number, and that the section sizes sum to the expected size (and are individually less than the expected size). &lt;br /&gt;
&lt;br /&gt;
However, package1ldr does not actually validate the package1 key against a fixed vector (much like kernel9loader forgot to do so on the 3ds). This would normally not matter, as keyblobs are validated -- however, with bootrom code execution one can dump SBK and forge keyblobs, and thus control the package1 key. &lt;br /&gt;
&lt;br /&gt;
Thus (&#039;&#039;&#039;in theory, but not in practice due to the size of the brute force required&#039;&#039;&#039;) one can replace the package1 key with garbage, causing package1 to decrypt into garbage, and hope that this garbage passes validation checks and that package1ldr jumping into the garbage will do something useful.&lt;br /&gt;
&lt;br /&gt;
This was fixed incidentally in [[6.2.0]], as pk1ldr does not use keyblob data to decrypt package1 any more.&lt;br /&gt;
&lt;br /&gt;
|  With a large enough brute force: arbitrary package1 code execution from coldboot.&lt;br /&gt;
&lt;br /&gt;
However, a usable brute force is on the order of &amp;gt;= ~2^80, so &#039;&#039;&#039;this is almost certainly not actually usable in any meaningful context&#039;&#039;&#039;.&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  Early 2017 (as soon as plaintext package1ldr was first dumped)&lt;br /&gt;
|  November 20, 2018&lt;br /&gt;
|  Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package1#Section_2|Secure Monitor]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
|  jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  Missed BPMP Exception Vector Writes&lt;br /&gt;
|  Starting in [[2.0.0]], the BPMP is asleep at runtime, and is turned on by TrustZone during [[SMC|smcCpuSuspend]] in order to initiate the deep sleep process. When it does so, it is held in RESET, and TrustZone attempts to write to the BPMP exception vectors at 0x6000F200 to register EVP_RESET = lp0_entry_fw_crt0, and all other EVPs to a function that simply reboots. However, while they successfully write EVP_RESET, they miss all the other vectors, accidentally writing to the 0x6000F004-0x6000F020 region instead of the 0x6000F204-0x6000F220 region they want to write to. This results in all the exception vectors for the BPMP other than RESET being &amp;quot;undefined&amp;quot; (attacker controlled).&lt;br /&gt;
&lt;br /&gt;
With some way of causing an exception vector to be taken at the right time, this would give pre-sleep code execution (and thus arbitrary TrustZone code execution, via the security engine flaw). However, none of the abort vectors are really triggerable, and interrupts are disabled for the BPMP when it is taken out of reset. Thus, this is useless in practice.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by writing to the correct registers.&lt;br /&gt;
|  Theoretically: Arbitrary TrustZone code execution. In practice: Useless.&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  January, 2018&lt;br /&gt;
|  February 23, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]], [[User:Naehrwert|naehrwert]], [[User:Hexkyz|hexkyz]], probably others, independently.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package2#Section_0|HorizonOS Kernel]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| svcWaitSynchronization/svcReplyAndReceive bad cleanup on error&lt;br /&gt;
| If there is a page fault when fetching handles from the userspace array, it cleans up by dereferencing all objects despite having only loaded first N. Allows the attacker to make arbitrary decrefs on any kernel synchronization object, and thus can be used to get UAF. Haven&#039;t actually been tried on real HW though, but should work (tm).&lt;br /&gt;
| Kernel code execution&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| 24 April&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
| Potential [[SVC|svcWaitForAddress]] thread use-after-free&lt;br /&gt;
| Between [[4.0.0]], where svcWaitForAddress was introduced, and [[7.0.0]], there was a second intrusive rbtree node in KThread for the WaitForAddress tree (the key being (address, priority), sorted lexicographically). Unlike the WaitProcessWideKeyAtomic tree, the kernel forgot to reinsert the WaitForAddress node when the thread&#039;s priority changed (priority inheritance and/or SetPriority), breaking the rbtree invariants; and since the kernel walks through the entire tree to remove intrusive nodes, you could cause threads to stay in the tree even after their deletion.&lt;br /&gt;
&lt;br /&gt;
[[7.0.0]] fixed the issue by using the same intrusive node for both trees. The thread/node knows which tree it is in, and the latter is correctly updated when thread priority changes.&lt;br /&gt;
| It unluckily didn&#039;t look exploitable&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| July 2018&lt;br /&gt;
| February 2019&lt;br /&gt;
| [[User:TuxSH|TuxSH]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) 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 &amp;quot;spl:&amp;quot;, 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. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders (like expLDR): dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| nspwn&lt;br /&gt;
| fsp-ldr command 0 &amp;quot;MountCode&amp;quot; takes in a Content Path (retrieved from NCM by Loader), and returns an IFileSystem for the resulting ExeFS. These content paths, are normally NCAs, but MountCode also supports a number of other formats, including &amp;quot;.nsp&amp;quot; -- which is just a PFS0.&lt;br /&gt;
&lt;br /&gt;
When a path ending in &amp;quot;.nsp&amp;quot; is parsed by MountCode, the PFS0 is treated as a raw ExeFS. Because there is no NCA header, the ACID signatures are not validated -- and because there are no other signatures in a PFS0, this results in no signature checking happening at all.&lt;br /&gt;
&lt;br /&gt;
The actual .nsp handling is eventually done by {content mounting function} called by MountCode and other FS commands.&lt;br /&gt;
&lt;br /&gt;
Thus, by placing an ExeFS (NSOs + &amp;quot;main.npdm&amp;quot;) and setting one&#039;s desired title ID to &amp;quot;@Sdcard:/some_title.nsp&amp;quot; or &amp;quot;@User:/some_title.nsp&amp;quot; etc one can launch arbitrary unsigned code, with arbitrary unsigned NPDMs.&lt;br /&gt;
&lt;br /&gt;
This appears to have been fixed by only allowing .nsp when the input fstype==7 for the internal content-mounting function, returning 0x2EE202 otherwise.&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: Arbitrary code execution with full system privileges.&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| Late 2017&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single null-byte stack overflow in Loader ContentPath parsing&lt;br /&gt;
| Previously, loader content path parsing looked like this, where path_from_lr was up to 0x300 bytes and not necessarily null-terminated:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300] = {0};&lt;br /&gt;
  strcat(nca_path, path_from_lr);&lt;br /&gt;
  for (int i = 0; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Thus, a content path of the maximum length (0x300 bytes) would result in strcat writing a NULL terminator past the end of the nca_path buffer.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[6.0.0]], the new code looks like this:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300];&lt;br /&gt;
  strncpy(nca_path, path_from_lr, sizeof(nca_path));&lt;br /&gt;
  for (int i = 0; i  &amp;lt; sizeof(nca_path) &amp;amp;&amp;amp; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: single null-byte stack overflow in Loader. Maybe (but probably not) loader code execution.&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| September 2, 2018&lt;br /&gt;
| September 19, 2018&lt;br /&gt;
| SciresM&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
Flaws in this category pertain to any non-built-in system module.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| 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.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  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.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], ReSwitched Team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|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.&lt;br /&gt;
|&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|-&lt;br /&gt;
| expLDR (sysmodule handle table exhaustion)&lt;br /&gt;
| Most sysmodules share common template code to handle IPC control messages. The command DuplicateSession (type 5 command 2)&#039;s template code will abort() if it fails to duplicate a session&#039;s handle for the requester. Because many sysmodules have limited handle table size (smaller than the browser/other entrypoints), repeatedly requesting to duplicate one&#039;s session will cause the sysmodule to run out of handle table space and abort, causing the service to release all its handles cleanly.&lt;br /&gt;
| Sysmodule crashes.  Most usefully, crashing ldr allows access to fsp-ldr and crashing pm allows access to fsp-pr. Useless after [[4.0.0]], which mitigated a number of single-session service access issues.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| [[4.1.0]]&lt;br /&gt;
| 24 June 2017&lt;br /&gt;
| 8 March 2018&lt;br /&gt;
| [[User:daeken|daeken]]&lt;br /&gt;
|-&lt;br /&gt;
| Transfer Memory leak in nvservices system module&lt;br /&gt;
| The nvservices sysmodule does not clear most of its transfer memory prior to release.&lt;br /&gt;
| The calling process can read key bits of memory, including breaking ASLR (by revealing the image base) and exposing the address of other transfer memory to set up attacks. More details here: [https://daeken.svbtle.com/nintendo-switch-nvservices-info-leak transfermeme (nvservices info leak)] by [[User:daeken|daeken]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| June 2017&lt;br /&gt;
| 16 October 2018&lt;br /&gt;
| [[User:qlutoo|qlutoo]] and [[User:hexkyz|hexkyz]],&lt;br /&gt;
[[User:daeken|daeken]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
| OOB write in audio system module&lt;br /&gt;
| Prior to [[2.0.0]], the [[Audio_services#audout:u|AppendAudioOutBuffer]] and [[Audio_services#audin:u|AppendAudioInBuffer]] IPC commands would blindly increment the appended buffers&#039; count while using said count value as an index to where the user data should be copied into. This resulted in an 0x28 bytes, user controlled, out-of-bounds memory write into the [[Audio_services|audio]] sysmodule&#039;s memory space.&lt;br /&gt;
Combined with the [[Audio_services#audout:u|GetReleasedAudioOutBuffer]] or [[Audio_services#audin:u|GetReleasedAudioInBuffer]] commands, this could also be used as an 8 byte infoleak.&lt;br /&gt;
&lt;br /&gt;
In [[2.0.0]], the commands now return error code 0x1099 if the number of unreleased buffers exceeds 0x1F.&lt;br /&gt;
| Code execution under audio sysmodule&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| November 2, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
| nvhax (memory corruption in nvservices system module)&lt;br /&gt;
| Prior to [[6.2.0]], the [[NV_services|nvservices]] ioctl [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] would take a single &amp;quot;pwarpstate&amp;quot; argument which would be interpreted by nvservices as a memory pointer for writing 2 &amp;quot;warpstate&amp;quot; structs (one for each Streaming Multiprocessor).&lt;br /&gt;
This resulted in nvservices attempting to blindly memcpy into this user supplied address and trigger a crash. However, if paired with an infoleak, this could be used to arbitrarily write 0x30 bytes anywhere in nvservices&#039; memory space.&lt;br /&gt;
Additionally, the &amp;quot;warpstate&amp;quot; struct itself was never initialized, which means nvservices would leak the 0x30 bytes from the stack. By invoking other ioctls it was also possible to partially control the stack contents and achieve a usable arbitrary memory write primitive.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] now takes 2 inline &amp;quot;warpstate&amp;quot; structs instead of a &amp;quot;pwarpstate&amp;quot; pointer, thus effectively avoiding the bad memcpy.&lt;br /&gt;
| Code execution under nvservices sysmodule&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 5, 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]]&lt;br /&gt;
|-&lt;br /&gt;
| Infoleak in nvservices system module&lt;br /&gt;
| The [[NV_services|nvservices]] ioctl [[NV_services#NVMAP_IOC_ALLOC|NVMAP_IOC_ALLOC]] takes an optional argument &amp;quot;addr&amp;quot; which allows the calling process to pass a pointer to user allocated memory for backing a nvmap object. If &amp;quot;addr&amp;quot; is left as 0, nvservices uses the transfer memory region (donated by the user during initialization) instead, when allocating memory for the nvmap object.&lt;br /&gt;
By design, freeing the nvmap object by calling the ioctl [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] returns, in its &amp;quot;refcount&amp;quot; argument, the user address previously supplied if the reference count reaches 0.&lt;br /&gt;
However, prior to [[6.2.0]], the case where the transfer memory region is used to allocate the nvmap object was not taken into account, thus resulting in [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] leaking back an address from within the transfer memory region mapped in nvservices&#039; memory space.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] no longer returns the address when the transfer memory region is used instead of user supplied memory.&lt;br /&gt;
| Combined with other vulnerabilities: Defeating ASLR in nvservices sysmodule.&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6249</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=6249"/>
		<updated>2019-02-19T13:08:52Z</updated>

		<summary type="html">&lt;p&gt;Rei: /* Bootloader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Exploits are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of publicly known Switch system flaws.&lt;br /&gt;
&lt;br /&gt;
For userland applications/applets flaws see [[Switch_Userland_Flaws|here]]. &lt;br /&gt;
&lt;br /&gt;
= System flaws =&lt;br /&gt;
== Hardware == &lt;br /&gt;
Flaws in this category pertain to the underlying hardware that powers the Switch.&lt;br /&gt;
&lt;br /&gt;
This includes components shared across Tegra based devices such as the [[TSEC]], the [[Security_Engine|Security Engine]], the [[GPU]] and so on.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| CVE-2018-6242 (leveraged by the ShofEL2 and Fusée Gelée exploits)&lt;br /&gt;
| The USB software stack provided inside the boot instruction rom (IROM/bootROM) contains a copy operation whose length can be controlled by an attacker. By carefully constructing a USB control request, an attacker can leverage this vulnerability to copy the contents of an attacker-controlled buffer over the active execution stack, gaining control of the Boot and Power Management processor (BPMP) before any lock-outs or privilege reductions occur. This execution can then be used to exfiltrate secrets and to load arbitrary code onto the main CPU Complex (CCPLEX) &amp;quot;application processors&amp;quot; at the highest possible level of privilege (typically as the TrustZone Secure Monitor at PL3/EL3).&lt;br /&gt;
| Unknown (Tegra186 and Tegra214)&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| January 2018&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| [[User:Shuffle2|shuffle2]] and fail0verflow (originally),&amp;lt;br&amp;gt; [[User:Ktemkin|ktemkin]] and ReSwitched Team (independently),&amp;lt;br&amp;gt; [[User:Naehrwert|naehrwert]] (independently),&amp;lt;br&amp;gt; [[User:Hexkyz|hexkyz]] (independently),&amp;lt;br&amp;gt; st4rk with [[User:Shinyquagsire23|Shiny Quagsire]] and Dazzozo (independently),&amp;lt;br&amp;gt; and many others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
&lt;br /&gt;
[5.0.0+] Works around this hardware flaw by using memory pool partitioning. You can no longer escalate into sysmodules with GPU DMA because all their memory is allocated using heap that&#039;s carved out.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
&lt;br /&gt;
This also bypasses the SBK protection of the bootROM: indeed, at warmboot, bootROM will always clear keyslot 0xE to prevent malicious code from saving the SBK. Moving the SBK to another keyslot in the saved context renders this protection moot.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
| Security Engine keyslots vulnerable to partial overwrite attack&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 security engine supports writing keyslot data to the engine with syntax as follows: &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_ADDR = (keyslot &amp;lt;&amp;lt; 4) | (dword_index_in_keyslot); &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_DATA = readle32(key, dword_index_in_keyslot * 4); &lt;br /&gt;
&lt;br /&gt;
However, the Security Engine flushes writes to the internal key tables immediately when AES_KEYTABLE_DATA is written -- this allows one to overwrite a single dword of a key at a time, and thus brute force the contents of keyslots in time (2^32 * 8) = 2^35 instead of 2^256.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| Theorized Summer 2017 due to suggestive syntax, confirmed April 9, 2018&lt;br /&gt;
| April 9, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], almost surely others (independently).&lt;br /&gt;
|-&lt;br /&gt;
| Poor validation of bootrom SDRAM configuration parameters leads to arbitrary writes in bootrom&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 bootrom supports saving SDRAM parameters to scratch registers, and using the saved configuration to enable DRAM during warmboot.&lt;br /&gt;
&lt;br /&gt;
The code that parses these parameters does if (params-&amp;gt;EmcBctSpareN) *params-&amp;gt;EmcBctSpareN = params-&amp;gt;EmcBctSpareNPlusOne for most N, without validating either the address or value written to it.&lt;br /&gt;
There are other arbitrary writes in this code, as well (e.g. BootromPatch parameters intended for patching MISC registers do not check a relative offset to 0x7000000, etc).&lt;br /&gt;
&lt;br /&gt;
This allows a user with access to the PMC registers (via pre-sleep bpmp execution, or otherwise) to gain arbitrary bootrom code execution.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001 (Tegra210)&lt;br /&gt;
| 2017&lt;br /&gt;
| December 16, 2018&lt;br /&gt;
| Everyone (independently).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Bootloader ===&lt;br /&gt;
Flaws in this category pertain to any bootloader component such as the [[Package1#Package1ldr|package1ldr]], the [[Package1#Section_1|NX bootloader]] or the [[Package1#Section_0|warmboot binary]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;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&#039;t get initialized until partway into the bootloader&#039;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. &lt;br /&gt;
The BPMP doesn&#039;t have an active MPU and the bus won&#039;t data abort on an invalid address, so no exception will be entered: it&#039;ll end up overwriting some exception vectors with NULL before halting.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Some exception vectors overwritten with NULL, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  TSEC firmware compromises itself&lt;br /&gt;
|  Package1ldr loads a firmware blob into TSEC early on boot. This piece of code runs on the TSEC in Authenticated Mode and has the sole purpose of generating the per-console TSEC key (see [[Cryptosystem]]).&lt;br /&gt;
&lt;br /&gt;
As a way to mitigate attacks, the TSEC firmware blob is split into 3 stages: [[TSEC#Stage_0|Stage 0]] which is unencrypted and unsigned, [[TSEC#Stage_1|Stage 1]] which is unencrypted but signed and [[TSEC#Stage_2|Stage 2]] which is encrypted and signed.&lt;br /&gt;
Stage 0 loads a static pre-generated signature into the Falcon&#039;s CPU crypto registers, loads Stage 1 into the Falcon&#039;s CODE region and jumps to it. Execution will proceed into Stage 1 in Authenticated Mode if, and only if, the loaded signature matches the one Falcon calculates internally for Stage 1.&lt;br /&gt;
&lt;br /&gt;
Among various things, Stage 1 will attempt to do a &amp;quot;backwards&amp;quot; security check by calculating a CMAC over Stage 0 and comparing it with a known hash stored in the TSEC firmware&#039;s key data (a small buffer stored after Stage 0&#039;s code). If the hashes don&#039;t match, execution aborts.&lt;br /&gt;
&lt;br /&gt;
Stage 1 stores the calculated Stage 0&#039;s CMAC in the stack, but forgets to clear it. Since the stack is located in Falcon&#039;s DATA region, loading the TSEC firmware blob and dumping the DATA region afterwards (via MMIO) will reveal the calculated hash.&lt;br /&gt;
This allows using Stage 1 as an oracle to generate a valid CMAC for arbitrary Stage 0 code. Replacing the CMAC in the TSEC firmware&#039;s key data region results in Stage 1 accepting any Stage 0 code, thus rendering this security measure useless.&lt;br /&gt;
&lt;br /&gt;
Additionally, since signed Falcon code can&#039;t be revoked without an hardware revision, an attacker can always reuse the flawed Stage 1 code even if a fix is issued.&lt;br /&gt;
|  Running TSEC firmware&#039;s Stage 1 in a user controlled environment. Mostly useless, but may aid in side-channel attacks.&lt;br /&gt;
|  None&lt;br /&gt;
|  [[5.0.2]]&lt;br /&gt;
|  January 2018&lt;br /&gt;
|  April 29, 2018&lt;br /&gt;
|  [[User:Hexkyz|hexkyz]], Reisyukaku (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  pk1ldrhax&lt;br /&gt;
|  Package1ldr decrypts and verifies the keyblob inside of the current BCT in order to get the package1 key, and then uses the package1 key to decrypt package1. It then validates package1 before jumping to it by checking the PK11 magic number, and that the section sizes sum to the expected size (and are individually less than the expected size). &lt;br /&gt;
&lt;br /&gt;
However, package1ldr does not actually validate the package1 key against a fixed vector (much like kernel9loader forgot to do so on the 3ds). This would normally not matter, as keyblobs are validated -- however, with bootrom code execution one can dump SBK and forge keyblobs, and thus control the package1 key. &lt;br /&gt;
&lt;br /&gt;
Thus (&#039;&#039;&#039;in theory, but not in practice due to the size of the brute force required&#039;&#039;&#039;) one can replace the package1 key with garbage, causing package1 to decrypt into garbage, and hope that this garbage passes validation checks and that package1ldr jumping into the garbage will do something useful.&lt;br /&gt;
&lt;br /&gt;
This was fixed incidentally in [[6.2.0]], as pk1ldr does not use keyblob data to decrypt package1 any more.&lt;br /&gt;
&lt;br /&gt;
|  With a large enough brute force: arbitrary package1 code execution from coldboot.&lt;br /&gt;
&lt;br /&gt;
However, a usable brute force is on the order of &amp;gt;= ~2^80, so &#039;&#039;&#039;this is almost certainly not actually usable in any meaningful context&#039;&#039;&#039;.&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  [[6.2.0]]&lt;br /&gt;
|  Early 2017 (as soon as plaintext package1ldr was first dumped)&lt;br /&gt;
|  November 20, 2018&lt;br /&gt;
|  Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package1#Section_2|Secure Monitor]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
|  jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  Missed BPMP Exception Vector Writes&lt;br /&gt;
|  Starting in [[2.0.0]], the BPMP is asleep at runtime, and is turned on by TrustZone during [[SMC|smcCpuSuspend]] in order to initiate the deep sleep process. When it does so, it is held in RESET, and TrustZone attempts to write to the BPMP exception vectors at 0x6000F200 to register EVP_RESET = lp0_entry_fw_crt0, and all other EVPs to a function that simply reboots. However, while they successfully write EVP_RESET, they miss all the other vectors, accidentally writing to the 0x6000F004-0x6000F020 region instead of the 0x6000F204-0x6000F220 region they want to write to. This results in all the exception vectors for the BPMP other than RESET being &amp;quot;undefined&amp;quot; (attacker controlled).&lt;br /&gt;
&lt;br /&gt;
With some way of causing an exception vector to be taken at the right time, this would give pre-sleep code execution (and thus arbitrary TrustZone code execution, via the security engine flaw). However, none of the abort vectors are really triggerable, and interrupts are disabled for the BPMP when it is taken out of reset. Thus, this is useless in practice.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by writing to the correct registers.&lt;br /&gt;
|  Theoretically: Arbitrary TrustZone code execution. In practice: Useless.&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  January, 2018&lt;br /&gt;
|  February 23, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]], [[User:Naehrwert|naehrwert]], [[User:Hexkyz|hexkyz]], probably others, independently.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
Flaws in this category pertain exclusively to the [[Package2#Section_0|HorizonOS Kernel]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| svcWaitSynchronization/svcReplyAndReceive bad cleanup on error&lt;br /&gt;
| If there is a page fault when fetching handles from the userspace array, it cleans up by dereferencing all objects despite having only loaded first N. Allows the attacker to make arbitrary decrefs on any kernel synchronization object, and thus can be used to get UAF. Haven&#039;t actually been tried on real HW though, but should work (tm).&lt;br /&gt;
| Kernel code execution&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| 24 April&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
| Potential [[SVC|svcWaitForAddress]] thread use-after-free&lt;br /&gt;
| Between [[4.0.0]], where svcWaitForAddress was introduced, and [[7.0.0]], there was a second intrusive rbtree node in KThread for the WaitForAddress tree (the key being (address, priority), sorted lexicographically). Unlike the WaitProcessWideKeyAtomic tree, the kernel forgot to reinsert the WaitForAddress node when the thread&#039;s priority changed (priority inheritance and/or SetPriority), breaking the rbtree invariants; and since the kernel walks through the entire tree to remove intrusive nodes, you could cause threads to stay in the tree even after their deletion.&lt;br /&gt;
&lt;br /&gt;
[[7.0.0]] fixed the issue by using the same intrusive node for both trees. The thread/node knows which tree it is in, and the latter is correctly updated when thread priority changes.&lt;br /&gt;
| It unluckily didn&#039;t look exploitable&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| [[7.0.0]]&lt;br /&gt;
| July 2018&lt;br /&gt;
| February 2019&lt;br /&gt;
| [[User:TuxSH|TuxSH]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) 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 &amp;quot;spl:&amp;quot;, 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. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders (like expLDR): dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| nspwn&lt;br /&gt;
| fsp-ldr command 0 &amp;quot;MountCode&amp;quot; takes in a Content Path (retrieved from NCM by Loader), and returns an IFileSystem for the resulting ExeFS. These content paths, are normally NCAs, but MountCode also supports a number of other formats, including &amp;quot;.nsp&amp;quot; -- which is just a PFS0.&lt;br /&gt;
&lt;br /&gt;
When a path ending in &amp;quot;.nsp&amp;quot; is parsed by MountCode, the PFS0 is treated as a raw ExeFS. Because there is no NCA header, the ACID signatures are not validated -- and because there are no other signatures in a PFS0, this results in no signature checking happening at all.&lt;br /&gt;
&lt;br /&gt;
The actual .nsp handling is eventually done by {content mounting function} called by MountCode and other FS commands.&lt;br /&gt;
&lt;br /&gt;
Thus, by placing an ExeFS (NSOs + &amp;quot;main.npdm&amp;quot;) and setting one&#039;s desired title ID to &amp;quot;@Sdcard:/some_title.nsp&amp;quot; or &amp;quot;@User:/some_title.nsp&amp;quot; etc one can launch arbitrary unsigned code, with arbitrary unsigned NPDMs.&lt;br /&gt;
&lt;br /&gt;
This appears to have been fixed by only allowing .nsp when the input fstype==7 for the internal content-mounting function, returning 0x2EE202 otherwise.&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: Arbitrary code execution with full system privileges.&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| Late 2017&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single null-byte stack overflow in Loader ContentPath parsing&lt;br /&gt;
| Previously, loader content path parsing looked like this, where path_from_lr was up to 0x300 bytes and not necessarily null-terminated:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300] = {0};&lt;br /&gt;
  strcat(nca_path, path_from_lr);&lt;br /&gt;
  for (int i = 0; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Thus, a content path of the maximum length (0x300 bytes) would result in strcat writing a NULL terminator past the end of the nca_path buffer.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[6.0.0]], the new code looks like this:&lt;br /&gt;
&lt;br /&gt;
  char nca_path[0x300];&lt;br /&gt;
  strncpy(nca_path, path_from_lr, sizeof(nca_path));&lt;br /&gt;
  for (int i = 0; i  &amp;lt; sizeof(nca_path) &amp;amp;&amp;amp; nca_path[i]; i++) {&lt;br /&gt;
      if (nca_path[i] == &#039;\\&#039;) { nca_path[i] = &#039;/&#039;); }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: single null-byte stack overflow in Loader. Maybe (but probably not) loader code execution.&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| September 2, 2018&lt;br /&gt;
| September 19, 2018&lt;br /&gt;
| SciresM&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
Flaws in this category pertain to any non-built-in system module.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| 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.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  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.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], ReSwitched Team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|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.&lt;br /&gt;
|&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|-&lt;br /&gt;
| expLDR (sysmodule handle table exhaustion)&lt;br /&gt;
| Most sysmodules share common template code to handle IPC control messages. The command DuplicateSession (type 5 command 2)&#039;s template code will abort() if it fails to duplicate a session&#039;s handle for the requester. Because many sysmodules have limited handle table size (smaller than the browser/other entrypoints), repeatedly requesting to duplicate one&#039;s session will cause the sysmodule to run out of handle table space and abort, causing the service to release all its handles cleanly.&lt;br /&gt;
| Sysmodule crashes.  Most usefully, crashing ldr allows access to fsp-ldr and crashing pm allows access to fsp-pr. Useless after [[4.0.0]], which mitigated a number of single-session service access issues.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| [[4.1.0]]&lt;br /&gt;
| 24 June 2017&lt;br /&gt;
| 8 March 2018&lt;br /&gt;
| [[User:daeken|daeken]]&lt;br /&gt;
|-&lt;br /&gt;
| Transfer Memory leak in nvservices system module&lt;br /&gt;
| The nvservices sysmodule does not clear most of its transfer memory prior to release.&lt;br /&gt;
| The calling process can read key bits of memory, including breaking ASLR (by revealing the image base) and exposing the address of other transfer memory to set up attacks. More details here: [https://daeken.svbtle.com/nintendo-switch-nvservices-info-leak transfermeme (nvservices info leak)] by [[User:daeken|daeken]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| [[6.0.0]]&lt;br /&gt;
| June 2017&lt;br /&gt;
| 16 October 2018&lt;br /&gt;
| [[User:qlutoo|qlutoo]] and [[User:hexkyz|hexkyz]],&lt;br /&gt;
[[User:daeken|daeken]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
| OOB write in audio system module&lt;br /&gt;
| Prior to [[2.0.0]], the [[Audio_services#audout:u|AppendAudioOutBuffer]] and [[Audio_services#audin:u|AppendAudioInBuffer]] IPC commands would blindly increment the appended buffers&#039; count while using said count value as an index to where the user data should be copied into. This resulted in an 0x28 bytes, user controlled, out-of-bounds memory write into the [[Audio_services|audio]] sysmodule&#039;s memory space.&lt;br /&gt;
Combined with the [[Audio_services#audout:u|GetReleasedAudioOutBuffer]] or [[Audio_services#audin:u|GetReleasedAudioInBuffer]] commands, this could also be used as an 8 byte infoleak.&lt;br /&gt;
&lt;br /&gt;
In [[2.0.0]], the commands now return error code 0x1099 if the number of unreleased buffers exceeds 0x1F.&lt;br /&gt;
| Code execution under audio sysmodule&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| &lt;br /&gt;
| November 2, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
| nvhax (memory corruption in nvservices system module)&lt;br /&gt;
| Prior to [[6.2.0]], the [[NV_services|nvservices]] ioctl [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] would take a single &amp;quot;pwarpstate&amp;quot; argument which would be interpreted by nvservices as a memory pointer for writing 2 &amp;quot;warpstate&amp;quot; structs (one for each Streaming Multiprocessor).&lt;br /&gt;
This resulted in nvservices attempting to blindly memcpy into this user supplied address and trigger a crash. However, if paired with an infoleak, this could be used to arbitrarily write 0x30 bytes anywhere in nvservices&#039; memory space.&lt;br /&gt;
Additionally, the &amp;quot;warpstate&amp;quot; struct itself was never initialized, which means nvservices would leak the 0x30 bytes from the stack. By invoking other ioctls it was also possible to partially control the stack contents and achieve a usable arbitrary memory write primitive.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#.2Fdev.2Fnvhost-ctrl-gpu|NVGPU_GPU_IOCTL_WAIT_FOR_PAUSE]] now takes 2 inline &amp;quot;warpstate&amp;quot; structs instead of a &amp;quot;pwarpstate&amp;quot; pointer, thus effectively avoiding the bad memcpy.&lt;br /&gt;
| Code execution under nvservices sysmodule&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 5, 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| [[User:hexkyz|hexkyz]]&lt;br /&gt;
|-&lt;br /&gt;
| Infoleak in nvservices system module&lt;br /&gt;
| The [[NV_services|nvservices]] ioctl [[NV_services#NVMAP_IOC_ALLOC|NVMAP_IOC_ALLOC]] takes an optional argument &amp;quot;addr&amp;quot; which allows the calling process to pass a pointer to user allocated memory for backing a nvmap object. If &amp;quot;addr&amp;quot; is left as 0, nvservices uses the transfer memory region (donated by the user during initialization) instead, when allocating memory for the nvmap object.&lt;br /&gt;
By design, freeing the nvmap object by calling the ioctl [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] returns, in its &amp;quot;refcount&amp;quot; argument, the user address previously supplied if the reference count reaches 0.&lt;br /&gt;
However, prior to [[6.2.0]], the case where the transfer memory region is used to allocate the nvmap object was not taken into account, thus resulting in [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] leaking back an address from within the transfer memory region mapped in nvservices&#039; memory space.&lt;br /&gt;
&lt;br /&gt;
In [[6.2.0]], [[NV_services#NVMAP_IOC_FREE|NVMAP_IOC_FREE]] no longer returns the address when the transfer memory region is used instead of user supplied memory.&lt;br /&gt;
| Combined with other vulnerabilities: Defeating ASLR in nvservices sysmodule.&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| [[6.2.0]]&lt;br /&gt;
| April 2017&lt;br /&gt;
| November 24, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=NCM_services&amp;diff=4789</id>
		<title>NCM services</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=NCM_services&amp;diff=4789"/>
		<updated>2018-06-22T22:21:43Z</updated>

		<summary type="html">&lt;p&gt;Rei: /* NcaID */ typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;NCM contains services for internal file path and content management.&lt;br /&gt;
&lt;br /&gt;
= Location Resolver services =&lt;br /&gt;
== lr ==&lt;br /&gt;
This is &amp;quot;nn::lr::ILocationResolverManager&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Arguments || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || OpenLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 1 || OpenRegisteredLocationResolver || None || &lt;br /&gt;
|-&lt;br /&gt;
| 2 || RefreshLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 3 || [2.0.0+] OpenAddOnContentLocationResolver || None  ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The only sysmodules which use this service are [[Filesystem_services|FS]], [[Loader_services|Loader]], and [[NS_Services|NS]]. [[boot2]] has access but doesn&#039;t use it.&lt;br /&gt;
&lt;br /&gt;
=== ILocationResolver ===&lt;br /&gt;
This is &amp;quot;nn::lr::ILocationResolver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || [[#ResolveProgramPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 1 || [[#RedirectProgramPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 2 || [[#ResolveApplicationControlPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 3 || [[#ResolveApplicationHtmlDocumentPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 4 || [[#ResolveDataPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 5 || [[#RedirectApplicationControlPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 6 || [[#RedirectApplicationHtmlDocumentPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [[#ResolveApplicationLegalInformationPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 8 || [[#RedirectApplicationLegalInformationPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 9 || [[#Refresh]]&lt;br /&gt;
|-&lt;br /&gt;
| 10 || [5.0.0+] [[#SetProgramNcaPath2]]&lt;br /&gt;
|-&lt;br /&gt;
| 11 || [5.0.0+] [[#ClearLocationResolver2]]&lt;br /&gt;
|-&lt;br /&gt;
| 12 || [5.0.0+] [[#DeleteProgramNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 13 || [5.0.0+] [[#DeleteControlNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [5.0.0+] [[#DeleteDocHtmlNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 15 || [5.0.0+] [[#DeleteInfoHtmlNcaPath]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the supplied [[Filesystem_services#StorageId|StorageID]] is 1 (Host), a different set of internal functions is used to handle these commands. In this more restricted set of functions, GetControlNcaPath is stubbed and only returns error 0x608.&lt;br /&gt;
&lt;br /&gt;
The Get* commands load the [[Filesystem_services|ContentPath]] from linked-lists&#039; [[#Location_List_Entry|entries]] in memory using the input TitleID. When the command fails to find an entry for the specified TitleID, 0x408 is returned for GetProgramNcaPath and 0xA08 is returned for the rest.&lt;br /&gt;
&lt;br /&gt;
The Set* commands always return 0 and add a new entry to the list. If a matching entry is found, it&#039;s removed first.&lt;br /&gt;
&lt;br /&gt;
==== ResolveProgramPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
&lt;br /&gt;
==== RedirectProgramPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 0.&lt;br /&gt;
&lt;br /&gt;
==== ResolveApplicationControlPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
==== ResolveApplicationHtmlDocumentPath====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].&lt;br /&gt;
&lt;br /&gt;
==== ResolveDataPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
==== RedirectApplicationControlPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== RedirectApplicationHtmlDocumentPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== ResolveApplicationLegalInformationPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].&lt;br /&gt;
&lt;br /&gt;
==== RedirectApplicationLegalInformationPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== Refresh ====&lt;br /&gt;
Takes no input. Frees all linked-lists&#039; entries that have &#039;&#039;&#039;flag&#039;&#039;&#039; set to 0.&lt;br /&gt;
&lt;br /&gt;
==== SetProgramNcaPath2 ====&lt;br /&gt;
Same as [[#SetProgramNcaPath|SetProgramNcaPath]], but inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== ClearLocationResolver2 ====&lt;br /&gt;
Takes no input. Frees all linked-lists&#039; entries that have &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== DeleteProgramNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
==== DeleteControlNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
==== DeleteDocHtmlNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
==== DeleteInfoHtmlNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
=== IRegisteredLocationResolver ===&lt;br /&gt;
This is &amp;quot;nn::lr::IRegisteredLocationResolver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This works like [[#ILocationResolver]], but only two types of NCA paths can be gotten/set. In addition, each type has a fallback path that can be set for a single title ID at a time.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Arguments || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || ResolveProgramPath || u64 TitleID + C descriptor || Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
|-&lt;br /&gt;
| 1 || RegisterProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 0 fallback TID and path to the provided arguments.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || UnregisterProgramPath || u64 TitleID || If the Type 0 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.&lt;br /&gt;
|-&lt;br /&gt;
| 3 || RedirectProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 4 || [2.0.0+] ResolveHtmlDocumentPath || u64 TitleID + C descriptor ||&lt;br /&gt;
|-&lt;br /&gt;
| 5 || [2.0.0+] RegisterHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 1 fallback TID and path to the provided arguments.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || [2.0.0+] UnregisterHtmlDocumentPath || u64 TitleID || If the Type 1 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [2.0.0+] RedirectHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== IAddOnContentLocationResolver ===&lt;br /&gt;
This is &amp;quot;nn::lr::IAddOnContentLocationResolver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Arguments || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || ResolveAddOnContentPath || u64 TitleID + C descriptor || &lt;br /&gt;
|-&lt;br /&gt;
| 1 || RegisterAddOnContentStorage || [[Filesystem_services#StorageId|StorageID]] + u64 TitleID || &lt;br /&gt;
|-&lt;br /&gt;
| 2 || UnregisterAllAddOnContentPath || None || Clears all registered titles here.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Location List Entry ===&lt;br /&gt;
Total size is 0x320 bytes. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset || Size || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0 || 0x8|| Pointer to previous entry&lt;br /&gt;
|-&lt;br /&gt;
| 0x8 || 0x8|| Pointer to next entry&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || 0x8|| TitleID&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || 0x300 || [[Filesystem_services|ContentPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x318 || 0x4 || Flag&lt;br /&gt;
|-&lt;br /&gt;
| 0x31C || 0x4 || Padding&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Content Manager services =&lt;br /&gt;
== ncm ==&lt;br /&gt;
This is &amp;quot;nn::ncm::IContentManager&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || CreateContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CreateContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 2 || VerifyContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 3 || VerifyContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 4 || OpenContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.&lt;br /&gt;
|-&lt;br /&gt;
| 5 || OpenContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || [1.0.0] CloseContentStorageForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentStorage-&amp;gt;CloseAndFlushStorage().&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [1.0.0] CloseContentMetaDatabaseForcibly || Takes a [[Filesystem_services#StorageId|StorageID]].  Calls IContentMetaDatabase-&amp;gt;CloseMetaDatabase().&lt;br /&gt;
|-&lt;br /&gt;
| 8 || CleanupContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and deletes the associated savedata.&lt;br /&gt;
|-&lt;br /&gt;
| 9 || [2.0.0+] OpenContentStorage2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentStorage for the StorageID to be gotten with GetIContentStorage. Note: Name is not official.&lt;br /&gt;
|-&lt;br /&gt;
| 10 || [2.0.0+] CloseContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentStorage. Note: Name is not official.&lt;br /&gt;
|-&lt;br /&gt;
| 11 || [2.0.0+] OpenContentMetaDatabase2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentMetaDatabase for the StorageID to be gotten with GetIContentMetaDatabase. Note: Name is not official.&lt;br /&gt;
|-&lt;br /&gt;
| 12 || [2.0.0+] CloseContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentMetaDatabase. Note: Name is not official.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== IContentStorage ===&lt;br /&gt;
This is &amp;quot;nn::ncm::IContentStorage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage.&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CreatePlaceHolder || Takes two [[#NcaID]]s, and a u64 filesize.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || DeletePlaceHolder || Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 3 || HasPlaceHolder ||  Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 4 || WritePlaceHolder || Takes a [[#NcaID]], a u64-offset, and type 5 buffer. Writes the buffer to the file for the NcaID&#039;s placeholder path at the specified offset.&lt;br /&gt;
|-&lt;br /&gt;
| 5 || Register || Takes two [[#NcaID]]s, moves the Placeholder NCA content to the registered NCA path.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || Delete || Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 7 || Has || Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 8 || GetPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].&lt;br /&gt;
|-&lt;br /&gt;
| 9 || GetPlaceHolderPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].&lt;br /&gt;
|-&lt;br /&gt;
| 10 || CleanupAllPlaceHolder || Deletes and re-creates the Placeholder directory.&lt;br /&gt;
|-&lt;br /&gt;
| 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory.&lt;br /&gt;
|-&lt;br /&gt;
| 12 || [[#GetContentCount]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 13 || [[#ListContentId]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [[#GetSize]] || &lt;br /&gt;
|-&lt;br /&gt;
| 15 || DisableForcibly || Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805.&lt;br /&gt;
|-&lt;br /&gt;
| 16 || [2.0.0+] RevertToPlaceHolder || Takes three 0x10-sized [[#NcaID]]s. Creates the registered directory NCA path, and renames the placeholder path to the registered NCA path.&lt;br /&gt;
|-&lt;br /&gt;
| 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[#NcaID]], and a u64 size&lt;br /&gt;
|-&lt;br /&gt;
| 18 || [2.0.0+] [[#ReadContentIdFile]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 19 || [2.0.0+] GetRightsIdFromPlaceHolderId || Gets the Rights ID for the [[#NcaID]]&#039;s placeholder path.&lt;br /&gt;
|-&lt;br /&gt;
| 20 || [2.0.0+] GetRightsIdFromContentId || Gets the Rights ID for the [[#NcaID]]&#039;s registered path&lt;br /&gt;
|-&lt;br /&gt;
| 21 || [2.0.0+] WriteContentForDebug || Takes a [[#NcaID]], a u64 offset, and a type 5 buffer. On debug units, writes the buffer to the NCA&#039;s registered path. On retail units, this just aborts.&lt;br /&gt;
|-&lt;br /&gt;
| 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage.&lt;br /&gt;
|-&lt;br /&gt;
| 23 || [2.0.0+] GetTotalSpaceSize || Gets total space for the storage.&lt;br /&gt;
|-&lt;br /&gt;
| 24 || [3.0.0+] FlushStorage || Flushes resources for the storage without closing it.&lt;br /&gt;
|-&lt;br /&gt;
| 25 || [4.0.0+] || &lt;br /&gt;
|-&lt;br /&gt;
| 26 || [4.0.0+] || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== GeneratePlaceHolderId ====&lt;br /&gt;
Generates a random [[#NcaID]] for use as a placeholder.&lt;br /&gt;
&lt;br /&gt;
Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16);&lt;br /&gt;
&lt;br /&gt;
==== GetContentCount ====&lt;br /&gt;
Writes the total number of entries which can be read by GetEntries, to cmdreply &amp;lt;SFCO_offset&amp;gt;+0x10.&lt;br /&gt;
&lt;br /&gt;
==== ListContentId====&lt;br /&gt;
Takes an output buffer, u32 offset and gets all entries starting at that offset.&lt;br /&gt;
Returns number of entries read.&lt;br /&gt;
&lt;br /&gt;
Each entry is a [[#NcaID]].&lt;br /&gt;
&lt;br /&gt;
The total read entries is exactly the same as the number of &amp;quot;&amp;lt;hex&amp;gt;.nca&amp;quot; directories in the storage FS(or at least under the &amp;quot;registered&amp;quot; directory?).&lt;br /&gt;
&lt;br /&gt;
==== GetSize ====&lt;br /&gt;
Takes a [[#NcaID]] as input.&lt;br /&gt;
&lt;br /&gt;
Returns the total size readable by ReadEntryRaw. This is the same as the size-field in the [[NAX0]] &amp;quot;&amp;lt;NcaID&amp;gt;.nca/00&amp;quot; file.&lt;br /&gt;
&lt;br /&gt;
==== ReadContentIdFile ====&lt;br /&gt;
Takes an output buffer, a [[#NcaID]] as input, and a u64 file offset.&lt;br /&gt;
&lt;br /&gt;
Reads plaintext NCA file contents from the Registered path for the NcaID.&lt;br /&gt;
&lt;br /&gt;
=== IContentMetaDatabase ===&lt;br /&gt;
This is &amp;quot;nn::ncm::IContentMetaDatabase&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note the official name for Meta Record is &amp;quot;ContentMetaKey&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Set || Takes a [[NCA#Meta_records|Meta Record]], a type-5 [[NCA#Content_records|Content Records]] buffer and a u64 size.&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Get || Takes a [[NCA#Meta_records|Meta Record]], a type-6 buffer to write [[NCA#Content_records|Content Records]] to and a u64 size. Returns the actual Content Records size read.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Remove || Takes a [[NCA#Meta_records|Meta Record]], and removes the associated record.&lt;br /&gt;
|-&lt;br /&gt;
| 3 || GetContentIdByType || Takes a [[NCA#Meta_records|Meta Record]] and a u8 [[#Title_Types|Title Type]]. Returns a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 4 || ListContentInfo || Takes a type-6 buffer to write [[NCA#Content_records|Content Record]] entries to, a [[NCA#Meta_records|Meta Record]], and a u32 index into the Content Record entries to start copying from. Returns a u32 entries_read.&lt;br /&gt;
|-&lt;br /&gt;
| 5 || List || Takes a type-6 buffer to write [[NCA#Meta_records|Meta Record]]s to, a u32 [[#Title_Types|Title Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Meta Records with low &amp;lt;= record-&amp;gt;title_id &amp;lt;= high, and record-&amp;gt;type == type. Additionally requires record-&amp;gt;title_id == TID, if record-&amp;gt;type is Application, Patch, Add-On, or Delta.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[NCA#Meta_records|Meta Record]] with the highest version field for that title id.&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [[#ListApplication]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 8 || Has || Takes a [[NCA#Meta_records|Meta Record]] and returns whether that record is present in the database.&lt;br /&gt;
|-&lt;br /&gt;
| 9 || HasAll || Takes a type-5 buffer containing [[NCA#Meta_records|Meta Records]] (code assumes there are size/sizeof(meta_record) records in the buffer), and returns whether all of those records are present in the database.&lt;br /&gt;
|-&lt;br /&gt;
| 10 || GetSize || Takes a [[NCA#Meta_records|Meta Record]], and returns the size of the associated [[NCA#Content_records|Content Records]].&lt;br /&gt;
|-&lt;br /&gt;
| 11 || GetRequiredSystemVersion || Takes a [[NCA#Meta_records|Meta Record]], and returns u32 from ContentRecords + 16 (only if the Meta record has type Application or Patch).&lt;br /&gt;
|-&lt;br /&gt;
| 12 || GetPatchId || Takes a [[NCA#Meta_records|Meta Record]], and returns the update title id for that record.&lt;br /&gt;
|-&lt;br /&gt;
| 13 || DisableForcibly ||  Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05.&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[#NcaID]]s.&lt;br /&gt;
|-&lt;br /&gt;
| 15 || Commit || Flushes the in-memory database to savedata.&lt;br /&gt;
|-&lt;br /&gt;
| 16 || HasContent || Takes a [[NCA#Meta_records|Meta Record]] and an [[#NcaID]]. Returns whether the content records for that meta record contain the NcaID.&lt;br /&gt;
|-&lt;br /&gt;
| 17 || ListContentMetaInfo || Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]].&lt;br /&gt;
|-&lt;br /&gt;
| 18 || GetAttributes || Takes a [[NCA#Meta_records|Meta Record]], and returns u8 from ContentRecords + 6.&lt;br /&gt;
|-&lt;br /&gt;
| 19 || [2.0.0+] GetRequiredApplicationVersion || Does the same thing as GetEntryUnknownRecordSize, but for AddOnContents.&lt;br /&gt;
|-&lt;br /&gt;
| 20 || [5.0.0+] ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== ListApplication ====&lt;br /&gt;
Each 24-byte entry (officially &amp;quot;ApplicationContentMetaKey&amp;quot;) is as follows:&lt;br /&gt;
  [[NCA#Meta_records|meta_record]] meta_record;&lt;br /&gt;
  u64    base_title_id;&lt;br /&gt;
&lt;br /&gt;
This function takes in a type 6 buffer to write entries to, and a u8 &amp;quot;filter&amp;quot; [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer.&lt;br /&gt;
&lt;br /&gt;
This func returns a u32 num_entries_written, and a u32 num_entries_total.&lt;br /&gt;
&lt;br /&gt;
==== ReadEntryMetaRecords ====&lt;br /&gt;
Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]] entry. Returns a u32 for total_read_entries.&lt;br /&gt;
&lt;br /&gt;
Reads the meta records stored in the entry&#039;s content records into the output buffer.&lt;br /&gt;
&lt;br /&gt;
This is used, for example, with System Update title 0100000000000816, which contains Meta Records for all other systitles in its Content Records.&lt;br /&gt;
&lt;br /&gt;
==== LookupOrphanContent ====&lt;br /&gt;
Takes a type-6 byte buffer, and a type-5 buffer containing [[#NcaID]]s.&lt;br /&gt;
&lt;br /&gt;
This function was stubbed to return 0xDC05 in [[2.0.0]].&lt;br /&gt;
&lt;br /&gt;
On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[#NcaID]] in the input buffer, it checks if that NcaID is present anywhere in the database, and if so writes 0 to the corresponding output byte.&lt;br /&gt;
&lt;br /&gt;
In pseudocode, the function basically does the following:&lt;br /&gt;
&lt;br /&gt;
for i in range(len(out_buf)):&lt;br /&gt;
    out_buf[i] = 1&lt;br /&gt;
&lt;br /&gt;
for i, NcaID in NcaIDs:&lt;br /&gt;
    if is_present_in_database(NcaID):&lt;br /&gt;
        out_buf[i] = 0&lt;br /&gt;
&lt;br /&gt;
=== NcaID ===&lt;br /&gt;
This is a 0x10-byte entry. This is originally from the hex portion of &amp;quot;&amp;lt;hex&amp;gt;.nca&amp;quot; directory-names from this storage FS(like [[SD_Filesystem|SD]]). This is also referred to as &amp;quot;ContentId&amp;quot; in the official SDK.&lt;br /&gt;
&lt;br /&gt;
The NcaID is the same as the first 0x10-bytes from the calculated SHA256 hash, from hashing the entire output from ReadEntryRaw.&lt;br /&gt;
&lt;br /&gt;
=== Enums ===&lt;br /&gt;
==== Title Types ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x01&lt;br /&gt;
| System Programs ([[Title_list#System_Modules|System Modules]] or [[Title_list#System_Applets|System Applets]])&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| [[Title_list#System_Data_Archives|System Data Archives]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| System Update&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| [[Title_list|Firmware package A]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x05&lt;br /&gt;
| [[Title_list|Firmware package B]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x80&lt;br /&gt;
| Regular application&lt;br /&gt;
|-&lt;br /&gt;
| 0x81&lt;br /&gt;
| Update title&lt;br /&gt;
|-&lt;br /&gt;
| 0x82&lt;br /&gt;
| Add-on content&lt;br /&gt;
|-&lt;br /&gt;
| 0x83&lt;br /&gt;
| Delta title&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ncm:v ==&lt;br /&gt;
This service doesn&#039;t normally exist on retail.&lt;br /&gt;
&lt;br /&gt;
[[Category:Services]]&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=NCM_services&amp;diff=4788</id>
		<title>NCM services</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=NCM_services&amp;diff=4788"/>
		<updated>2018-06-22T22:21:07Z</updated>

		<summary type="html">&lt;p&gt;Rei: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;NCM contains services for internal file path and content management.&lt;br /&gt;
&lt;br /&gt;
= Location Resolver services =&lt;br /&gt;
== lr ==&lt;br /&gt;
This is &amp;quot;nn::lr::ILocationResolverManager&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Arguments || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || OpenLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 1 || OpenRegisteredLocationResolver || None || &lt;br /&gt;
|-&lt;br /&gt;
| 2 || RefreshLocationResolver || [[Filesystem_services#StorageId|StorageID]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 3 || [2.0.0+] OpenAddOnContentLocationResolver || None  ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The only sysmodules which use this service are [[Filesystem_services|FS]], [[Loader_services|Loader]], and [[NS_Services|NS]]. [[boot2]] has access but doesn&#039;t use it.&lt;br /&gt;
&lt;br /&gt;
=== ILocationResolver ===&lt;br /&gt;
This is &amp;quot;nn::lr::ILocationResolver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || [[#ResolveProgramPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 1 || [[#RedirectProgramPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 2 || [[#ResolveApplicationControlPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 3 || [[#ResolveApplicationHtmlDocumentPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 4 || [[#ResolveDataPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 5 || [[#RedirectApplicationControlPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 6 || [[#RedirectApplicationHtmlDocumentPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [[#ResolveApplicationLegalInformationPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 8 || [[#RedirectApplicationLegalInformationPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 9 || [[#Refresh]]&lt;br /&gt;
|-&lt;br /&gt;
| 10 || [5.0.0+] [[#SetProgramNcaPath2]]&lt;br /&gt;
|-&lt;br /&gt;
| 11 || [5.0.0+] [[#ClearLocationResolver2]]&lt;br /&gt;
|-&lt;br /&gt;
| 12 || [5.0.0+] [[#DeleteProgramNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 13 || [5.0.0+] [[#DeleteControlNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [5.0.0+] [[#DeleteDocHtmlNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 15 || [5.0.0+] [[#DeleteInfoHtmlNcaPath]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If the supplied [[Filesystem_services#StorageId|StorageID]] is 1 (Host), a different set of internal functions is used to handle these commands. In this more restricted set of functions, GetControlNcaPath is stubbed and only returns error 0x608.&lt;br /&gt;
&lt;br /&gt;
The Get* commands load the [[Filesystem_services|ContentPath]] from linked-lists&#039; [[#Location_List_Entry|entries]] in memory using the input TitleID. When the command fails to find an entry for the specified TitleID, 0x408 is returned for GetProgramNcaPath and 0xA08 is returned for the rest.&lt;br /&gt;
&lt;br /&gt;
The Set* commands always return 0 and add a new entry to the list. If a matching entry is found, it&#039;s removed first.&lt;br /&gt;
&lt;br /&gt;
==== ResolveProgramPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
&lt;br /&gt;
==== RedirectProgramPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 0.&lt;br /&gt;
&lt;br /&gt;
==== ResolveApplicationControlPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
==== ResolveApplicationHtmlDocumentPath====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].&lt;br /&gt;
&lt;br /&gt;
==== ResolveDataPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
==== RedirectApplicationControlPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== RedirectApplicationHtmlDocumentPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== ResolveApplicationLegalInformationPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a C descriptor. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].&lt;br /&gt;
&lt;br /&gt;
==== RedirectApplicationLegalInformationPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039; and a X descriptor with a [[Filesystem_services#ContentPath|ContentPath]]. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].&lt;br /&gt;
&lt;br /&gt;
Inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== Refresh ====&lt;br /&gt;
Takes no input. Frees all linked-lists&#039; entries that have &#039;&#039;&#039;flag&#039;&#039;&#039; set to 0.&lt;br /&gt;
&lt;br /&gt;
==== SetProgramNcaPath2 ====&lt;br /&gt;
Same as [[#SetProgramNcaPath|SetProgramNcaPath]], but inserts a new [[#Location_List_Entry|entry]] with &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== ClearLocationResolver2 ====&lt;br /&gt;
Takes no input. Frees all linked-lists&#039; entries that have &#039;&#039;&#039;flag&#039;&#039;&#039; set to 1.&lt;br /&gt;
&lt;br /&gt;
==== DeleteProgramNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
==== DeleteControlNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type3|NCA-type3]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
==== DeleteDocHtmlNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type4|NCA-type4]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
==== DeleteInfoHtmlNcaPath ====&lt;br /&gt;
Takes an u64 &#039;&#039;&#039;TitleID&#039;&#039;&#039;. Used for [[NCA_Content_FS#NCA-type5|NCA-type5]].&lt;br /&gt;
&lt;br /&gt;
Removes the [[#Location_List_Entry|entry]] that matches the input TitleID.&lt;br /&gt;
&lt;br /&gt;
=== IRegisteredLocationResolver ===&lt;br /&gt;
This is &amp;quot;nn::lr::IRegisteredLocationResolver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This works like [[#ILocationResolver]], but only two types of NCA paths can be gotten/set. In addition, each type has a fallback path that can be set for a single title ID at a time.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Arguments || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || ResolveProgramPath || u64 TitleID + C descriptor || Used for [[NCA_Content_FS#NCA-type1|NCA-type1]].&lt;br /&gt;
|-&lt;br /&gt;
| 1 || RegisterProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 0 fallback TID and path to the provided arguments.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || UnregisterProgramPath || u64 TitleID || If the Type 0 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.&lt;br /&gt;
|-&lt;br /&gt;
| 3 || RedirectProgramPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 4 || [2.0.0+] ResolveHtmlDocumentPath || u64 TitleID + C descriptor ||&lt;br /&gt;
|-&lt;br /&gt;
| 5 || [2.0.0+] RegisterHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] || Sets the Type 1 fallback TID and path to the provided arguments.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || [2.0.0+] UnregisterHtmlDocumentPath || u64 TitleID || If the Type 1 fallback TID is == argument TID, unregisters the fallback path. Otherwise, noop.&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [2.0.0+] RedirectHtmlDocumentPath || u64 TitleID + X descriptor [[Filesystem_services#ContentPath|ContentPath]] ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== IAddOnContentLocationResolver ===&lt;br /&gt;
This is &amp;quot;nn::lr::IAddOnContentLocationResolver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Arguments || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || ResolveAddOnContentPath || u64 TitleID + C descriptor || &lt;br /&gt;
|-&lt;br /&gt;
| 1 || RegisterAddOnContentStorage || [[Filesystem_services#StorageId|StorageID]] + u64 TitleID || &lt;br /&gt;
|-&lt;br /&gt;
| 2 || UnregisterAllAddOnContentPath || None || Clears all registered titles here.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Location List Entry ===&lt;br /&gt;
Total size is 0x320 bytes. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset || Size || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0 || 0x8|| Pointer to previous entry&lt;br /&gt;
|-&lt;br /&gt;
| 0x8 || 0x8|| Pointer to next entry&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || 0x8|| TitleID&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || 0x300 || [[Filesystem_services|ContentPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x318 || 0x4 || Flag&lt;br /&gt;
|-&lt;br /&gt;
| 0x31C || 0x4 || Padding&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Content Manager services =&lt;br /&gt;
== ncm ==&lt;br /&gt;
This is &amp;quot;nn::ncm::IContentManager&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || CreateContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CreateContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 2 || VerifyContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 3 || VerifyContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]].&lt;br /&gt;
|-&lt;br /&gt;
| 4 || OpenContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.&lt;br /&gt;
|-&lt;br /&gt;
| 5 || OpenContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], [2.0.0+] Only returns a storage if one has previously been opened globally via OpenIContentStorage.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || [1.0.0] CloseContentStorageForcibly || Takes a [[Filesystem_services#StorageId|StorageID]]. Calls IContentStorage-&amp;gt;CloseAndFlushStorage().&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [1.0.0] CloseContentMetaDatabaseForcibly || Takes a [[Filesystem_services#StorageId|StorageID]].  Calls IContentMetaDatabase-&amp;gt;CloseMetaDatabase().&lt;br /&gt;
|-&lt;br /&gt;
| 8 || CleanupContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and deletes the associated savedata.&lt;br /&gt;
|-&lt;br /&gt;
| 9 || [2.0.0+] OpenContentStorage2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentStorage for the StorageID to be gotten with GetIContentStorage. Note: Name is not official.&lt;br /&gt;
|-&lt;br /&gt;
| 10 || [2.0.0+] CloseContentStorage || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentStorage. Note: Name is not official.&lt;br /&gt;
|-&lt;br /&gt;
| 11 || [2.0.0+] OpenContentMetaDatabase2 || Takes a [[Filesystem_services#StorageId|StorageID]], and opens an IContentMetaDatabase for the StorageID to be gotten with GetIContentMetaDatabase. Note: Name is not official.&lt;br /&gt;
|-&lt;br /&gt;
| 12 || [2.0.0+] CloseContentMetaDatabase || Takes a [[Filesystem_services#StorageId|StorageID]], and closes the associated IContentMetaDatabase. Note: Name is not official.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== IContentStorage ===&lt;br /&gt;
This is &amp;quot;nn::ncm::IContentStorage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage.&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CreatePlaceHolder || Takes two [[#NcaID]]s, and a u64 filesize.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || DeletePlaceHolder || Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 3 || HasPlaceHolder ||  Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 4 || WritePlaceHolder || Takes a [[#NcaID]], a u64-offset, and type 5 buffer. Writes the buffer to the file for the NcaID&#039;s placeholder path at the specified offset.&lt;br /&gt;
|-&lt;br /&gt;
| 5 || Register || Takes two [[#NcaID]]s, moves the Placeholder NCA content to the registered NCA path.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || Delete || Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 7 || Has || Takes a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 8 || GetPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].&lt;br /&gt;
|-&lt;br /&gt;
| 9 || GetPlaceHolderPath || Takes a [[#NcaID]]. Returns a [[Filesystem_services#ContentPath|Content Path]].&lt;br /&gt;
|-&lt;br /&gt;
| 10 || CleanupAllPlaceHolder || Deletes and re-creates the Placeholder directory.&lt;br /&gt;
|-&lt;br /&gt;
| 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory.&lt;br /&gt;
|-&lt;br /&gt;
| 12 || [[#GetContentCount]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 13 || [[#ListContentId]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [[#GetSize]] || &lt;br /&gt;
|-&lt;br /&gt;
| 15 || DisableForcibly || Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805.&lt;br /&gt;
|-&lt;br /&gt;
| 16 || [2.0.0+] RevertToPlaceHolder || Takes three 0x10-sized [[#NcaID]]s. Creates the registered directory NCA path, and renames the placeholder path to the registered NCA path.&lt;br /&gt;
|-&lt;br /&gt;
| 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[#NcaID]], and a u64 size&lt;br /&gt;
|-&lt;br /&gt;
| 18 || [2.0.0+] [[#ReadContentIdFile]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 19 || [2.0.0+] GetRightsIdFromPlaceHolderId || Gets the Rights ID for the [[#NcaID]]&#039;s placeholder path.&lt;br /&gt;
|-&lt;br /&gt;
| 20 || [2.0.0+] GetRightsIdFromContentId || Gets the Rights ID for the [[#NcaID]]&#039;s registered path&lt;br /&gt;
|-&lt;br /&gt;
| 21 || [2.0.0+] WriteContentForDebug || Takes a [[#NcaID]], a u64 offset, and a type 5 buffer. On debug units, writes the buffer to the NCA&#039;s registered path. On retail units, this just aborts.&lt;br /&gt;
|-&lt;br /&gt;
| 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage.&lt;br /&gt;
|-&lt;br /&gt;
| 23 || [2.0.0+] GetTotalSpaceSize || Gets total space for the storage.&lt;br /&gt;
|-&lt;br /&gt;
| 24 || [3.0.0+] FlushStorage || Flushes resources for the storage without closing it.&lt;br /&gt;
|-&lt;br /&gt;
| 25 || [4.0.0+] || &lt;br /&gt;
|-&lt;br /&gt;
| 26 || [4.0.0+] || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== GeneratePlaceHolderId ====&lt;br /&gt;
Generates a random [[#NcaID]] for use as a placeholder.&lt;br /&gt;
&lt;br /&gt;
Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16);&lt;br /&gt;
&lt;br /&gt;
==== GetContentCount ====&lt;br /&gt;
Writes the total number of entries which can be read by GetEntries, to cmdreply &amp;lt;SFCO_offset&amp;gt;+0x10.&lt;br /&gt;
&lt;br /&gt;
==== ListContentId====&lt;br /&gt;
Takes an output buffer, u32 offset and gets all entries starting at that offset.&lt;br /&gt;
Returns number of entries read.&lt;br /&gt;
&lt;br /&gt;
Each entry is a [[#NcaID]].&lt;br /&gt;
&lt;br /&gt;
The total read entries is exactly the same as the number of &amp;quot;&amp;lt;hex&amp;gt;.nca&amp;quot; directories in the storage FS(or at least under the &amp;quot;registered&amp;quot; directory?).&lt;br /&gt;
&lt;br /&gt;
==== GetSize ====&lt;br /&gt;
Takes a [[#NcaID]] as input.&lt;br /&gt;
&lt;br /&gt;
Returns the total size readable by ReadEntryRaw. This is the same as the size-field in the [[NAX0]] &amp;quot;&amp;lt;NcaID&amp;gt;.nca/00&amp;quot; file.&lt;br /&gt;
&lt;br /&gt;
==== ReadContentIdFile ====&lt;br /&gt;
Takes an output buffer, a [[#NcaID]] as input, and a u64 file offset.&lt;br /&gt;
&lt;br /&gt;
Reads plaintext NCA file contents from the Registered path for the NcaID.&lt;br /&gt;
&lt;br /&gt;
=== IContentMetaDatabase ===&lt;br /&gt;
This is &amp;quot;nn::ncm::IContentMetaDatabase&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note the official name for Meta Record is &amp;quot;ContentMetaKey&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name || Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Set || Takes a [[NCA#Meta_records|Meta Record]], a type-5 [[NCA#Content_records|Content Records]] buffer and a u64 size.&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Get || Takes a [[NCA#Meta_records|Meta Record]], a type-6 buffer to write [[NCA#Content_records|Content Records]] to and a u64 size. Returns the actual Content Records size read.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Remove || Takes a [[NCA#Meta_records|Meta Record]], and removes the associated record.&lt;br /&gt;
|-&lt;br /&gt;
| 3 || GetContentIdByType || Takes a [[NCA#Meta_records|Meta Record]] and a u8 [[#Title_Types|Title Type]]. Returns a [[#NcaID]].&lt;br /&gt;
|-&lt;br /&gt;
| 4 || ListContentInfo || Takes a type-6 buffer to write [[NCA#Content_records|Content Record]] entries to, a [[NCA#Meta_records|Meta Record]], and a u32 index into the Content Record entries to start copying from. Returns a u32 entries_read.&lt;br /&gt;
|-&lt;br /&gt;
| 5 || List || Takes a type-6 buffer to write [[NCA#Meta_records|Meta Record]]s to, a u32 [[#Title_Types|Title Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Meta Records with low &amp;lt;= record-&amp;gt;title_id &amp;lt;= high, and record-&amp;gt;type == type. Additionally requires record-&amp;gt;title_id == TID, if record-&amp;gt;type is Application, Patch, Add-On, or Delta.&lt;br /&gt;
|-&lt;br /&gt;
| 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[NCA#Meta_records|Meta Record]] with the highest version field for that title id.&lt;br /&gt;
|-&lt;br /&gt;
| 7 || [[#ListApplication]] ||&lt;br /&gt;
|-&lt;br /&gt;
| 8 || Has || Takes a [[NCA#Meta_records|Meta Record]] and returns whether that record is present in the database.&lt;br /&gt;
|-&lt;br /&gt;
| 9 || HasAll || Takes a type-5 buffer containing [[NCA#Meta_records|Meta Records]] (code assumes there are size/sizeof(meta_record) records in the buffer), and returns whether all of those records are present in the database.&lt;br /&gt;
|-&lt;br /&gt;
| 10 || GetSize || Takes a [[NCA#Meta_records|Meta Record]], and returns the size of the associated [[NCA#Content_records|Content Records]].&lt;br /&gt;
|-&lt;br /&gt;
| 11 || GetRequiredSystemVersion || Takes a [[NCA#Meta_records|Meta Record]], and returns u32 from ContentRecords + 16 (only if the Meta record has type Application or Patch).&lt;br /&gt;
|-&lt;br /&gt;
| 12 || GetPatchId || Takes a [[NCA#Meta_records|Meta Record]], and returns the update title id for that record.&lt;br /&gt;
|-&lt;br /&gt;
| 13 || DisableForcibly ||  Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05.&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[#NcaID]]s.&lt;br /&gt;
|-&lt;br /&gt;
| 15 || Commit || Flushes the in-memory database to savedata.&lt;br /&gt;
|-&lt;br /&gt;
| 16 || HasContent || Takes a [[NCA#Meta_records|Meta Record]] and an [[#NcaID]]. Returns whether the content records for that meta record contain the NcaID.&lt;br /&gt;
|-&lt;br /&gt;
| 17 || ListContentMetaInfo || Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]].&lt;br /&gt;
|-&lt;br /&gt;
| 18 || GetAttributes || Takes a [[NCA#Meta_records|Meta Record]], and returns u8 from ContentRecords + 6.&lt;br /&gt;
|-&lt;br /&gt;
| 19 || [2.0.0+] GetRequiredApplicationVersion || Does the same thing as GetEntryUnknownRecordSize, but for AddOnContents.&lt;br /&gt;
|-&lt;br /&gt;
| 20 || [5.0.0+] ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== ListApplication ====&lt;br /&gt;
Each 24-byte entry (officially &amp;quot;ApplicationContentMetaKey&amp;quot;) is as follows:&lt;br /&gt;
  [[NCA#Meta_records|meta_record]] meta_record;&lt;br /&gt;
  u64    base_title_id;&lt;br /&gt;
&lt;br /&gt;
This function takes in a type 6 buffer to write entries to, and a u8 &amp;quot;filter&amp;quot; [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer.&lt;br /&gt;
&lt;br /&gt;
This func returns a u32 num_entries_written, and a u32 num_entries_total.&lt;br /&gt;
&lt;br /&gt;
==== ReadEntryMetaRecords ====&lt;br /&gt;
Takes a type-6 [[NCA#Meta_records|Meta Record]] output buffer, a u32 eoffset into that buffer, and an input [[NCA#Meta_records|Meta Record]] entry. Returns a u32 for total_read_entries.&lt;br /&gt;
&lt;br /&gt;
Reads the meta records stored in the entry&#039;s content records into the output buffer.&lt;br /&gt;
&lt;br /&gt;
This is used, for example, with System Update title 0100000000000816, which contains Meta Records for all other systitles in its Content Records.&lt;br /&gt;
&lt;br /&gt;
==== LookupOrphanContent ====&lt;br /&gt;
Takes a type-6 byte buffer, and a type-5 buffer containing [[#NcaID]]s.&lt;br /&gt;
&lt;br /&gt;
This function was stubbed to return 0xDC05 in [[2.0.0]].&lt;br /&gt;
&lt;br /&gt;
On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[#NcaID]] in the input buffer, it checks if that NcaID is present anywhere in the database, and if so writes 0 to the corresponding output byte.&lt;br /&gt;
&lt;br /&gt;
In pseudocode, the function basically does the following:&lt;br /&gt;
&lt;br /&gt;
for i in range(len(out_buf)):&lt;br /&gt;
    out_buf[i] = 1&lt;br /&gt;
&lt;br /&gt;
for i, NcaID in NcaIDs:&lt;br /&gt;
    if is_present_in_database(NcaID):&lt;br /&gt;
        out_buf[i] = 0&lt;br /&gt;
&lt;br /&gt;
=== NcaID ===&lt;br /&gt;
This is a 0x10-byte entry. This is originally from the hex portion of &amp;quot;&amp;lt;hex&amp;gt;.nca&amp;quot; directory-names from this storage FS(like [[SD_Filesystem|SD]]). This is also referred to as &amp;quot;ContentId&amp;quot; in the offical SDK.&lt;br /&gt;
&lt;br /&gt;
The NcaID is the same as the first 0x10-bytes from the calculated SHA256 hash, from hashing the entire output from ReadEntryRaw.&lt;br /&gt;
&lt;br /&gt;
=== Enums ===&lt;br /&gt;
==== Title Types ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x01&lt;br /&gt;
| System Programs ([[Title_list#System_Modules|System Modules]] or [[Title_list#System_Applets|System Applets]])&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| [[Title_list#System_Data_Archives|System Data Archives]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| System Update&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| [[Title_list|Firmware package A]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x05&lt;br /&gt;
| [[Title_list|Firmware package B]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x80&lt;br /&gt;
| Regular application&lt;br /&gt;
|-&lt;br /&gt;
| 0x81&lt;br /&gt;
| Update title&lt;br /&gt;
|-&lt;br /&gt;
| 0x82&lt;br /&gt;
| Add-on content&lt;br /&gt;
|-&lt;br /&gt;
| 0x83&lt;br /&gt;
| Delta title&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ncm:v ==&lt;br /&gt;
This service doesn&#039;t normally exist on retail.&lt;br /&gt;
&lt;br /&gt;
[[Category:Services]]&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=ETicket_services&amp;diff=4787</id>
		<title>ETicket services</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=ETicket_services&amp;diff=4787"/>
		<updated>2018-06-22T21:49:20Z</updated>

		<summary type="html">&lt;p&gt;Rei: /* es */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= es =&lt;br /&gt;
This is &amp;quot;nn::es::IETicketService&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name&lt;br /&gt;
|-&lt;br /&gt;
| 1 || ImportTicket&lt;br /&gt;
|-&lt;br /&gt;
| 2 || ImportTicketCertificateSet&lt;br /&gt;
|-&lt;br /&gt;
| 3 || DeleteTicket&lt;br /&gt;
|-&lt;br /&gt;
| 4 || DeletePersonalizedTicket&lt;br /&gt;
|-&lt;br /&gt;
| 5 || DeleteAllCommonTicket&lt;br /&gt;
|-&lt;br /&gt;
| 6 || DeleteAllPersonalizedTicket&lt;br /&gt;
|-&lt;br /&gt;
| 7 || DeleteAllPersonalizedTicketEx&lt;br /&gt;
|-&lt;br /&gt;
| 8 || GetTitleKey&lt;br /&gt;
|-&lt;br /&gt;
| 9 || CountCommonTicket&lt;br /&gt;
|-&lt;br /&gt;
| 10 || CountPersonalizedTicket&lt;br /&gt;
|-&lt;br /&gt;
| 11 || ListCommonTicket&lt;br /&gt;
|-&lt;br /&gt;
| 12 || ListPersonalizedTicket&lt;br /&gt;
|-&lt;br /&gt;
| 13 || ListMissingPersonalizedTicket&lt;br /&gt;
|-&lt;br /&gt;
| 14 || GetCommonTicketSize&lt;br /&gt;
|-&lt;br /&gt;
| 15 || GetPersonalizedTicketSize&lt;br /&gt;
|-&lt;br /&gt;
| 16 || GetCommonTicketData&lt;br /&gt;
|-&lt;br /&gt;
| 17 || GetPersonalizedTicketData&lt;br /&gt;
|-&lt;br /&gt;
| 18 || OwnTicket&lt;br /&gt;
|-&lt;br /&gt;
| 19 || GetTicketInfo&lt;br /&gt;
|-&lt;br /&gt;
| 20 || ListLightTicketInfo&lt;br /&gt;
|-&lt;br /&gt;
| 21 || [2.0.0+] SignData&lt;br /&gt;
|-&lt;br /&gt;
| 22 || [4.0.0+] GetCommonTicketAndCertificateSize&lt;br /&gt;
|-&lt;br /&gt;
| 23 || [4.0.0+] GetCommonTicketAndCertificateData&lt;br /&gt;
|-&lt;br /&gt;
| 24 || [4.0.0+] ImportPrepurchaseRecord&lt;br /&gt;
|-&lt;br /&gt;
| 25 || [4.0.0+] DeletePrepurchaseRecord&lt;br /&gt;
|-&lt;br /&gt;
| 26 || [4.0.0+] DeleteAllPrepurchaseRecord&lt;br /&gt;
|-&lt;br /&gt;
| 27 || [4.0.0+] CountPrepurchaseRecord&lt;br /&gt;
|-&lt;br /&gt;
| 28 || [4.0.0+] ListPrepurchaseRecord&lt;br /&gt;
|-&lt;br /&gt;
| 29 || [4.0.0+] ListPrepurchaseRecordInfo&lt;br /&gt;
|-&lt;br /&gt;
| 30 || [5.0.0+]&lt;br /&gt;
|-&lt;br /&gt;
| 31 || [5.0.0+]&lt;br /&gt;
|-&lt;br /&gt;
| 32 || [5.0.0+]&lt;br /&gt;
|-&lt;br /&gt;
| 33 || [5.0.0+]&lt;br /&gt;
|-&lt;br /&gt;
| 34 || [5.0.0+]&lt;br /&gt;
|-&lt;br /&gt;
| 35 || [5.0.0+]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=3767</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=3767"/>
		<updated>2018-02-18T22:58:59Z</updated>

		<summary type="html">&lt;p&gt;Rei: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== BootROM ==&lt;br /&gt;
The bootrom initializes two keyslots in the hardware engine:&lt;br /&gt;
&lt;br /&gt;
* the SBK (Secure Boot Key) in keyslot 14&lt;br /&gt;
* the SSK (Secure Storage Key) in keyslot 15.&lt;br /&gt;
&lt;br /&gt;
Reads from both of these keyslots are disabled by the bootROM.&lt;br /&gt;
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes.&lt;br /&gt;
&lt;br /&gt;
SBK is &#039;&#039;&#039;unique&#039;&#039;&#039; per console, and not shared among consoles as originally believed.&lt;br /&gt;
&lt;br /&gt;
The SSK is derived on boot via the SBK, the 32-bit console-unique &amp;quot;Device Key&amp;quot;, and hardware information stored in fuses.&lt;br /&gt;
&lt;br /&gt;
Pseudocode for the derivation is as follows:&lt;br /&gt;
  void generateSSK() {&lt;br /&gt;
      char keyBuffer[0x10]; // Used to store keydata&lt;br /&gt;
      uint hwInfoBuffer[4]; // Used to store info about hardware from fuses&lt;br /&gt;
      uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4.&lt;br /&gt;
      for (int i = 0; i &amp;lt; 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey&lt;br /&gt;
          ((uint *)keyBuffer)[i] = deviceKey;&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...})&lt;br /&gt;
      &lt;br /&gt;
      // Set up Hardware info buffer&lt;br /&gt;
      uint vendor_code = *((uint *)0x7000FA00) &amp;amp; 0x0000000F; // FUSE_VENDOR_CODE&lt;br /&gt;
      uint fab_code    = *((uint *)0x7000FA04) &amp;amp; 0x0000003F; // FUSE_FAB_CODE&lt;br /&gt;
      uint lot_code_0  = *((uint *)0x7000FA08) &amp;amp; 0xFFFFFFFF; // FUSE_LOT_CODE_0&lt;br /&gt;
      uint lot_code_1  = *((uint *)0x7000FA0C) &amp;amp; 0x0FFFFFFF; // FUSE_LOT_CODE_1&lt;br /&gt;
      uint wafer_id    = *((uint *)0x7000FA10) &amp;amp; 0x0000003F; // FUSE_WAFER_ID&lt;br /&gt;
      uint x_coord     = *((uint *)0x7000FA14) &amp;amp; 0x000001FF; // FUSE_X_COORDINATE&lt;br /&gt;
      uint y_coord     = *((uint *)0x7000FA18) &amp;amp; 0x000001FF; // FUSE_Y_COORDINATE&lt;br /&gt;
      uint unk_hw_fuse = *((uint *)0x7000FA20) &amp;amp; 0x0000003F; // Unknown cached fuse.&lt;br /&gt;
      &lt;br /&gt;
      // HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID&lt;br /&gt;
      hwInfoBuffer[0] = (lot_code_1 &amp;lt;&amp;lt; 30) | (wafer_id &amp;lt;&amp;lt; 24) | (x_coord &amp;lt;&amp;lt; 15) | (y_coord &amp;lt;&amp;lt; 6) | unk_hw_fuse;&lt;br /&gt;
      hwInfoBuffer[1] = (lot_code_0 &amp;lt;&amp;lt; 26) | (lot_code_1 &amp;gt;&amp;gt; 2);&lt;br /&gt;
      hwInfoBuffer[2] = (fab_code &amp;lt;&amp;lt; 26) | (lot_code_0 &amp;gt;&amp;gt; 6);&lt;br /&gt;
      hwInfoBuffer[3] = vendor_code;&lt;br /&gt;
      &lt;br /&gt;
      for (int i = 0; i &amp;lt; 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)&lt;br /&gt;
          keyBuffer[i] ^= ((char *)hwInfoBuffer)[i];&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER))&lt;br /&gt;
      &lt;br /&gt;
      setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer.&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
The falcon processor (TSEC) generates a special console-unique key (that will be referred to as the &amp;quot;tsec key&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This is presumably using data stored in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Security Engine ==&lt;br /&gt;
The security engine (SE) is responsible for the crypto done on the switch. SE is mapped to physical address 0x70012000.&lt;br /&gt;
&lt;br /&gt;
=== SE registers ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Register&lt;br /&gt;
! Offset&lt;br /&gt;
|-&lt;br /&gt;
| OPERATION_REG_OFFSET&lt;br /&gt;
| 0x008&lt;br /&gt;
|-&lt;br /&gt;
| INT_ENABLE_REG_OFFSET&lt;br /&gt;
| 0x00C&lt;br /&gt;
|-&lt;br /&gt;
| INT_STATUS_REG_OFFSET&lt;br /&gt;
| 0x010&lt;br /&gt;
|-&lt;br /&gt;
| CONFIG_REG_OFFSET&lt;br /&gt;
| 0x014&lt;br /&gt;
|-&lt;br /&gt;
| IN_LL_ADDR_REG_OFFSET&lt;br /&gt;
| 0x018&lt;br /&gt;
|-&lt;br /&gt;
| OUT_LL_ADDR_REG_OFFSET&lt;br /&gt;
| 0x024&lt;br /&gt;
|-&lt;br /&gt;
| HASH_RESULT_REG_OFFSET&lt;br /&gt;
| 0x030&lt;br /&gt;
|-&lt;br /&gt;
| CONTEXT_SAVE_CONFIG_REG_OFFSET&lt;br /&gt;
| 0x070&lt;br /&gt;
|-&lt;br /&gt;
| SHA_CONFIG_REG&lt;br /&gt;
| 0x200&lt;br /&gt;
|-&lt;br /&gt;
| SHA_MSG_LENGTH_REG&lt;br /&gt;
| 0x204&lt;br /&gt;
|-&lt;br /&gt;
| SHA_MSG_LEFT_REG&lt;br /&gt;
| 0x214&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_1&lt;br /&gt;
| 0x284&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_2&lt;br /&gt;
| 0x288&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_3&lt;br /&gt;
| 0x28C&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_4&lt;br /&gt;
| 0x290&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_5&lt;br /&gt;
| 0x294&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_6&lt;br /&gt;
| 0x298&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_7&lt;br /&gt;
| 0x29C&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_8&lt;br /&gt;
| 0x2A0&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_9&lt;br /&gt;
| 0x2A4&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_10&lt;br /&gt;
| 0x2A8&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_11&lt;br /&gt;
| 0x2AC&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_12&lt;br /&gt;
| 0x2B0&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_13&lt;br /&gt;
| 0x2B4&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_14&lt;br /&gt;
| 0x2B8&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_15&lt;br /&gt;
| 0x2BC&lt;br /&gt;
|-&lt;br /&gt;
| KEYSLOT_16&lt;br /&gt;
| 0x2C0&lt;br /&gt;
|-&lt;br /&gt;
| CRYPTO_REG&lt;br /&gt;
| 0x304&lt;br /&gt;
|-&lt;br /&gt;
| CRYPTO_CTR_REG&lt;br /&gt;
| 0x308&lt;br /&gt;
|-&lt;br /&gt;
| BLOCK_COUNT_REG&lt;br /&gt;
| 0x318&lt;br /&gt;
|-&lt;br /&gt;
| KEYTABLE_REG&lt;br /&gt;
| 0x31C&lt;br /&gt;
|-&lt;br /&gt;
| KEYTABLE_DATA0_REG&lt;br /&gt;
| 0x320&lt;br /&gt;
|-&lt;br /&gt;
| CRYPTO_KEYTABLE_DST_REG&lt;br /&gt;
| 0x330&lt;br /&gt;
|-&lt;br /&gt;
| RNG_CONFIG_REG&lt;br /&gt;
| 0x340&lt;br /&gt;
|-&lt;br /&gt;
| RNG_SRC_CONFIG_REG&lt;br /&gt;
| 0x344&lt;br /&gt;
|-&lt;br /&gt;
| RNG_RESEED_INTERVAL_REG&lt;br /&gt;
| 0x348&lt;br /&gt;
|-&lt;br /&gt;
| RSA_CONFIG&lt;br /&gt;
| 0x400&lt;br /&gt;
|-&lt;br /&gt;
| RSA_KEY_SIZE_REG_OFFSET&lt;br /&gt;
| 0x404&lt;br /&gt;
|-&lt;br /&gt;
| RSA_EXP_SIZE_REG_OFFSET&lt;br /&gt;
| 0x408&lt;br /&gt;
|-&lt;br /&gt;
| RSA_KEYSLOT_1&lt;br /&gt;
| 0x410&lt;br /&gt;
|-&lt;br /&gt;
| RSA_KEYSLOT_2&lt;br /&gt;
| 0x414&lt;br /&gt;
|-&lt;br /&gt;
| RSA_KEYTABLE_ADDR&lt;br /&gt;
| 0x420&lt;br /&gt;
|-&lt;br /&gt;
| RSA_KEYTABLE_DATA&lt;br /&gt;
| 0x424&lt;br /&gt;
|-&lt;br /&gt;
| RSA_OUTPUT&lt;br /&gt;
| 0x428&lt;br /&gt;
|-&lt;br /&gt;
| SPARE_0_REG_OFFSET&lt;br /&gt;
| 0x80C&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Package1 ==&lt;br /&gt;
&lt;br /&gt;
=== Key table during package1 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Package1Key&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [1.0.0-3.0.2] Key table after package1 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1 (Secure Monitor boot) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKeyForNewPerConsoleKeyGen&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| StaticKeyForNewPerConsoleKeyGen&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1 (Secure Monitor runtime) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| NewPerConsoleKey&lt;br /&gt;
| Secure Monitor init&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption.&lt;br /&gt;
&lt;br /&gt;
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only):&lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = aes_unwrap(f5b1eadb.., sbk)&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x11 ? simpleseed_dev0 : simpleseed_dev1, aes_unwrap(5ff9c2d9.., sbk))&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk))&lt;br /&gt;
&lt;br /&gt;
[4.0.0+] Above method was removed.&lt;br /&gt;
&lt;br /&gt;
Normal key generation looks like this on 1.0.0/2.0.0:&lt;br /&gt;
&lt;br /&gt;
  keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key    /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 3.0.0, they moved keyslots around a little to generate the same per-console key as 1.0.0:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot10 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 4.0.0 it was further moved around:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot15 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key        /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key          /* slot12 */ = aes_unwrap(normalseed_retail, keyblob+0x20)&lt;br /&gt;
  new_master_key      /* slot14 */ = aes_unwrap(2dc1f48d.., keyblob+0x20)&lt;br /&gt;
  new_per_console_key /* slot13 */ = aes_unwrap(0c9109db.., old_keyblob_key)&lt;br /&gt;
  per_console_key     /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
SBK and SSK keyslots are cleared after keys have been generated.&lt;br /&gt;
&lt;br /&gt;
See table above for which keys are console unique.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants.&lt;br /&gt;
&lt;br /&gt;
This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob.&lt;br /&gt;
&lt;br /&gt;
Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described in more detail [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Keyblob ====&lt;br /&gt;
There are 32 keyblobs written to NAND at factory, with each keyblob encrypted with a console-unique key derived from the console&#039;s SBK, the console&#039;s tsec key, and a constant specific to each keyblob.&lt;br /&gt;
&lt;br /&gt;
Despite being encrypted with console unique keys, though, the decrypted keyblob contents are shared for all consoles.&lt;br /&gt;
&lt;br /&gt;
==== Seeds ====&lt;br /&gt;
  normalseed_retail = d8a2410a...&lt;br /&gt;
  &lt;br /&gt;
  [1.0.0] wrapped_keyblob_key = df206f59...&lt;br /&gt;
  [1.0.0] simpleseed_dev0   = aff11423...&lt;br /&gt;
  [1.0.0] simpleseed_dev1   = 5e177ee1...&lt;br /&gt;
  [1.0.0] normalseed_dev    = 0542a0fd...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.0] wrapped_keyblob_key = 0c25615d...  &lt;br /&gt;
  [3.0.0] simpleseed_dev0   = de00216a...&lt;br /&gt;
  [3.0.0] simpleseed_dev1   = 2db7c0a1...&lt;br /&gt;
  [3.0.0] normalseed_dev    = 678c5a03...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.1] wrapped_keyblob_key = 337685ee...  &lt;br /&gt;
  [3.0.1] simpleseed_dev0   = e045f5ba...&lt;br /&gt;
  [3.0.1] simpleseed_dev1   = 84d92e0d...&lt;br /&gt;
  [3.0.1] normalseed_dev    = cd88155b...&lt;br /&gt;
  &lt;br /&gt;
  [4.0.0] wrapped_keyblob_key = 2d1f4880...&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor Init ==&lt;br /&gt;
On all versions, the key to decrypt [[Package2]] is generated by decrypting a constant seed with the master key. The key is erased after use.   &lt;br /&gt;
&lt;br /&gt;
Additionally, starting from 4.0.0, the Secure Monitor init will decrypt another constant seed successively with a special per console key and a special static key passed by package1loader, to generate a new per-console key. The operation will erase these special keys passed by package1loader. &lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=NS_services&amp;diff=1513</id>
		<title>NS services</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=NS_services&amp;diff=1513"/>
		<updated>2017-07-14T21:40:31Z</updated>

		<summary type="html">&lt;p&gt;Rei: /* ns:am */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is the Switch equivalent of [https://3dbrew.org/wiki/NS_and_APT_Services this].&lt;br /&gt;
&lt;br /&gt;
= ns:am =&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || [[#GetTitlesInfo]]&lt;br /&gt;
|-&lt;br /&gt;
| 1 ||&lt;br /&gt;
|-&lt;br /&gt;
| 2 ||&lt;br /&gt;
|-&lt;br /&gt;
| 3 ||&lt;br /&gt;
|-&lt;br /&gt;
| 4 ||&lt;br /&gt;
|-&lt;br /&gt;
| 5 ||&lt;br /&gt;
|-&lt;br /&gt;
| 6 ||&lt;br /&gt;
|-&lt;br /&gt;
| 7 ||&lt;br /&gt;
|-&lt;br /&gt;
| 8 ||&lt;br /&gt;
|-&lt;br /&gt;
| 9 ||&lt;br /&gt;
|-&lt;br /&gt;
| 11 ||&lt;br /&gt;
|-&lt;br /&gt;
| 13 ||&lt;br /&gt;
|-&lt;br /&gt;
| 16 ||&lt;br /&gt;
|-&lt;br /&gt;
| 17 ||&lt;br /&gt;
|-&lt;br /&gt;
| 19 ||&lt;br /&gt;
|-&lt;br /&gt;
| 21 || [[#GetTitlePatchContentNcaPath]]&lt;br /&gt;
|-&lt;br /&gt;
| 22 ||&lt;br /&gt;
|-&lt;br /&gt;
| 23 ||&lt;br /&gt;
|-&lt;br /&gt;
| 25 ||&lt;br /&gt;
|-&lt;br /&gt;
| 27 ||&lt;br /&gt;
|-&lt;br /&gt;
| 30 ||&lt;br /&gt;
|-&lt;br /&gt;
| 31 ||&lt;br /&gt;
|-&lt;br /&gt;
| 33 ||&lt;br /&gt;
|-&lt;br /&gt;
| 35 ||&lt;br /&gt;
|-&lt;br /&gt;
| 36 ||&lt;br /&gt;
|-&lt;br /&gt;
| 37 ||&lt;br /&gt;
|-&lt;br /&gt;
| 38 ||&lt;br /&gt;
|-&lt;br /&gt;
| 39 ||&lt;br /&gt;
|-&lt;br /&gt;
| 40 ||&lt;br /&gt;
|-&lt;br /&gt;
| 41 ||&lt;br /&gt;
|-&lt;br /&gt;
| 42 ||&lt;br /&gt;
|-&lt;br /&gt;
| 43 ||&lt;br /&gt;
|-&lt;br /&gt;
| 44 ||&lt;br /&gt;
|-&lt;br /&gt;
| 45 ||&lt;br /&gt;
|-&lt;br /&gt;
| 46 ||&lt;br /&gt;
|-&lt;br /&gt;
| 47 || [[#GetFreeSpace]]&lt;br /&gt;
|-&lt;br /&gt;
| 48 || [[#GetTotalSpace]]&lt;br /&gt;
|-&lt;br /&gt;
| 49 ||&lt;br /&gt;
|-&lt;br /&gt;
| 52 ||&lt;br /&gt;
|-&lt;br /&gt;
| 53 ||&lt;br /&gt;
|-&lt;br /&gt;
| 54 ||&lt;br /&gt;
|-&lt;br /&gt;
| 55 ||&lt;br /&gt;
|-&lt;br /&gt;
| 56 ||&lt;br /&gt;
|-&lt;br /&gt;
| 57 ||&lt;br /&gt;
|-&lt;br /&gt;
| 58 ||&lt;br /&gt;
|-&lt;br /&gt;
| 59 ||&lt;br /&gt;
|-&lt;br /&gt;
| 60 || [[#GetLanguageIdFromString]]&lt;br /&gt;
|-&lt;br /&gt;
| 61 ||&lt;br /&gt;
|-&lt;br /&gt;
| 62 ||&lt;br /&gt;
|-&lt;br /&gt;
| 63 ||&lt;br /&gt;
|-&lt;br /&gt;
| 64 ||&lt;br /&gt;
|-&lt;br /&gt;
| 65 ||&lt;br /&gt;
|-&lt;br /&gt;
| 100 || InitializeNXFileSystem?&lt;br /&gt;
|-&lt;br /&gt;
| 101 || ? Seems to wipe filesystem but keeps some data (savegames? users?)&lt;br /&gt;
|-&lt;br /&gt;
| 102 ||&lt;br /&gt;
|-&lt;br /&gt;
| 200 ||&lt;br /&gt;
|-&lt;br /&gt;
| 201 ||&lt;br /&gt;
|-&lt;br /&gt;
| 210 ||&lt;br /&gt;
|-&lt;br /&gt;
| 220 ||&lt;br /&gt;
|-&lt;br /&gt;
| 300 ||&lt;br /&gt;
|-&lt;br /&gt;
| 301 ||&lt;br /&gt;
|-&lt;br /&gt;
| 302 ||&lt;br /&gt;
|-&lt;br /&gt;
| 303 ||&lt;br /&gt;
|-&lt;br /&gt;
| 304 ||&lt;br /&gt;
|-&lt;br /&gt;
| 305 ||&lt;br /&gt;
|-&lt;br /&gt;
| 306 ||&lt;br /&gt;
|-&lt;br /&gt;
| 307 ||&lt;br /&gt;
|-&lt;br /&gt;
| 401 ||&lt;br /&gt;
|-&lt;br /&gt;
| 402 ||&lt;br /&gt;
|-&lt;br /&gt;
| 403 ||&lt;br /&gt;
|-&lt;br /&gt;
| 404 ||&lt;br /&gt;
|-&lt;br /&gt;
| 405 ||&lt;br /&gt;
|-&lt;br /&gt;
| 502 ||&lt;br /&gt;
|-&lt;br /&gt;
| 503 ||&lt;br /&gt;
|-&lt;br /&gt;
| 504 ||&lt;br /&gt;
|-&lt;br /&gt;
| 600 ||&lt;br /&gt;
|-&lt;br /&gt;
| 601 || [[#GetTitleInfo1]]&lt;br /&gt;
|-&lt;br /&gt;
| 602 ||&lt;br /&gt;
|-&lt;br /&gt;
| 603 ||&lt;br /&gt;
|-&lt;br /&gt;
| 604 ||&lt;br /&gt;
|-&lt;br /&gt;
| 605 || Used same way as [[#GetTitleInfo1]].&lt;br /&gt;
|-&lt;br /&gt;
| 700 ||&lt;br /&gt;
|-&lt;br /&gt;
| 701 ||&lt;br /&gt;
|-&lt;br /&gt;
| 702 ||&lt;br /&gt;
|-&lt;br /&gt;
| 703 ||&lt;br /&gt;
|-&lt;br /&gt;
| 704 ||&lt;br /&gt;
|-&lt;br /&gt;
| 705 ||&lt;br /&gt;
|-&lt;br /&gt;
| 800 ||&lt;br /&gt;
|-&lt;br /&gt;
| 801 ||&lt;br /&gt;
|-&lt;br /&gt;
| 900 ||&lt;br /&gt;
|-&lt;br /&gt;
| 901 ||&lt;br /&gt;
|-&lt;br /&gt;
| 902 ||&lt;br /&gt;
|-&lt;br /&gt;
| 903 ||&lt;br /&gt;
|-&lt;br /&gt;
| 904 ||&lt;br /&gt;
|-&lt;br /&gt;
| 905 ||&lt;br /&gt;
|-&lt;br /&gt;
| 906 ||&lt;br /&gt;
|-&lt;br /&gt;
| 907 ||&lt;br /&gt;
|-&lt;br /&gt;
| 908 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1000 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1001 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1200 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1300 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1301 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1302 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1400 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1500 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1501 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1502 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1503 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1600 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1700 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1800 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1801 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1802 ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== GetTitlePatchContentNcaPath ==&lt;br /&gt;
Takes a 0x16-type output buffer, an u8 [[NCA|type]], and an u64 titleID.&lt;br /&gt;
&lt;br /&gt;
The input titleID is used with the application-title table like various other cmds, anything not in that table can&#039;t be used with this.&lt;br /&gt;
&lt;br /&gt;
Returns a string path for the specified type of patch content with this titleID, otherwise returns regular-application paths when update-title not installed. Returns an error when the specified type of content doesn&#039;t exist for this title. Starts with &amp;quot;@{SdCardContent,UserContent}://&amp;quot; and ends in &amp;quot;.nca&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For gamecard content, the output path is: &amp;quot;@GcSXXXXXXXX:/&amp;lt;NcaId&amp;gt;.nca&amp;quot;. NCA-type0 with gamecard returns 0 with an empty output string.&lt;br /&gt;
&lt;br /&gt;
The output string is then used by the user-process with [[Filesystem_services|FS]] to mount the content.&lt;br /&gt;
&lt;br /&gt;
== GetFreeSpace ==&lt;br /&gt;
Takes an input media-id that must be 5.&lt;br /&gt;
&lt;br /&gt;
Returns the u64 from [[Content_Manager_services#IContentStorage]] cmd22.&lt;br /&gt;
&lt;br /&gt;
== GetTotalSpace ==&lt;br /&gt;
Takes an input media-id that must be 5.&lt;br /&gt;
&lt;br /&gt;
Returns the u64 from [[Content_Manager_services#IContentStorage]] cmd23.&lt;br /&gt;
&lt;br /&gt;
== GetLanguageIdFromString ==&lt;br /&gt;
Takes an input u8 pointer for the resulting Id to be written to and a string represented as a u64 (i.e 0x53552D6E65 for &#039;en-US&#039;).&lt;br /&gt;
&lt;br /&gt;
Returns 0 if an ID was successfully found, otherwise returns 0x25810.&lt;br /&gt;
&lt;br /&gt;
== GetTitlesInfo ==&lt;br /&gt;
Takes a type-6 output buffer and an u64.&lt;br /&gt;
&lt;br /&gt;
Returns an array of title-info entries using the specified offset and size. No input titleID is passed to this.&lt;br /&gt;
&lt;br /&gt;
== GetTitleInfo1 ==&lt;br /&gt;
Returns 0x10-byte entries using the specified titleID starting at the specified u32 entryindex. Can only return game titles. The second entry if any is the update-title usually. When the input entryindex is &amp;gt;= totalentries, this will return 0 with out_entrycount=0.&lt;br /&gt;
&lt;br /&gt;
Entry structure:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x1&lt;br /&gt;
| u8 &amp;quot;type&amp;quot;. [[Content_Manager_services|Title type]] (String is from web-applet)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1&lt;br /&gt;
| 0x1&lt;br /&gt;
| u8 &amp;quot;installedStorage&amp;quot; / [[Filesystem_services|StorageId]] (String is from web-applet)&lt;br /&gt;
|-&lt;br /&gt;
| 0x2&lt;br /&gt;
| 0x1&lt;br /&gt;
| Unknown. Non-zero with output from cmd 605, differs for app/update titles.&lt;br /&gt;
|-&lt;br /&gt;
| 0x3&lt;br /&gt;
| 0x1&lt;br /&gt;
| Padding&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 0x4&lt;br /&gt;
| u32 Title-version&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 0x8&lt;br /&gt;
| u64 titleID&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= ns:su =&lt;br /&gt;
&lt;br /&gt;
= ns:dev =&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Cmd || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || LaunchTitle&lt;br /&gt;
|-&lt;br /&gt;
| 1 || TerminateTitle&lt;br /&gt;
|-&lt;br /&gt;
| 2 ||&lt;br /&gt;
|-&lt;br /&gt;
| 3 ||&lt;br /&gt;
|-&lt;br /&gt;
| 4 ||&lt;br /&gt;
|-&lt;br /&gt;
| 5 ||&lt;br /&gt;
|-&lt;br /&gt;
| 6 ||&lt;br /&gt;
|-&lt;br /&gt;
| 7 ||&lt;br /&gt;
|-&lt;br /&gt;
| 8 ||&lt;br /&gt;
|-&lt;br /&gt;
| 9 ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Enums =&lt;br /&gt;
=== AppletId ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  ID&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| Unknown (throws fatal error 2128-0203)&lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| Unknown (throws fatal error 2128-0203)&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| Unknown (throws fatal error 2128-0203)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| Unknown (blinks the screen)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0D&lt;br /&gt;
| Unknown (displays &amp;quot;Checking for free space...&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0E&lt;br /&gt;
| ErrorApplet&lt;br /&gt;
|-&lt;br /&gt;
| 0x0F&lt;br /&gt;
| NetworkSelect&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| PlayerSelect&lt;br /&gt;
|-&lt;br /&gt;
| 0x11&lt;br /&gt;
| Swkbd (on-screen keyboard)&lt;br /&gt;
|-&lt;br /&gt;
| 0x13&lt;br /&gt;
| [[Internet_Browser|WebApplet]] From WebApplet string: &amp;quot;aInfo.appletId == ::nn::applet::AppletId_LibraryAppletWeb&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| Ec ([[Internet_Browser|ShopN]]) From ShopN string: &amp;quot;aInfo.appletId == ::nn::applet::AppletId_LibraryAppletShop&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| 0x15&lt;br /&gt;
| Album&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| [[Internet_Browser|Whitelisted]] web-applet (From whitelisted web-applet string: &amp;quot;aInfo.appletId == ::nn::applet::AppletId_LibraryAppletLoginShare&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x19&lt;br /&gt;
| [[Internet_Browser|WifiWebAuth]] (From browser string: &amp;quot;aInfo.appletId == ::nn::applet::AppletId_LibraryAppletWifiWebAuth&amp;quot;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This seems to be the equivalent of [https://3dbrew.org/wiki/NS_and_APT_Services#AppIDs this].&lt;br /&gt;
&lt;br /&gt;
=== ShimKind ===&lt;br /&gt;
This is from strings and code in the [[Internet_Browser| web-applets]].&lt;br /&gt;
&lt;br /&gt;
This indicates the type of web-applet.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  shimKind value&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| LoginApplet&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| ShareApplet&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| WebApplet&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| WifiWebAuthApplet&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| LobbyApplet&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Services]]&lt;/div&gt;</summary>
		<author><name>Rei</name></author>
	</entry>
</feed>