Langsung ke konten utama

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

Posted yesteryear Gal Beniamini,

Traditionally, the operating system’s gist is the final security boundary standing betwixt an assaulter as well as total command over a target system. As such, additional aid must hold out taken inwards club to ensure the integrity of the kernel. First, when a organisation boots, the integrity of its telephone commutation components, including that of the operating system’s kernel, must hold out verified. This is achieved on Android yesteryear the verified kick chain. However, only booting an authenticated gist is insufficient—what well-nigh maintaining the integrity of the gist piece the organisation is executing?

Imagine a scenario where an assaulter is able to detect as well as exploit a vulnerability inwards the operating system’s kernel. Using such a vulnerability, the assaulter may endeavour to subvert the integrity of the gist itself, either yesteryear modifying the contents of its code, or yesteryear introducing novel attacker-controlled code as well as running it inside the context of the operating system. Even to a greater extent than subtly, the assaulter may pick out to modify the information structures used yesteryear the operating organisation inwards club to alter its demeanour (for example, yesteryear granting excessive rights to select processes). As the gist is inwards accuse of managing all retentiveness translations, including its own, at that topographic point 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 out added inwards club to safeguard the gist against such would-be attackers. If stacked correctly, these layers may hold out 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 work of ensuring the integrity of the gist during runtime. The hypervisor, dubbed “Real-Time Kernel Protection” (RKP), was introduced every bit constituent of Samsung KNOX. In this weblog post service we’ll have got an in-depth aspect at the inner-working of RKP as well as nowadays multiple vulnerabilities which allowed attackers to subvert each of RKP’s security mechanisms. We’ll likewise consider how the pattern of RKP could hold out fortified inwards club to foreclose hereafter attacks of this nature, making exploitation of RKP much harder.

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

I would similar to complaint that inwards improver to addressing the reported issues, the Samsung KNOX squad has been extremely helpful as well as opened upward to discussion. This dialogue helped ensure that the issues were diagnosed correctly as well as the origin causes identified. Moreover, the KNOX squad has reviewed this article inwards advance, as well as have got provided telephone commutation insights into hereafter improvements planned for RKP based on this research.

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

HYP 101


Before nosotros tin start exploring the architecture of RKP, nosotros offset call for 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 gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

In this weblog post service we’ll alone 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, as well as EL2 (also known every bit “HYP” mode) represents the RKP hypervisor.

Recall as well as so when user-mode processes (EL0) want to interact amongst the operating system’s gist (EL1), they must exercise so yesteryear issuing “Supervisor Calls” (SVCs), triggering exceptions which are as well as 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 telephone commutation 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 for certain bits inwards the HCR volition motility the hypervisor to trap specific operations which would unremarkably hold out handled yesteryear EL1, enabling the hypervisor to pick out 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) as well as physical addresses (PAs), the translation procedure is separate inwards two.

First, the EL1 translation tables are used inwards club 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 likewise applied, including access permission (AP) bits, execute never (XN) as well as 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, as well as is inaccessible to code running inwards EL1. By using this 2-stage translation regime, the hypervisor is able to foreclose access to for certain telephone commutation regions of physical memory, which may comprise sensitive information that should hold out kept hole-and-corner from EL1.

s gist is the final security boundary standing betwixt an assaulter as well as 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 out freely issued yesteryear code running inwards EL0, HVCs tin alone hold out triggered yesteryear code running inwards EL1. Since RKP runs inwards EL2 as well as exposes the vast bulk of its functionality yesteryear agency of commands which tin hold out triggered from HVCs, nosotros offset call for a platform from which nosotros are able to ship arbitrary HVCs.

Fortunately, inwards a recent weblog post, nosotros already covered an exploit that allowed us to lift privileges into the context of system_server. This agency that all that’s left before nosotros tin start investigating RKP as well as interacting amongst EL2, is to detect an additional vulnerability that allows escalation from an already privileged context (such every bit system_server), to the context of the kernel.

Luckily, only surveying the assail surface exposed to such privileged contexts revealed a vast amount of relatively straightforward vulnerabilities, whatever of which could hold out used to gain just about foothold inwards EL1. For the purpose of this research, I’ve decided to exploit the most convenient of these: a uncomplicated stack overflow inwards a sysfs entry, which could hold out used to gain arbitrary command over the stack contents for a gist thread. Once nosotros have got command over the stack’s contents, nosotros tin build a ROP payload that prepares arguments for a role telephone call upward inwards the kernel, calls that function, as well as returns the results dorsum to user-space.

s gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

In club to ease exploitation, nosotros tin roll the entire procedure of creating a ROP stack which calls a gist role as well as returns the results to user-space, into a unmarried function, which we’ll telephone call upward “execute_in_kernel”. Combined amongst our shellcode wrapper, which converts normal-looking C code to shellcode that tin hold out injected into system_server, nosotros are at nowadays able to freely build as well as run code which is able to invoke gist functions on demand.

s gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection


Putting it all together, nosotros tin start investigating as well as interacting amongst RKP using this robust inquiry platform. The ease of the inquiry detailed inwards this weblog post service was conducted on a fully updated Milky Way S7 Edge (SM-G935F, XXS1APG3, Exynos chipset), using this exact framework inwards club to inject code into system_server using the offset exploit, as well as and so run code inwards the gist 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 gist is shifted. Normally, the gist 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 every bit a “slide”).

While KASLR may hold out a valid mitigation against remote attackers aiming to exploit the kernel, it is rattling difficult to implement inwards a robust way against local attackers. In fact, at that topographic point has been just about rattling interesting recent research on the bailiwick 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 out noted that bypassing KASLR tin oft hold out achieved much to a greater extent than easily. Recall that the entire gist is shifted yesteryear a unmarried “slide” value - this agency that leaking any pointer inwards the gist 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 gist 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 gist 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 every bit it may, all nosotros call for is to detect a unmarried pointer which a gist developer neglected to anonymise. In Samsung’s case, this turned out to hold out 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 every bit a adept instance of how fragile KASLR is). Regardless, this allows us to only read the contents of pm_qos, as well as 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 gist code is ane of the psyche mitigations enforced yesteryear RKP. In addition, RKP aims to protect all existing gist 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 every bit “Privileged Execute Never” (PXN)
  2. Kernel information pages are never marked executable
  3. Kernel code pages are never marked writable
  4. All gist code pages are marked every bit read-only inwards the phase 2 translation table
  5. All retentiveness translation entries (PGDs, PMDs as well as PTEs) are marked every bit read-only for EL1

While these rules appear to hold out quite robust, how tin nosotros hold out for certain that they are beingness 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 offset assertion; namely, that amongst the exception of the kernel’s code, all other pages are marked every bit PXN. We tin banking company check this assertion yesteryear looking at the phase 1 translation tables inwards EL1. ARMv8 supports the exercise of 2 translation tables inwards EL1, TTBR0_EL1 as well as TTBR1_EL1. TTBR0_EL1 is used to concord the mappings for user-space’s VAS, piece TTBR1_EL1 holds the kernel’s global mappings.

In club to analyse the contents of the EL1 phase 1 translation tabular array used yesteryear the kernel, we’ll call for to offset locate the physical address of the translation tabular array itself. Once nosotros detect the translation table, nosotros tin exercise our execute_in_kernel primitive inwards club to iteratively execute a “read gadget” inwards the kernel, allowing us to read out the contents of the translation table.

There is ane tiny snag, though - how volition nosotros hold out able to recall the location of the translation table? To exercise so, we’ll call for to detect 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 every bit though such gadgets are quite rare. While at that topographic point are just about functions that exercise read TTBR1_EL1, they likewise perform additional operations, resulting inwards unwanted side effects. In contrast, RKP’s code segments seem to hold out rife amongst such gadgets - inwards fact, RKP contains pocket-size gadgets to read as well as write nearly every unmarried command register belonging to EL1.

Perhaps nosotros could somehow exercise 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 agency that instead of booting EL2 straight from EL3, it seems that EL1 is booted first, as well as alone as well as so performs just about operations inwards club to bootstrap EL2.

This bootstrapping is achieved yesteryear embedding the entire binary containing RKP’s code inwards the EL1 kernel’s code segment. Then, ane time the gist boots, it copies the RKP binary to a predefined physical make as well as transitions to TrustZone inwards club to bootstrap as well as initialise RKP.

s gist is the final security boundary standing betwixt an assaulter as well as 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 constituent 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 exercise a pocket-size computer program which reads the location of the phase 1 translation tabular array using the gadgets from the RKP binary straight inwards EL1, as well as afterwards dumps as well as 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 as well as 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 consider above, the entire physical retentiveness make [0x80000000, 0x81400000] is mapped inwards the phase 1 translation tabular array using offset degree “Section” descriptors, each of which is responsible for translating a 1MB make of memory. We tin likewise consider that, every bit expected, this make is marked UXN as well as non-PXN - thus EL1 is allowed to execute retentiveness inwards these ranges, piece EL0 is prohibited from doing so. However, much to a greater extent than surprisingly, the entire make is marked amongst access permission (AP) flake values of “00”. Let’s consult the ARM VMSA to consider what these values indicate:

s gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection


Aha - so inwards fact this agency that these retentiveness ranges are likewise readable as well as writable from EL1! Combining all this together, nosotros make the decision that the entire physical make of [0x80000000, 0x81400000] is mapped every bit RWX inwards the phase 1 translation table.

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

After just about reversing, nosotros detect 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 as well as to analyse it inwards detail, similar to our previous piece of work on the phase 1 translation table.

s gist is the final security boundary standing betwixt an assaulter as well as 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 exercise this script inwards club 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 consider 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 residuum of this weblog post service as well as focus of PAs instead.

More importantly, however, nosotros tin consider that our retentiveness make of involvement is non marked every bit XN, every bit is expected. After all, the gist should hold out 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 gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection
So this seems a lilliputian odd… Does this hateful that the entire kernel’s code make is marked every bit RWX inwards both the phase 1 as well as the phase 2 translation table? That doesn’t seem to add together up. Indeed, trying to write to retentiveness addresses containing EL1 gist 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 gist finishes its initialisation it volition somehow asking RKP to modify these mappings inwards club to protect its ain retentiveness ranges.

Indeed, looking ane time once to a greater extent than at the kernel’s initialisation routines, nosotros tin consider that soon after booting, the EL1 gist 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 consider that this command provides RKP amongst many of the retentiveness ranges belonging to the kernel. In club 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 brand it 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 role telephone call upward to a higher house is used inwards club to modify the phase 2 access permissions for a given PA retentiveness range. Calling the role amongst these arguments volition motility the given retentiveness make to hold out marked every bit read-only inwards the phase 2 translation. This agency that soon after booting the EL1 kernel, RKP does indeed lock downwards write access to the kernel’s code ranges.

...And yet, something’s soundless missing here. Remember that RKP should non alone foreclose the kernel’s code from beingness modified, but it aims to likewise foreclose attackers from creating novel executable code inwards EL1. Well, piece the kernel’s code is indeed beingness marked every bit 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 as well as the corresponding physical address) is shifted yesteryear a randomised “slide” value. Moreover, since the Linux gist assumes that the virtual to physical offset for gist addresses is constant, this agency that the same slide value is used for both virtual as well as physical addresses.

However, there’s a tiny snag hither -- the address make nosotros examined before on, the same ane which is marked RWX is both the phase 1 as well as phase 2 translation table, is much larger than the kernel’s text segment. This is, partly, inwards club to allow the gist to hold out placed somewhere inside that share after the KASLR slide is determined. However, every bit we’ve just seen, after choosing the KASLR slide, RKP only protects the make spanning from “_text” to “_etext” - that is, alone the share containing the kernel’s text after applying the KASLR slide.

s gist is the final security boundary standing betwixt an assaulter as well as 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 every bit RWX inwards both the phase 1 as well as phase 2 translation tables! Thus, nosotros tin only write novel code to these regions as well as execute it freely inside the context of EL1, thus bypassing the code loading mitigation. I’ve included a pocket-size PoC which demonstrates this issue, here.

Mitigation #3 - Bypassing EL1 Memory Controls


As we’ve just seen inwards the previous section, just about of RKP’s stated goals require retentiveness controls that are enforced non alone inwards the phase 2 translation, but likewise 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 every bit PXN. These goals require RKP to have got just about shape of command over the contents of the phase 1 translation table.

So how just does RKP brand for certain 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 share which is marked every bit read-only inwards the phase 2 translation tables. This, inwards effect, disallows EL1 code from straight modifying the translation tables themselves. Secondly, the gist is instrumented (a shape of paravirtualisation), inwards club 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 upward an RKP command, informing it of the requested change.

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

Or exercise they?

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

Obviously, such operations cannot hold out permitted yesteryear RKP. In club to allow the hypervisor to bargain amongst such situations, the “Hypervisor Configuration Register” (HCR) tin hold out leveraged. Recall that the HCR allows the hypervisor to disallow for certain operations from beingness performed nether EL1. One such functioning which tin hold out trapped is the modification of the EL1 retentiveness management command registers.


In the instance of RKP on Exynos devices, piece 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 soundless doesn’t guarantee they stay protected. This is truly quite a fragile province of affairs - the Linux gist requires just about access to many of these registers inwards club to perform regular operations. This agency that piece just about access tin hold out denied yesteryear RKP, other operations call for to hold out inspected carefully inwards club to brand for certain they exercise non violate RKP’s security guarantees, before allowing them to proceed. Once again, we’ll call for to contrary engineer RKP’s code to assess the situation.

s gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

As nosotros tin consider above, attempts to modify the location of the translation tables themselves, outcome inwards RKP correctly verifying the entire translation table, making for certain it follows the allowed phase 1 translation policy. In contrast, at that topographic point are a yoke of crucial retentiveness command registers which, at the time, weren’t intercepted yesteryear RKP at all - TCR_EL1 as well as 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 flake of crucial importance inwards our scenario is the SCTLR_EL1.M bit.


This flake denotes the patch of the MMU for phase 1 translation inwards EL0 as well as EL1. Therefore, only yesteryear unsetting this bit, an assaulter tin disable the MMU for phase 1 translation. Once the flake is unset, all retentiveness translation inwards EL1 map straight to IPAs, but to a greater extent than importantly - these retentiveness translation exercise non have got whatever access permissions checks enabled, effectively making all retentiveness ranges considered every bit RWX inwards the phase 1 translation. This, inwards turn, bypasses several of RKP’s assurances, such every bit making for certain that alone the kernel’s text is non marked every bit 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 for certain telephone commutation ways inwards which an assaulter may leverage it inwards club 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 organisation is operating. Normally, AARCH64 Linux kernels exercise 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 club to brand for certain that EL1 cannot gain access to it. Indeed, reversing the corresponding code inside RKP reveals that it does just that:

s gist is the final security boundary standing betwixt an assaulter as well as total command over  Lifting the (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

However, every bit nosotros tin consider inwards the moving-picture demo above, the phase 2 protection is alone performed on a 4KB share (a unmarried page). This is because when using a 4KB translation granule, the translation authorities has a translation tabular array size of 4KB. However, this is where we, every bit an attacker, come upward in. What if nosotros were to alter the value of the translation granule to 64KB, yesteryear modifying TCR_EL1.TG0 as well as TCR_EL1.TG1?


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


Lastly, it should ane time to a greater extent than hold out noted that piece 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 club to modify the registers above. I’ve written a pocket-size 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, at that topographic point be several other retentiveness regions which may comprise potentially sensitive information that should non hold out accessible yesteryear code running inwards EL0 as well as 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 out accessible to Android itself.

In club to enforce such protections, RKP explicitly unmaps a few retentiveness ranges from the phase 2 translation table. By doing so, whatever endeavour to access these PA ranges inwards EL0 or EL1 volition outcome inwards a translation fault, consequently crashing the gist as well as rebooting the device.

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

s gist is the final security boundary standing betwixt an assaulter as well as 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 rattling share beingness unmapped from the phase 2 translation table, thus ensuring that code inwards EL1 cannot modify it. However, mayhap nosotros could detect just about other way to command phase 2 mappings, but leveraging RKP itself.

For example, every bit we’ve previously seen, for certain operations such every bit setting TTBR1_EL1 outcome inwards changes to the phase 2 translation table. Combing over the RKP binary, nosotros come upward across ane such operation, every bit 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, as well as if so proceeds to telephone call upward rkp_s2_page_change_permission inwards club to modify the access permissions on this make inwards the phase 2 translation table. Digging deeper into the role reveals that this set of parameters is used to announce the share every bit read-only as well as XN.

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

This allows us to re-map whatever phase 2 unmapped share (albeit every bit read-only as well as XN) from EL1. I’ve written a pocket-size PoC which demonstrates the number yesteryear phase 2 re-mapping RKP’s physical address make as well as reading it from EL1.

Design Improvements to RKP


After seeing just about specific issues inwards this weblog post, highlighting how the dissimilar defense strength mechanisms of RKP could hold out subverted yesteryear an attacker, let’s zoom out for a minute as well as think well-nigh just about pattern choices that could serve to strengthen RKP’s security posture against hereafter attacks.

First, RKP on Exynos devices is currently beingness 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, as well as afterwards booted yesteryear EL3. Ideally, I believe the same model used on Qualcomm devices should hold out adopted for Exynos every bit well.

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

As inwards interim improvement, RKP decided to nix out the RKP binary resident inwards EL1’s code during initialisation. This improvement volition curl out inwards the adjacent Nougat milestone release of Samsung devices, as well as 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 gist to subvert the initialization of EL2, which requires a to a greater extent than extensive modification.

Second, RKP’s code segments are currently marked every bit both writable as well as executable inwards TTBR0_EL2. This, combined amongst the fact that SCTLR_EL2.WXN is non set, allows an assaulter to exercise whatever retentiveness corruption primitive inwards EL2 inwards club 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 out 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 out used yesteryear an assaulter to straight modify RKP’s code itself, thus gaining code execution inside it.

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

Third, RKP should lock downwards all retentiveness command registers, unless they absolutely must hold out used yesteryear the Linux kernel. This would foreclose abuse of several of these registers which may subtly comport on the system’s behaviour, as well as inwards doing so, violate assumptions made yesteryear RKP well-nigh the kernel. Where these registers have got to hold out modified yesteryear EL1, RKP should verify that alone the appropriate bits are accessed.

RKP has since locked downwards access to the 2 registers mentioned inwards this weblog post. This is a adept measuring inwards the right direction, as well as unfortunately every bit access to just about of these registers must hold out 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, at that topographic point should hold out just about distinction betwixt phase 2 unmapped regions that were only never mapped in, as well as those which were explicitly mapped out. This tin hold out achieved yesteryear storing the retentiveness ranges corresponding to explicitly unmapped regions, as well as disallowing whatever modification that would outcome inwards remapping them inside RKP. While the number I highlighted is at nowadays fixed, implementing this extra measuring would foreclose farther similar issues from cropping upward inwards the future.

Komentar

Postingan populer dari blog ini

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...

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...

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-co...