Joshua Brindle

How to Win At Security

SE Android and the motochopper exploit

SE Android prevents first exploit against commercial phone

That should have been the title of this post, but alas it is not.

By now you may know that the Samsung Galaxy S4 is the first commercial device shipped with SE Android included.

Included, but not enforcing. If you are familiar with SELinux you know that there is a developer mode (also called permissive) that audits access that would have been denied, but does not actually deny them. This is very useful for developing your policies without having to interate through accesses one at a time (this takes a very very long time with complex software).

The standard way of writing policy is to use permissive mode to run an application, then look at the logs and figure out what the access patterns are, what should be labeled what, write the policy, then try again. Eventually you go into enforcing mode when you are ready to send your product to production.

That is the theory, anyway.

History lesson

Back in the Fedora 2 days (that is 2004) SELinux shipped in enforcing, with a strict policy. It was a catastrophy. Linux users who were accustumed to cat'ing /dev/cdrom, for whatever reason, became angry that they couldn't do it all of a sudden. The targeted policy was then created which would resrtict only high-threat applications, like apache and ssh. Most recently Dan Walsh, over at Red Hat, introduces new application policies to the masses in permissive mode (note, SELinux supports permissive mode per-type, not just system wide) and collects denials from users for a few months, to figure out how people use the applications, since he can't be an expert at every single one. He then switches the policy to enforcing when the policy has been fleshed out.

Lost Opportunity

This is the first commercial phone with SE Android; there is a huge amount of risk to going into the wild in enforcing. I don't know if they were nervous that something like Fedora 2 would happen or it was carrier certification delays or perhaps they just don't think SE Android should be on unless explicitely requested. No matter what the reason, a huge opportunity to show the world the power of SE Android was lost. No worries, though, there will be another opportunity.

The Exploit

Ok, lets look at this exploit and see what would have happened. I don't happen to have a Galaxy S4 in front of me, but the stock recovery image has everything I need to look at this.

First, the exploit is motochopper and was originally written for a Motorola. The reason it works on the S4 is that the phones have similar chipsets. The chipset vendors provide kernel patches, drivers, userspace components, etc to the OEM's. The OEM's then integrate that into their version of Android, normally what Google gives them + their extras. In this case the vulnerability was in the code provided by the chipset, it had a world writable fb0 device node, that allowed an mmap() of kernel memory.

Without a phone in front of me, how on earth could I know that the exploit wouldn't have worked, you ask?

Edit: The above isn't quiet accurate. The vulnerability was a bug in the mainline framebuffer rather than in a specific chipset, which means it may affect even more devices.

The Policy

On the recovery ROM are 2 files that I can use to mount this investigation. I know the exploit mmap()'s /dev/graphics/fb0 so first I want to know what that would be labeled:

$ grep /dev/graphics file_contexts 
/dev/graphics(/.*)?     u:object_r:graphics_device:s0

So, /dev/graphics/fb0 (and indeed everything under the graphics directory) would be labeled graphics_device.

On SE Android the type you get when you use adb shell is shell. So, next I need to look for accesses between shell and graphics_device:

$ sesearch --all -s shell -t graphics_device sepolicy       
Found 7 semantic av rules:
   allow appdomain dev_type : file getattr ; 
   allow appdomain dev_type : dir { ioctl read getattr search open } ; 
   allow appdomain dev_type : lnk_file { read getattr } ; 
   allow appdomain dev_type : chr_file getattr ; 
   allow appdomain dev_type : blk_file getattr ; 
   allow appdomain dev_type : sock_file getattr ; 
   allow appdomain dev_type : fifo_file getattr ; 

Indeed there is no write permission so the mmap attempt to write to kernel memory would fail. This only covers the adb shell case though, and that is typically done by the owner of the device. Granted that this makes problems for BYOD but the more interesting question is, could malicious apps exploit this?

In the seapp_contexts file it shows that third party apps will be labeled untrusted_app, so lets look at that:

$ sesearch --all -s untrusted_app -t graphics_device sepolicy      
Found 7 semantic av rules:
   allow appdomain dev_type : file getattr ; 
   allow appdomain dev_type : dir { ioctl read getattr search open } ; 
   allow appdomain dev_type : lnk_file { read getattr } ; 
   allow appdomain dev_type : chr_file getattr ; 
   allow appdomain dev_type : blk_file getattr ; 
   allow appdomain dev_type : sock_file getattr ; 
   allow appdomain dev_type : fifo_file getattr ; 

Again, no dice. Apps can stat() the file but not read or write it. The same goes for the browser (browser_app) and even platform_app, which includes all of the apps included on the device from Samsung and Google.

But which types can write to the file? Good question, SE Android may be blocking all of this access but we know the vulnerability is there, we should find out what on the system is able to exploit it:

$ sesearch -t graphics_device --allow -c chr_file -p write sepolicy 
Found 7 semantic av rules:
   allow system graphics_device : chr_file { ioctl read write getattr lock append open } ; 
   allow system_app graphics_device : chr_file { ioctl read write getattr lock append open } ; 
   allow mediaserver graphics_device : chr_file { ioctl read write getattr lock append open } ; 
   allow unconfineddomain dev_type : chr_file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton execute_no_trans entrypoint execmod open audit_access } ; 
   allow mm-pp-daemon graphics_device : chr_file { ioctl read write getattr lock append open } ; 
   allow surfaceflinger graphics_device : chr_file { ioctl read write getattr lock append open } ; 
   allow bintvoutservice graphics_device : chr_file { ioctl read write getattr lock append open } ; 

Well, system and system_app, which are pretty powerful either way, granted it is an escalation if you can compromise them. unconfineddomain (hrm.. whats that?), the seapp_contexts file doesn't have any entries for it, so presumably it is there for MDM/MAM vendors to run unconfined apps if they choose to. surfaceflinger obviously needs to be able to write to the graphics device, and possibly mediaserver. bintvoutservice probably does too, and I don't know what mm-pp-domain is, probably a Qualcomm specific thing.

So, there are definitely vectors to get at this, but they involve compromising protected apps (in a real security analysis we'd keep backtracking to see what vectors there are to attack system and system_app, for example) but this exploit wouldn't have been pulled off nearly as easily as it was, if SE Android were enforcing.

Conclusion

Exploits like this are scary, not because of owners that want to root their phones but because, if an owner can do it, it is highly likely that an adversary can. These mobile devices are our lives, they have business data on them, they have private data, and they can be used to steal your money in various ways (such as premium SMS's). There will not be a shortage of vulnerabilities until OEM's and users alike start thinking from a security mindset. The tools are there, no OEM has an excuse not to use them.

It may not be a bad idea to set SE Android into enforcing once you've rooted your phone, so that malicious apps don't take advantage of the same vulnerability, if I get my hands on a GS4 I'll blog about doing that.