phhusson / Superuser

Keeping koush's Superuser fresh
GNU General Public License v3.0
426 stars 50 forks source link

Considerations for Android 6.0 support #4

Open lbdroid opened 9 years ago

lbdroid commented 9 years ago

From what I can tell, the difference between 5.x and 6.0 basically involve a tightened up sepolicy. Specifically (and most likely), things like https://android.googlesource.com/platform/external/sepolicy/+/356df32778732aa576e15071bf2736fbbd778b77%5E!/#F0

The evil closed source supersu has implemented a sepolicy patcher in their "supolicy" command. It takes the factory sepolicy file and generates a "patched" sepolicy that works with the rest of their code. HOWEVER, they refuse to even document the changes they are making to the sepolicy, which makes it impossible to trust them.

It is likely that a similar policy patch will be required. It should be possible to build it into an update zip that can repack the boot.img similar to things like http://forum.xda-developers.com/nexus-6/development/fix-fed-patcher-forceencrypt-disable-t3203867

I also suggest that consideration should be made to having the entire su system (save for the android apk) made part of the boot.img rather than breaking dmverity on the system partition. Since the boot.img will require modification either way, it is trivial to add the rest in there. Possibly even simplifies the process, since there are other hijacks made available for obtaining the init context from the boot.img.

phhusson commented 9 years ago

Oops, you're right, thanks. Now, it's not the app who calls app_process, I guess it's system_server who does it, so it would still work (unless it explicitly forgets LD_PRELOAD)

phhusson commented 9 years ago

Changing file_contexts should be enough to change context of /sbin/su, no?

lbdroid commented 9 years ago

No, the ramdisk doesn't store the extended attributes, which means that it has to be restored after selinux is initialized. I spent about 3 hours bashing my head against a wall last night figuring this out.

In fact, I'm targeting init.c specifically because that is where google does precisely this. Line 1048 they restore the context on /init itself and cause it to self-re-exec with the new context.

phhusson commented 9 years ago

Yes, but file_contexts is the file read at run-time to apply context

lbdroid commented 9 years ago

Right, but to make it apply, you still need to run restorecon, which it does NOT do automatically.

lbdroid commented 9 years ago

http://blog.gmane.org/gmane.comp.security.seandroid/month=20150601 http://comments.gmane.org/gmane.comp.security.seandroid/2301

The first link is a discussion about adding built-in file context support to the rootfs, the second is discussing adding a restorecon_recursive("/sbin") to init.c.

You should recognize the name Nick Kralevich from both of those threads.

lbdroid commented 9 years ago

Actually may not have to go to that extreme, since with daemon mode the application doesn't need to make the transition, just the daemon, and that can be transitioned using seclabel from the init.zygote

phhusson commented 9 years ago

Thanks for all your research, nice to know. Having a transition when calling /sbin/su would be great to have better protection on the su socket/pts, and I don't see a problem in doing remount rw/restorecon/remount ro. I don't think manufacturer would break that.

But I agree that for first steps seclabel is enough.

lbdroid commented 9 years ago

Good point!

lbdroid commented 9 years ago

I've managed to get su working through adb (shell context), having selinux enforcing.

phhusson commented 9 years ago

Nice :-) Next step is from untrusted_app

lbdroid commented 9 years ago

Correction: I actually have it working also from untrusted_app, there are just some context screwups that limit what I can do with it.

If I try using the --context option, it gives a hard time connecting to the daemon.

lbdroid commented 9 years ago

Like this: (--context u:r:system_app:s0)

[  508.008088] type=1400 audit(1445529993.672:76): avc: denied { getattr } for pid=5394 comm="sh" path="/dev/pts/5" dev="devpts" ino=8 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
[  508.008677] type=1400 audit(1445529993.672:77): avc: denied { ioctl } for pid=5394 comm="sh" path="/dev/pts/5" dev="devpts" ino=8 ioctlcmd=5401 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
[  508.008922] type=1400 audit(1445529993.672:78): avc: denied { getattr } for pid=5394 comm="sh" path="/dev/pts/5" dev="devpts" ino=8 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
[  508.009156] type=1400 audit(1445529993.672:79): avc: denied { read } for pid=5394 comm="sh" path="/dev/pts/5" dev="devpts" ino=8 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
phhusson commented 9 years ago

I guess it's acceptable to whitelist all contexts access to untrusted_app_devpts, since we still have unix permissions... ? (only problem would be with dac_override)

phhusson commented 9 years ago

Or su daemon could whitelist on-the-fly, when su --context XXXX is called.

lbdroid commented 9 years ago

This is an interesting one, running --context u:r:su:s0 yields root, then running "dumpsys power" it spits out this;

[  690.664395] type=1400 audit(1445530176.322:80): avc: denied { read write } for pid=5679 comm="dumpsys" path="/dev/pts/5" dev="devpts" ino=8 scontext=u:r:system_server:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0

Note that that is from system_server, which I wasn't expecting to see.

lbdroid commented 9 years ago

Can it be whitelisted on the fly without reloading the policy? If possible, it would be nice to be able to block policy reloads like google has it, since one bad application could, in theory, completely destroy the security of the device if it is able to obtain that kind of access.

lbdroid commented 9 years ago

Hmm, looks like the auto transition isn't happening from untrusted_app.

u:r:untrusted_app:s0:c512,c768 u0_a124   6773  6083  su

May have something to do with the categories?

Edit: note that I am actually using a restorecon on the su binary and auto transitions.

phhusson commented 9 years ago

No, you obviously need to reload policy to whitelist, that's the problem. My guess is google no longer has the ability to reload policy, since they removed load_policy from every context.

What do you get in audit log?

lbdroid commented 9 years ago

Nothing at all in the audit log regarding the transition.

phhusson commented 9 years ago

Do you have any dontaudit in your policy?

lbdroid commented 9 years ago

Default policy is loaded with dontaudit's. I'm looking at them right now.

lbdroid commented 9 years ago

May not actually be correct that the auto transition isn't working. Looks like some of these things aren't actually reported from ps -Z.

For instance, from adb, I ran "su --context u:r:system_app:s0", yet from a different adb, it still shows as u:r:su:s0, but when I run things from the one on system_app, it appears to be restricted to system_app anway.

# ps -Z                                                           
LABEL                          USER      PID   PPID  NAME
u:r:system_app:s0              system    1651  320   com.quicinc.cne.CNEService
u:r:system_app:s0              system    2716  320   com.qualcomm.telephony
u:r:system_app:s0              root      6997  6992  sh
u:r:system_app:s0              root      7110  6997  ps

Mind you, the su daemon does appear to be reported normally after the auto transition.

phhusson commented 9 years ago

Can you check you can read /proc//attr/current and that it contains the same result as ps -Z?

lbdroid commented 9 years ago

No such file or directory. Remember that I'm running factory nexus 6 kernel.

lbdroid commented 9 years ago

Ah, interesting.

su --context u:r:system_server:s0
Cannot execute /system/bin/sh: Permission denied

Which is good. It means that I have, indeed, entered the system_server domain.

phhusson commented 9 years ago

sorry I meant /proc/ PID /attr/current

lbdroid commented 9 years ago

It matches ps -Z

lbdroid commented 9 years ago
$ grep -rn untrusted_app_devpts *
grep: Android.bp: No such file or directory
grep: bootstrap.bash: No such file or directory
Binary file out/target/product/shamu/root/sepolicy matches
Binary file out/target/product/shamu/obj/ETC/sepolicy_intermediates/sepolicy matches
out/target/product/shamu/obj/ETC/sepolicy_intermediates/policy.conf:3843:type untrusted_app_devpts, fs_type;
out/target/product/shamu/obj/ETC/sepolicy_intermediates/policy.conf:3847:type_transition untrusted_app devpts:chr_file untrusted_app_devpts;
out/target/product/shamu/obj/ETC/sepolicy_intermediates/policy.conf:3851:allow untrusted_app untrusted_app_devpts:chr_file { open getattr read write ioctl };
out/target/product/shamu/obj/ETC/sepolicy_intermediates/policy.conf.dontaudit:3843:type untrusted_app_devpts, fs_type;
out/target/product/shamu/obj/ETC/sepolicy_intermediates/policy.conf.dontaudit:3847:type_transition untrusted_app devpts:chr_file untrusted_app_devpts;
out/target/product/shamu/obj/ETC/sepolicy_intermediates/policy.conf.dontaudit:3851:allow untrusted_app untrusted_app_devpts:chr_file { open getattr read write ioctl };
Binary file out/target/product/shamu/obj/ETC/sepolicy_intermediates/sepolicy.dontaudit matches

I'm inclined to open that up to everything. Its already opened up to the least trustworthy domain in existence, untrusted_app...

phhusson commented 9 years ago

Which actually makes sense, since it's the app who creates it -_-'

lbdroid commented 9 years ago

Right.

lbdroid commented 9 years ago

allow domain untrusted_app_devpts:chr_file { open getattr read write ioctl };

Probably can narrow that down at some point.

lbdroid commented 9 years ago

Hmm, well closer now... If I don't set the context, or leave the context alone, I can now successfully run "dumpsys power" from terminal emulator. If I set the context to system_app, it dies with this;

<36>[  126.161802] type=1400 audit(1445535147.549:72): avc: denied { getattr } for pid=4741 comm="sh" path="/dev/pts/3" dev="devpts" ino=6 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
<36>[  126.162859] type=1400 audit(1445535147.549:73): avc: denied { getattr } for pid=4741 comm="sh" path="/dev/pts/3" dev="devpts" ino=6 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
<36>[  126.178793] type=1400 audit(1445535147.569:74): avc: denied { dac_override } for pid=4741 comm="sh" capability=1 scontext=u:r:system_app:s0 tcontext=u:r:system_app:s0 tclass=capability permissive=0
<36>[  126.194515] type=1400 audit(1445535147.579:75): avc: denied { write } for pid=4741 comm="sh" path="/dev/pts/3" dev="devpts" ino=6 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0
<36>[  126.194667] type=1400 audit(1445535147.579:76): avc: denied { read } for pid=4741 comm="sh" path="/dev/pts/3" dev="devpts" ino=6 scontext=u:r:system_app:s0 tcontext=u:object_r:untrusted_app_devpts:s0:c512,c768 tclass=chr_file permissive=0

I'm thinking that system_app may not be a member of domain... if that makes any sense...

Yep, appdomain. Still not working though.

lbdroid commented 9 years ago

Its the category.

I don't know why it works with system_server and not system_app, but when I use --context "u:r:system_app:s0:c512,c768" it works beautifully -- except for dac_override, for which I don't see any pressing need to permit.

I'm pretty sure that the auto transition is failing on the same category issue.

phhusson commented 9 years ago

Ok thanks. I know pretty much nothing about categories, I'll try to understand what those are. (I guess that here it's used to separate apps from others?)

lbdroid commented 9 years ago

From what I can tell, they seem to, at least on Android, be set universally to c512,c768. As I understand it, this actually implies c0,c512,c768

That is, when they are set to anything besides nothing at all. Nothing at all implies c0.

phhusson commented 9 years ago

Ok, from what I'm reading ( https://wiki.gentoo.org/wiki/SELinux/Tutorials/SELinux_Multi-Level_Security ), categories are totally orthogonal to other parts of SELinux, and if two systems doesn't share a common category, they can't communicate. So I guess just setting c512 would be enough? (or 768)

lbdroid commented 9 years ago

Should be. Or a range c0.cwhatever.

lbdroid commented 9 years ago

Heh, sit here bashing my head against a wall for an hour trying to figure out why something isn't working and there's no audit message... two lines up an execv. Duh.

lbdroid commented 9 years ago

Yeah, there we are. Now I have it starting in enforcing, rather than switching there after booting.

lbdroid commented 9 years ago

FYI: I tried out the categories a bit, and turns out they work on an AND basis.

So if the resource you want to access has c512,c768, you need to match them both. Looks like it has to match precisely also, so throwing in a c123 along with the other two doesn't work.

lbdroid commented 9 years ago

I think that the category problem might be with just terminal emulator. Reason it seems that way is that I have another program I wrote that disables and kills some services on bootup, which has to use the same system_app context (well maybe it doesn't have to any more...) but doesn't have the problem with the pts. It just works without complaint.

lbdroid commented 9 years ago

I've updated my patch here: https://github.com/lbdroid/AOSP-SU-PATCH

There is one additional change that will be necessary for running restorecon from a script, if you notice line 104 of the patch, it is necessary to authorize init for relabelto su_exec.

Current state is: enforcing, with policy reload disabled.

The policy patches, FOR USERDEBUG are pretty straightforward. I'll have a look at user build policies tomorrow.

lbdroid commented 9 years ago

This is the actual request window;

[ 4208.208968] type=1400 audit(1445560975.200:36): avc: denied { write } for pid=15987 comm="Thread-745" name=".socket15976" dev="tmpfs" ino=107615 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:device:s0 tclass=sock_file permissive=0
[ 4215.717367] type=1400 audit(1445560982.710:37): avc: denied { getattr } for pid=14729 comm="ruser:superuser" path="/dev/com.koushikdutta.superuser/.socket15976" dev="tmpfs" ino=107615 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:device:s0 tclass=sock_file permissive=0
lbdroid commented 9 years ago

This appears to be an instance of creating a socket, which inherits its parent's context, and then being locked out as a result.

# Sockets under /dev/socket that are not specifically typed.
neverallow appdomain socket_device:sock_file write;

This might be a good application for a filetrans_pattern rule.

Edit... no, that wouldn't do it, would it... I mean that neverallow rule doesn't really have the implication that it prevents device:sock_file

lbdroid commented 9 years ago

Its another problem with these stupid categories. u:r:untrusted_app:s0:c512,c768 u:r:foo:s0 Even when there is an allow rule for untrusted_app --> foo, foo is category c0 u:r:foo:s0 == u:r:foo:s0:c0 But because u:r:untrusted_app:s0:c512,c768 explicitely does NOT include c0, it therefore can't access the resource with label foo.

Also unfortunate thing... categories don't appear to inherit from their parent.

lbdroid commented 9 years ago

There might be a better way to do this; have an android/java service listening for connections from the su client binary, rather than the su binary waiting on the application to call it back. It can still be launched with an am start.

lbdroid commented 9 years ago

Or an easier way...

mlstrustedobject = ignore category when dealing with this object. mlstrustedsubject = ignore this process's category always.

I added to the sepolicy as follows;

type su_device, dev_type, mlstrustedobject; allow untrusted_app su_device:sock_file rw_file_perms; allow untrusted_app su_device:dir rw_file_perms; allow untrusted_app su_device:dir r_dir_perms; (I think the dir rw_file_perms is probably unnecessary)

And then chcon u:object_r:su_device:s0 on /dev/{the su client's path}

Then the auth window started working.

lbdroid commented 9 years ago

filetrans_pattern(unconfined_t, admin_home_t, dir, ssh_home_t, “.ssh”)

first param: calling process context (should be untrusted_app), second param: parent directory context (/dev is u:object_r:device:s0), third param: type of object being created (dir is correct), fourth param: new context to apply to the directory (u:object_r:su_device:s0), fifth param: the name of the what is being created, which seems to come from the package name.

lbdroid commented 9 years ago

I'm having no luck with the auto transitions. I'm thinking that I may have the calling process context wrong.

Ah, I get it... its not untrusted_app, its actually making the transition as su...

Working, and its actually better not to use a name pattern in this case, since we can transition using file_type_auto_trans(su, device, su_device)