Langsung ke konten utama

Lifting The (Hyper) Visor: Bypassing Samsung’S Real-Time Total Protection

Posted yesteryear Gal Beniamini,

Traditionally, the operating system’s total is the concluding security boundary standing betwixt an assaulter together with total command over a target system. As such, additional aid must hold upwards taken inwards lodge to ensure the integrity of the kernel. First, when a organization boots, the integrity of its primal components, including that of the operating system’s kernel, must hold upwards verified. This is achieved on Android yesteryear the verified kicking chain. However, only booting an authenticated total is insufficient—what most maintaining the integrity of the total spell the organization is executing?

Imagine a scenario where an assaulter is able to abide by together with exploit a vulnerability inwards the operating system’s kernel. Using such a vulnerability, the assaulter may endeavor to subvert the integrity of the total itself, either yesteryear modifying the contents of its code, or yesteryear introducing novel attacker-controlled code together with running it inside the context of the operating system. Even to a greater extent than subtly, the assaulter may select to modify the information structures used yesteryear the operating organization inwards lodge to alter its behavior (for example, yesteryear granting excessive rights to select processes). As the total is inwards accuse of managing all retentiveness translations, including its own, in that location is no machinery inwards house preventing an assaulter inside the same context from doing so.

However, inwards keeping amongst the concept of “defence inwards depth”, additional layers may hold upwards added inwards lodge to safeguard the total against such would-be attackers. If stacked correctly, these layers may hold upwards designed inwards such a way which either severely limits or only prevents an assaulter from subverting the kernel’s integrity.

In the Android ecosystem, Samsung provides a security hypervisor which aims to tackle the job of ensuring the integrity of the total during runtime. The hypervisor, dubbed “Real-Time Kernel Protection” (RKP), was introduced equally part of Samsung KNOX. In this weblog post we’ll have got an in-depth facial expression at the inner-working of RKP together with nowadays multiple vulnerabilities which allowed attackers to subvert each of RKP’s security mechanisms. We’ll too reckon how the pattern of RKP could hold upwards fortified inwards lodge to foreclose futurity attacks of this nature, making exploitation of RKP much harder.

As always, all the vulnerabilities inwards this article have got been disclosed to Samsung, together with the fixes have got been made available inwards the Jan SMR.

I would similar to regime annotation that inwards improver to addressing the reported issues, the Samsung KNOX squad has been extremely helpful together with opened upwards to discussion. This dialogue helped ensure that the issues were diagnosed correctly together with the rootage causes identified. Moreover, the KNOX squad has reviewed this article inwards advance, together with have got provided primal insights into futurity improvements planned for RKP based on this research.

I would particularly similar to give cheers Tomislav Suchan from the Samsung KNOX squad for helping address every unmarried query I had together with for providing deep insightful responses. Tomislav’s difficult piece of work ensured that all the issues were addressed correctly together with fully, leaving no rock unturned.

HYP 101


Before nosotros tin start exploring the architecture of RKP, nosotros starting fourth dimension involve a basic agreement of the virtualisation extensions on ARMv8. In the ARMv8 architecture, a novel concept of exception levels was introduced. Generally, discrete components run nether dissimilar exception levels - the to a greater extent than privileged the component, the higher its exception level.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

In this weblog post we’ll solely focus on exception levels inside the “Normal World”. Within this context, EL0 represents user-mode processes running on Android, EL1 represents Android’s Linux kernel, together with EL2 (also known equally “HYP” mode) represents the RKP hypervisor.

Recall so when user-mode processes (EL0) wishing to interact amongst the operating system’s total (EL1), they must practise so yesteryear issuing “Supervisor Calls” (SVCs), triggering exceptions which are so handled yesteryear the kernel. Much inwards the same way, interactions amongst the hypervisor (EL2) are performed yesteryear issuing “Hypervisor Calls” (HVCs).

Additionally, the hypervisor may command primal operations that are performed inside the kernel, yesteryear using the “Hypervisor Configuration Register” (HCR). This register governs over the virtualisation features that enable EL2 to interact amongst code running inwards EL1. For example, setting sure as shooting bits inwards the HCR volition drive the hypervisor to trap specific operations which would commonly hold upwards handled yesteryear EL1, enabling the hypervisor to select whether to allow or disallow the requested operation.

Lastly, the hypervisor is able to implement an additional layer of retentiveness translation, called a “stage 2 translation”. Instead of using the regular model where the operating system’s translation tabular array maps betwixt virtual addresses (VAs) together with physical addresses (PAs), the translation procedure is split upwards inwards two.

First, the EL1 translation tables are used inwards lodge to map a given VA to an intermediate physical address (IPA) - this is called a “stage 1 translation”. In the process, the access controls nowadays inwards the translation are too applied, including access permission (AP) bits, execute never (XN) together with privileged execute never (PXN).

Then, the resulting IPA is translated to a PA yesteryear performing a “stage 2 translation”. This mapping is performed yesteryear using a translation tabular array which is accessible to EL2, together with is inaccessible to code running inwards EL1. By using this 2-stage translation regime, the hypervisor is able to foreclose access to sure as shooting primal regions of physical memory, which may comprise sensitive information that should hold upwards kept cloak-and-dagger from EL1.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

Creating a Research Platform


As nosotros just saw inwards our “HYP 101” lesson, communicating amongst EL2 explicitly is done yesteryear issuing HVCs. Unlike SVCs which may hold upwards freely issued yesteryear code running inwards EL0, HVCs tin solely hold upwards triggered yesteryear code running inwards EL1. Since RKP runs inwards EL2 together with exposes the vast bulk of its functionality yesteryear way of commands which tin hold upwards triggered from HVCs, nosotros starting fourth dimension involve a platform from which nosotros are able to send arbitrary HVCs.

Fortunately, inwards a recent weblog post, nosotros already covered an exploit that allowed us to nurture privileges into the context of system_server. This way that all that’s left before nosotros tin start investigating RKP together with interacting amongst EL2, is to abide by an additional vulnerability that allows escalation from an already privileged context (such equally system_server), to the context of the kernel.

Luckily, only surveying the set on surface exposed to such privileged contexts revealed a vast amount of relatively straightforward vulnerabilities, whatever of which could hold upwards used to gain to a greater extent than or less foothold inwards EL1. For the purpose of this research, I’ve decided to exploit the most convenient of these: a elementary stack overflow inwards a sysfs entry, which could hold upwards used to gain arbitrary command over the stack contents for a total thread. Once nosotros have got command over the stack’s contents, nosotros tin build a ROP payload that prepares arguments for a business office telephone call upwards inwards the kernel, calls that function, together with returns the results dorsum to user-space.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

In lodge to ease exploitation, nosotros tin twine the entire procedure of creating a ROP stack which calls a total business office together with returns the results to user-space, into a unmarried function, which we’ll telephone call upwards “execute_in_kernel”. Combined amongst our shellcode wrapper, which converts normal-looking C code to shellcode that tin hold upwards injected into system_server, nosotros are at nowadays able to freely build together with run code which is able to invoke total functions on demand.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection


Putting it all together, nosotros tin start investigating together with interacting amongst RKP using this robust interrogation platform. The ease of the interrogation detailed inwards this weblog post was conducted on a fully updated Milky Way S7 Edge (SM-G935F, XXS1APG3, Exynos chipset), using this exact framework inwards lodge to inject code into system_server using the starting fourth dimension exploit, together with so run code inwards the total using the minute exploit.

Finally, at nowadays that we’ve set downwards all the needed foundations, let’s teach cracking!

Mitigation #1 - KASLR


With the introduction of KNOX v2.6, Samsung devices implement Kernel Address Space Layout Randomisation (KASLR). This security characteristic introduces a random “offset”, generated each fourth dimension the device boots, yesteryear which the base of operations address of the total is shifted. Normally, the total is loaded into a fixed physical address, which corresponds to a fixed virtual address inwards the VAS of the kernel. By introducing KASLR, all the kernel’s memory, including its code, is shifted yesteryear this randomised offset (also known equally a “slide”).

While KASLR may hold upwards a valid mitigation against remote attackers aiming to exploit the kernel, it is real difficult to implement inwards a robust way against local attackers. In fact, in that location has been to a greater extent than or less real interesting recent research on the discipline which manages to defeat KASLR without requiring whatever software põrnikas (e.g., yesteryear observing timing differences).

While those attacks are quite interesting inwards their ain right, it should hold upwards noted that bypassing KASLR tin oftentimes hold upwards achieved much to a greater extent than easily. Recall that the entire total is shifted yesteryear a unmarried “slide” value - this way that leaking any pointer inwards the total which resides at a known offset from the kernel’s base of operations address would allow us to easily calculate the slide’s value.

The Linux total does include mechanisms intended to foreclose the leakage of such pointers to user-space. One such mitigation is enforced yesteryear ensuring that every fourth dimension a pointer’s value is written yesteryear the kernel, it is printed using a special format specifier: “%pK”. Then, depending on the value of kptr_restrict, the total may anonymise the printed pointer. In all Android devices that I’ve encountered, kptr_restrict is configured correctly, indeed ensuring the “%pK” pointers are anonymised.

Be that equally it may, all nosotros involve is to abide by a unmarried pointer which a total developer neglected to anonymise. In Samsung’s case, this turned out to hold upwards rather amusing… The pm_qos debugfs entry, which is readable yesteryear system_server, included the next code snippet responsible for outputting the entry’s contents:

static void pm_qos_debug_show_one(struct seq_file *s, struct pm_qos_object *qos)
{
   struct plist_node *p;
   unsigned long flags;

   spin_lock_irqsave(&pm_qos_lock, flags);

   seq_printf(s, "%s\n", qos->name);
   seq_printf(s, "   default value: %d\n", qos->constraints->default_value);
   seq_printf(s, "   target value: %d\n", qos->constraints->target_value);
   seq_printf(s, "   requests:\n");
   plist_for_each(p, &qos->constraints->list)
       seq_printf(s, "      %pk(%s:%d): %d\n",
                     container_of(p, struct pm_qos_request, node),
                     (container_of(p, struct pm_qos_request, node))->func,
                     (container_of(p, struct pm_qos_request, node))->line,
                     p->prio);

   spin_unlock_irqrestore(&pm_qos_lock, flags);
}

Unfortunately, the anonymisation format specifier is case sensitive… Using a lowercase “k”, similar the code above, causes the code to a higher house to output the pointer without applying the anonymisation offered yesteryear “%pK” (perhaps this serves equally a expert instance of how fragile KASLR is). Regardless, this allows us to only read the contents of pm_qos, together with subtract the pointer’s value from it’s known offset from the kernel’s base of operations address, thus giving us the value of the KASLR slide.

Mitigation #2 - Loading Arbitrary Kernel Code


Preventing the allotment of novel total code is 1 of the original mitigations enforced yesteryear RKP. In addition, RKP aims to protect all existing total code against modification. These mitigations are achieved yesteryear enforcing the next set of rules:

  1. All pages, amongst the exception of the kernel’s code, are marked equally “Privileged Execute Never” (PXN)
  2. Kernel information pages are never marked executable
  3. Kernel code pages are never marked writable
  4. All total code pages are marked equally read-only inwards the phase 2 translation table
  5. All retentiveness translation entries (PGDs, PMDs together with PTEs) are marked equally read-only for EL1

While these rules appear to hold upwards quite robust, how tin nosotros hold upwards sure as shooting that they are existence enforced correctly? Admittedly, the rules are set out nicely inwards the RKP documentation, but that’s non a strong plenty guarantee...

Instead of exercising trust, let’s start yesteryear challenging the starting fourth dimension assertion; namely, that amongst the exception of the kernel’s code, all other pages are marked equally PXN. We tin banking concern check this assertion yesteryear looking at the phase 1 translation tables inwards EL1. ARMv8 supports the occupation of 2 translation tables inwards EL1, TTBR0_EL1 together with TTBR1_EL1. TTBR0_EL1 is used to agree the mappings for user-space’s VAS, spell TTBR1_EL1 holds the kernel’s global mappings.

In lodge to analyse the contents of the EL1 phase 1 translation tabular array used yesteryear the kernel, we’ll involve to starting fourth dimension locate the physical address of the translation tabular array itself. Once nosotros abide by the translation table, nosotros tin occupation our execute_in_kernel primitive inwards lodge to iteratively execute a “read gadget” inwards the kernel, allowing us to read out the contents of the translation table.

There is 1 tiny snag, though - how volition nosotros hold upwards able to call back the location of the translation table? To practise so, we’ll involve to abide by a gadget which allows us to read TTBR1_EL1 without causing whatever adverse effects inwards the kernel.

Unfortunately, combing over the kernel’s code reveals a depressing fact - it seems equally though such gadgets are quite rare. While in that location are to a greater extent than or less functions that practise read TTBR1_EL1, they too perform additional operations, resulting inwards unwanted side effects. In contrast, RKP’s code segments seem to hold upwards rife amongst such gadgets - inwards fact, RKP contains small-scale gadgets to read together with write nearly every unmarried command register belonging to EL1.

Perhaps nosotros could somehow occupation this fact to our advantage? Digging deeper into the kernel’s code (init/main.c) reveals that rather perplexingly, on Exynos devices (as opposed to Qualcomm-based devices) RKP is bootstrapped yesteryear the EL1 kernel. This way that instead of booting EL2 straight from EL3, it seems that EL1 is booted first, together with solely so performs to a greater extent than or less operations inwards lodge to bootstrap EL2.

This bootstrapping is achieved yesteryear embedding the entire binary containing RKP’s code inwards the EL1 kernel’s code segment. Then, in 1 lawsuit the total boots, it copies the RKP binary to a predefined physical make together with transitions to TrustZone inwards lodge to bootstrap together with initialise RKP.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

By embedding the RKP binary inside the kernel’s text segment, it becomes a part of the retentiveness make executable from EL1. This allows us to leverage all of the gadgets inwards the embedded RKP binary - making life that much easier.

Equipped amongst this novel knowledge, nosotros tin at nowadays practise a small-scale computer program which reads the location of the phase 1 translation tabular array using the gadgets from the RKP binary straight inwards EL1, together with afterwards dumps together with parses the table’s contents. Since nosotros are interested inwards bypassing the code loading mitigations enforced yesteryear RKP, we’ll focus on the physical retentiveness ranges containing the Linux kernel. After writing together with running this program, nosotros are faced amongst the next output:

...
[256] L1 tabular array [PXNTable: 0, APTable: 0]
 [  0] 0x080000000-0x080200000 [PXN: 0, UXN: 1, AP: 0]
 [  1] 0x080200000-0x080400000 [PXN: 0, UXN: 1, AP: 0]
 [  2] 0x080400000-0x080600000 [PXN: 0, UXN: 1, AP: 0]
 [  3] 0x080600000-0x080800000 [PXN: 0, UXN: 1, AP: 0]
 [  4] 0x080800000-0x080a00000 [PXN: 0, UXN: 1, AP: 0]
 [  5] 0x080a00000-0x080c00000 [PXN: 0, UXN: 1, AP: 0]
 [  6] 0x080c00000-0x080e00000 [PXN: 0, UXN: 1, AP: 0]
 [  7] 0x080e00000-0x081000000 [PXN: 0, UXN: 1, AP: 0]
 [  8] 0x081000000-0x081200000 [PXN: 0, UXN: 1, AP: 0]
 [  9] 0x081200000-0x081400000 [PXN: 0, UXN: 1, AP: 0]
 [ 10] 0x081400000-0x081600000 [PXN: 1, UXN: 1, AP: 0]
...

As nosotros tin reckon above, the entire physical retentiveness make [0x80000000, 0x81400000] is mapped inwards the phase 1 translation tabular array using starting fourth dimension grade “Section” descriptors, each of which is responsible for translating a 1MB make of memory. We tin too reckon that, equally expected, this make is marked UXN together with non-PXN - hence EL1 is allowed to execute retentiveness inwards these ranges, spell EL0 is prohibited from doing so. However, much to a greater extent than surprisingly, the entire make is marked amongst access permission (AP) chip values of “00”. Let’s consult the ARM VMSA to reckon what these values indicate:

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection


Aha - so inwards fact this way that these retentiveness ranges are too readable together with writable from EL1! Combining all this together, nosotros make the determination that the entire physical make of [0x80000000, 0x81400000] is mapped equally RWX inwards the phase 1 translation table.

This silent doesn’t hateful nosotros tin modify the kernel’s code. Remember, RKP enforces the phase 2 retentiveness translation equally well. These retentiveness ranges could good hold upwards restricted inwards the phase 2 translation inwards lodge to foreclose attackers from gaining write access to them.

After to a greater extent than or less reversing, nosotros abide by that RKP’s initial phase 2 translation tabular array is inwards fact embedded inwards the RKP binary itself. This allows us to extract its contents together with to analyse it inwards detail, similar to our previous piece of work on the phase 1 translation table.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

I’ve written a python script which analyses a given binary blob according to the phase 2 translation table’s format specified inwards the ARM VMSA. Next, nosotros tin occupation this script inwards lodge to discovery the retentiveness protections enforced yesteryear RKP on the kernel’s physical address range:

...
0x80000000-0x80200000: S2AP=11, XN=0
0x80200000-0x80400000: S2AP=11, XN=0
0x80400000-0x80600000: S2AP=11, XN=0
0x80600000-0x80800000: S2AP=11, XN=0
0x80800000-0x80a00000: S2AP=11, XN=0
0x80a00000-0x80c00000: S2AP=11, XN=0
0x80c00000-0x80e00000: S2AP=11, XN=0
0x80e00000-0x81000000: S2AP=11, XN=0
0x81000000-0x81200000: S2AP=11, XN=0
0x81200000-0x81400000: S2AP=11, XN=0
0x81400000-0x81600000: S2AP=11, XN=0
...

First of all, nosotros tin reckon that the phase 2 translation tabular array used yesteryear RKP maps every IPA to the same PA. As such, nosotros tin safely ignore the existence of IPAs for the balance of this weblog post together with focus of PAs instead.

More importantly, however, nosotros tin reckon that our retentiveness make of involvement is non marked equally XN, equally is expected. After all, the total should hold upwards executable yesteryear EL1. But bafflingly, the entire make is marked amongst the phase 2 access permission (S2AP) bits set to “11”. Once again, let’s consult the ARM VMSA:

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection
So this seems a picayune odd… Does this hateful that the entire kernel’s code make is marked equally RWX inwards both the phase 1 together with the phase 2 translation table? That doesn’t seem to add together up. Indeed, trying to write to retentiveness addresses containing EL1 total code results inwards a translation fault, so we’re definitely missing something here.

Ah, but wait! The phase 2 translation tables that we’ve analysed to a higher house are only the initial translation tables which are used when RKP boots. Perhaps after the EL1 total finishes its initialisation it volition somehow asking RKP to modify these mappings inwards lodge to protect its ain retentiveness ranges.

Indeed, looking in 1 lawsuit once to a greater extent than at the kernel’s initialisation routines, nosotros tin reckon that presently after booting, the EL1 total calls into RKP:

static void rkp_init(void)
{
rkp_init_t init;
init.magic = RKP_INIT_MAGIC;
init.vmalloc_start = VMALLOC_START;
init.vmalloc_end = (u64)high_memory;
init.init_mm_pgd = (u64)__pa(swapper_pg_dir);
init.id_map_pgd = (u64)__pa(idmap_pg_dir);
init.rkp_pgt_bitmap = (u64)__pa(rkp_pgt_bitmap);
init.rkp_map_bitmap = (u64)__pa(rkp_map_bitmap);
init.rkp_pgt_bitmap_size = RKP_PGT_BITMAP_LEN;
init.zero_pg_addr = page_to_phys(empty_zero_page);
init._text = (u64) _text;
init._etext = (u64) _etext;
if (!vmm_extra_mem) {
printk(KERN_ERR"Disable RKP: Failed to allocate extra mem\n");
return;
}
init.extra_memory_addr = __pa(vmm_extra_mem);
init.extra_memory_size = 0x600000;
init._srodata = (u64) __start_rodata;
init._erodata =(u64) __end_rodata;
init.large_memory = rkp_support_large_memory;

rkp_call(RKP_INIT, (u64)&init, 0, 0, 0, 0);
rkp_started = 1;
return;
}

On the kernel’s side nosotros tin reckon that this command provides RKP amongst many of the retentiveness ranges belonging to the kernel. In lodge to figure out the implementation of this command, let’s shift our focus dorsum to RKP. By contrary technology scientific discipline the implementation of this command inside RKP, nosotros teach inwards at the next guess high-level logic:

void handle_rkp_init(...) {
   ...
   void* kern_text_phys_start = rkp_get_pa(text);
   void* kern_text_phys_end = rkp_get_pa(etext);
   rkp_debug_log("DEFERRED INIT START", 0, 0, 0);

   if (etext & 0x1FFFFF)
       rkp_debug_log("Kernel make is non aligned", 0, 0, 0);

   if (!rkp_s2_range_change_permission(kern_text_phys_start, kern_text_phys_end, 128, 1, 1))
       rkp_debug_log("Failed to brand Kernel make RO", 0, 0, 0);

   ...
}

The highlighted business office telephone call upwards to a higher house is used inwards lodge to modify the phase 2 access permissions for a given PA retentiveness range. Calling the business office amongst these arguments volition drive the given retentiveness make to hold upwards marked equally read-only inwards the phase 2 translation. This way that presently after booting the EL1 kernel, RKP does indeed lock downwards write access to the kernel’s code ranges.

...And yet, something’s silent missing here. Remember that RKP should non solely foreclose the kernel’s code from existence modified, but it aims to too foreclose attackers from creating novel executable code inwards EL1. Well, spell the kernel’s code is indeed existence marked equally read-only inwards the phase 2 translation table, does that necessarily foreclose us from creating novel executable code?

Recall that we’ve previously encountered the presence of KASLR, inwards which the kernel’s base of operations address (both inwards the kernel’s VAS together with the corresponding physical address) is shifted yesteryear a randomised “slide” value. Moreover, since the Linux total assumes that the virtual to physical offset for total addresses is constant, this way that the same slide value is used for both virtual together with physical addresses.

However, there’s a tiny snag hither -- the address make nosotros examined before on, the same 1 which is marked RWX is both the phase 1 together with phase 2 translation table, is much larger than the kernel’s text segment. This is, partly, inwards lodge to allow the total to hold upwards placed somewhere inside that part after the KASLR slide is determined. However, equally we’ve just seen, after choosing the KASLR slide, RKP only protects the make spanning from “_text” to “_etext” - that is, solely the part containing the kernel’s text after applying the KASLR slide.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

This leaves us amongst 2 large regions: [0x80000000, “_text”], [“_etext”, 0x81400000], which are left marked equally RWX inwards both the phase 1 together with phase 2 translation tables! Thus, nosotros tin only write novel code to these regions together with execute it freely inside the context of EL1, hence bypassing the code loading mitigation. I’ve included a small-scale PoC which demonstrates this issue, here.

Mitigation #3 - Bypassing EL1 Memory Controls


As we’ve just seen inwards the previous section, to a greater extent than or less of RKP’s stated goals require retentiveness controls that are enforced non solely inwards the phase 2 translation, but too straight inwards the phase 1 translation used yesteryear EL1. For example, RKP aims to ensure that all pages, amongst the exception of the kernel’s code, are marked equally PXN. These goals require RKP to have got to a greater extent than or less shape of command over the contents of the phase 1 translation table.

So how precisely does RKP brand sure as shooting that these kinds of assurances are kept? This is done yesteryear using a combined approach; first, the phase 1 translation tables are placed inwards a part which is marked equally read-only inwards the phase 2 translation tables. This, inwards effect, disallows EL1 code from straight modifying the translation tables themselves. Secondly, the total is instrumented (a shape of paravirtualisation), inwards lodge to brand it aware of RKP’s existence. This instrumentation is performed so that each write functioning to a information construction used inwards the phase 1 translation procedure (a PGD, PMD or PTE), volition instead telephone call upwards an RKP command, informing it of the requested change.

Putting these 2 defences together, nosotros teach inwards at the determination that all modifications to the phase 1 translation tabular array must hence exceed through RKP which can, inwards turn, ensure that they practise non violate whatever of its security goals.

Or practise they?

While these rules practise foreclose modification of the electrical flow contents of the phase 1 translation table, they don’t foreclose an assaulter from using the retentiveness administration command registers to circumvent these protections. For example, an assaulter could endeavor to modify the value of TTBR1_EL1 directly, pointing it at an arbitrary (and unprotected) retentiveness address.

Obviously, such operations cannot hold upwards permitted yesteryear RKP. In lodge to allow the hypervisor to bargain amongst such situations, the “Hypervisor Configuration Register” (HCR) tin hold upwards leveraged. Recall that the HCR allows the hypervisor to disallow sure as shooting operations from existence performed nether EL1. One such functioning which tin hold upwards trapped is the modification of the EL1 retentiveness administration command registers.


In the instance of RKP on Exynos devices, spell it does non set HCR_EL2.TRVM (i.e., it allows all read access to retentiveness command registers), it does indeed set HCR_EL2.TVM, allowing it to trap write access to these registers.

So although we’ve established that RKP does correctly trap write access to the command registers, this silent doesn’t guarantee they rest protected. This is truly quite a fragile province of affairs - the Linux total requires to a greater extent than or less access to many of these registers inwards lodge to perform regular operations. This way that spell to a greater extent than or less access tin hold upwards denied yesteryear RKP, other operations involve to hold upwards inspected carefully inwards lodge to brand sure as shooting they practise non violate RKP’s security guarantees, before allowing them to proceed. Once again, we’ll involve to contrary engineer RKP’s code to assess the situation.

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

As nosotros tin reckon above, attempts to modify the location of the translation tables themselves, outcome inwards RKP correctly verifying the entire translation table, making sure as shooting it follows the allowed phase 1 translation policy. In contrast, in that location are a couplet of crucial retentiveness command registers which, at the time, weren’t intercepted yesteryear RKP at all - TCR_EL1 together with SCTLR_EL1!

Inspecting these registers inwards the ARM reference manual reveals that they both tin have got profound effects on the phase 1 translation process.

For starters, the System Control Register for EL1 (SCTLR_EL1) provides top-level command over the system, including the retentiveness system, inwards EL1. One chip of crucial importance inwards our scenario is the SCTLR_EL1.M bit.


This chip denotes the terra firma of the MMU for phase 1 translation inwards EL0 together with EL1. Therefore, only yesteryear unsetting this bit, an assaulter tin disable the MMU for phase 1 translation. Once the chip is unset, all retentiveness translation inwards EL1 map straight to IPAs, but to a greater extent than importantly - these retentiveness translation practise non have got whatever access permissions checks enabled, effectively making all retentiveness ranges considered equally RWX inwards the phase 1 translation. This, inwards turn, bypasses several of RKP’s assurances, such equally making sure as shooting that solely the kernel’s text is non marked equally PXN.

As for the Translation Control Register for EL1 (TCR_EL1), it’s effects are slightly to a greater extent than subtle. Instead of completely disabling the phase 1 translation’s MMU, this register governs the way inwards which translation is performed.


Indeed, observing this register to a greater extent than closely, reveals sure as shooting primal ways inwards which an assaulter may leverage it inwards lodge to circumvent RKP’s phase 1 protections. For example, the AARCH64 retentiveness translation tabular array may assume dissimilar formats, depending on the translation granule nether which the organization is operating. Normally, AARCH64 Linux kernels occupation a translation granule of 4KB.

This fact is implicitly acknowledged inwards RKP. For example, when code inwards EL1 changes the value of the translation tabular array (e.g., TTBR1_EL1), RKP must protect this PGD inwards the phase 2 translation inwards lodge to brand sure as shooting that EL1 cannot gain access to it. Indeed, reversing the corresponding code inside RKP reveals that it does just that:

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

However, equally nosotros tin reckon inwards the moving painting above, the phase 2 protection is solely performed on a 4KB part (a unmarried page). This is because when using a 4KB translation granule, the translation regime has a translation tabular array size of 4KB. However, this is where we, equally an attacker, come upwards in. What if nosotros were to modify the value of the translation granule to 64KB, yesteryear modifying TCR_EL1.TG0 together with TCR_EL1.TG1?


In that case, the translation regime’s translation tabular array volition at nowadays hold upwards 64KB equally well, equally opposed to 4KB nether the previous regime. Since RKP uses a hard-coded value of 4KB when protecting the translation table, the bottom 60KB rest unprotected yesteryear RKP, allowing an assaulter inwards EL1 to freely modify it inwards lodge to dot to whatever IPA, whatever to a greater extent than crucially, amongst whatever access permissions, UXN/PXN values.


Lastly, it should in 1 lawsuit to a greater extent than hold upwards noted that spell the gadgets needed to access these registers aren’t abundant inwards the kernel’s image, they are nowadays inwards the embedded RKP binary on Exynos devices. Therefore nosotros tin only execute these gadgets inside EL1 inwards lodge to modify the registers above. I’ve written a small-scale PoC that demonstrates this number yesteryear disabling the phase 1 MMU inwards EL1.

Mitigation #4 - Accessing Stage 2 Unmapped Memory


Other than the operating system’s memory, in that location be several other retentiveness regions which may comprise potentially sensitive information that should non hold upwards accessible yesteryear code running inwards EL0 together with EL1. For example, peripherals on the SoC may have got their firmware stored inwards the “Normal World”, inwards physical retentiveness ranges which should never hold upwards accessible to Android itself.

In lodge to enforce such protections, RKP explicitly unmaps a few retentiveness ranges from the phase 2 translation table. By doing so, whatever endeavor to access these PA ranges inwards EL0 or EL1 volition outcome inwards a translation fault, consequently crashing the total together with rebooting the device.

Moreover, RKP’s ain retentiveness ranges should too hold upwards made inaccessible to lesser privileged code. This is crucial so equally to protect RKP from modifications yesteryear EL0 together with EL1, but too serves to protect the sensitive information that is processed inside RKP (such equally the “cfprop” key). Indeed, after starting up, RKP explicitly unmaps it’s ain retentiveness ranges inwards lodge to foreclose such access:

s total is the concluding security boundary standing betwixt an assaulter together with total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

Admittedly, the phase 2 translation tabular array itself is placed inside the real part existence unmapped from the phase 2 translation table, hence ensuring that code inwards EL1 cannot modify it. However, possibly nosotros could abide by to a greater extent than or less other way to command phase 2 mappings, but leveraging RKP itself.

For example, equally we’ve previously seen, sure as shooting operations such equally setting TTBR1_EL1 outcome inwards changes to the phase 2 translation table. Combing over the RKP binary, nosotros come upwards across 1 such operation, equally follows:

__int64 rkp_set_init_page_ro(unsigned args* args_buffer)
{
 unsigned long page_pa = rkp_get_pa(args_buffer->arg0);
 if ( page_pa < rkp_get_pa(text) || page_pa >= rkp_get_pa(etext) )
 {
   if ( !rkp_s2_page_change_permission(page_pa, 128, 0, 0) )
     return rkp_debug_log("Cred: Unable to set permission for init cred", 0LL, 0LL, 0LL);
 }
 else
 {
   rkp_debug_log("Good init CRED is inside RO range", 0LL, 0LL, 0LL);
 }
 rkp_debug_log("init cred page", 0LL, 0LL, 0LL);
 return rkp_set_pgt_bitmap(page_pa, 0);
}

As nosotros tin see, this command receives a pointer from EL1, verifies it is non inside the kernel’s text segment, together with if so proceeds to telephone call upwards rkp_s2_page_change_permission inwards lodge to modify the access permissions on this make inwards the phase 2 translation table. Digging deeper into the business office reveals that this set of parameters is used to announce the part equally read-only together with XN.

But, what if nosotros were to provide a page that resides somewhere that is non currently mapped inwards the phase 2 translation at all, such equally RKP’s ain retentiveness ranges? Well, inwards this case, rkp_s2_page_change_permission will happily practise a translation entry for the given page, effectively mapping inwards a previously unmapped region!

This allows us to re-map whatever phase 2 unmapped part (albeit equally read-only together with XN) from EL1. I’ve written a small-scale PoC which demonstrates the number yesteryear phase 2 re-mapping RKP’s physical address make together with reading it from EL1.

Design Improvements to RKP


After seeing to a greater extent than or less specific issues inwards this weblog post, highlighting how the dissimilar defense mechanisms of RKP could hold upwards subverted yesteryear an attacker, let’s zoom out for a minute together with think most to a greater extent than or less pattern choices that could serve to strengthen RKP’s security posture against futurity attacks.

First, RKP on Exynos devices is currently existence bootstrapped yesteryear EL1 code. This is inwards contrast to the model used on Qualcomm devices, whereby the EL2 code is both verified yesteryear the bootloader, together with afterwards booted yesteryear EL3. Ideally, I believe the same model used on Qualcomm devices should hold upwards adopted for Exynos equally well.

Performing the bootstrapping inwards this lodge automatically fixes other related security issues “for free”, such equally the presence of RKP’s binary inside the kernel’s text segment. As we’ve seen, this seemingly harmless fact is inwards fact real useful for an assaulter inwards several of the scenarios we’ve highlighted inwards this post. Moreover, it removes other risks such equally attackers exploiting the EL1 total early on inwards the kicking procedure together with leveraging that access to subvert the initialisation of EL2.

As inwards interim improvement, RKP decided to null out the RKP binary resident inwards EL1’s code during initialisation. This improvement volition curlicue out inwards the adjacent Nougat milestone release of Samsung devices, together with addresses the number of attackers leveraging the binary for gadgets. However, it doesn’t address the number regarding potential early on exploitation of the EL1 total to subvert the initialization of EL2, which requires a to a greater extent than extensive modification.

Second, RKP’s code segments are currently marked equally both writable together with executable inwards TTBR0_EL2. This, combined amongst the fact that SCTLR_EL2.WXN is non set, allows an assaulter to occupation whatever retentiveness corruption primitive inwards EL2 inwards lodge to straight overwrite the EL2 code segments, allowing for much easier exploitation of the hypervisor.

While I have got non chosen to include these issues inwards the weblog post, I’ve found several memory corruptions, whatever of which could hold upwards used to modify retentiveness inside the context of RKP. Combining these 2 facts together, nosotros tin conclude that whatever of these retentiveness corruptions could hold upwards used yesteryear an assaulter to straight modify RKP’s code itself, hence gaining code execution inside it.

Simply setting SCTLR_EL2.WXN together with marker RKP’s code equally read-only would non foreclose an assaulter from gaining access to RKP, but it could brand exploitation of such retentiveness corruptions harder to exploit together with to a greater extent than fourth dimension consuming.

Third, RKP should lock downwards all retentiveness command registers, unless they absolutely must hold upwards used yesteryear the Linux kernel. This would foreclose abuse of several of these registers which may subtly send upon the system’s behaviour, together with inwards doing so, violate assumptions made yesteryear RKP most the kernel. Where these registers have got to hold upwards modified yesteryear EL1, RKP should verify that solely the appropriate bits are accessed.

RKP has since locked downwards access to the 2 registers mentioned inwards this weblog post. This is a expert measurement inwards the right direction, together with unfortunately equally access to to a greater extent than or less of these registers must hold upwards retained, only revoking access to all of them is non a viable solution. As such, preventing access to other retentiveness command registers remains a long term goal.

Lastly, in that location should hold upwards to a greater extent than or less distinction betwixt phase 2 unmapped regions that were only never mapped in, together with those which were explicitly mapped out. This tin hold upwards achieved yesteryear storing the retentiveness ranges corresponding to explicitly unmapped regions, together with disallowing whatever modification that would outcome inwards remapping them inside RKP. While the number I highlighted is at nowadays fixed, implementing this extra measurement would foreclose farther similar issues from cropping upwards inwards the future.

Komentar

Postingan populer dari blog ini

Exception-Oriented Exploitation On Ios

Posted past times Ian Beer, This postal service covers the regain in addition to exploitation of CVE-2017-2370 , a heap buffer overflow inwards the mach_voucher_extract_attr_recipe_trap mach trap. It covers the bug, the evolution of an exploitation technique which involves repeatedly in addition to deliberately crashing in addition to how to build alive meat introspection features using onetime meat exploits. It’s a trap! Alongside a large number of BSD syscalls (like ioctl, mmap, execve in addition to so on) XNU also has a pocket-sized number of extra syscalls supporting the MACH side of the meat called mach traps. Mach trap syscall numbers start at 0x1000000. Here’s a snippet from the syscall_sw.c file where the trap tabular array is defined: /* 12 */ MACH_TRAP(_kernelrpc_mach_vm_deallocate_trap, 3, 5, munge_wll), /* xiii */ MACH_TRAP(kern_invalid, 0, 0, NULL), /* xiv */ MACH_TRAP(_kernelrpc_mach_vm_protect_trap, 5, 7, munge_wllww), Most of the mach traps a...

Chrome Bone Exploit: 1 Byte Overflow As Well As Symlinks

The next article is an invitee weblog post from an external researcher (i.e. the writer is non a or Google researcher). This post is most a Chrome OS exploit I reported to Chrome VRP inward September. The folks were squeamish to allow me do a invitee post most it, therefore hither goes. The study includes a detailed writeup , therefore this post volition have got less detail. 1 byte overflow inward a DNS library In Apr I constitute a TCP port listening on localhost inward Chrome OS. It was an HTTP proxy built into shill, the Chrome OS network manager. The proxy has at nowadays been removed equally component of a fix, but its source tin give notice nonetheless move seen from an one-time revision: shill/http_proxy.cc . The code is unproblematic in addition to doesn’t seem to incorporate whatever obvious exploitable bugs, although it is real liberal inward what it accepts equally incoming HTTP. It calls into the c-ares library for resolving DNS. There was a possible 1 byte ov...