dxwu/BinderFilter

Port to Newer Kernel? 3.18 and/or 4.4

Opened this issue · 15 comments

Hey,

I watched your presentation at shmoocon on youtube. I found it quite interesting and was hoping to have a stab at trying out BinderFilter. Unfortunately, it looks like your code only works on very old kernels... Is there any change this code might be ported to msm-3.18 or higher??

I'm hoping to try it out on my Pixel... I'm more than capable of building AOSP, my kernel, android apps, etc... I was able to manually apply your changes and fix up a few errors/warning, But the changes needed in your code for new kernels/binder are a little beyond me...

thanks.

dxwu commented

Hi 979,

I can look into porting the module code to a higher kernel, but it may take a week or so. I can also try to debug the kernel issues you're having if you send me specific errors.

Thanks,
David

Hey David,

First, thanks for the response! ... I'm not not in a rush and I am sure that you are busy, but that would be absolutely great if you can have a look at updating to a newer kernel.

When I'm in front of that machine, I can do a build again and show you specific errors.

Thanks again!

Update: So I did manage to get the kernel module to build and I can see /dev/binderfilter on my Pixel.

The errors during the compile went as follows;

  1. fix the #include error in binder_filter.h; https://pastebin.com/qKaHmjRe
  2. Next, I hit this;

drivers/staging/android/binder.c: In function ‘binder_transaction’:
drivers/staging/android/binder.c:2309:3: error: incompatible type for argument 4 of ‘filter_binder_message’
t->sender_euid, (void*)offp, tr->offsets_size);
^
drivers/staging/android/binder.c:46:12: note: expected ‘int’ but argument is of type ‘kuid_t {aka struct }’
extern int filter_binder_message(unsigned long, signed long, int, int, void*, size_t);
^~~~~~~~~~~~~~~~~~~~~

So I changed the 4th argument. compile continues.

  1. I had to change fp->type in binder_filter.c to fp->handle. [line: 978] (but I'm not sure if that's correct)...But it continues to compile....

  2. finally there were a few format warnings, all of which I corrected (enough to make the compiler happy, but not necessarily right);

printk(KERN_INFO "BINDERFILTER: type BINDER_TYPE_FD, handle %ld\n", fp->handle);

I did this on my own branch of 3.18.75 (Marlin/Google Pixel) so it was easy to create a diff. Which is right here; https://pastebin.com/2cNQiELa

my kernel sources are here: https://github.com/nine7nine/marlin/tree/EX-NoShadez-3.18.75-gcc6-plus

Unfortunately, I haven't gotten Picky / The Middleware to compile to test. I did get it stup in android studio, but I'm having a bit of a spat with it. LOL...Like this;

:app:compilePicky-jniMips64DebugSharedLibraryPicky-jniMainC
/tmp/picky-jni-69ae83.s: Assembler messages:
/tmp/picky-jni-69ae83.s:1391: Warning: unrecognized section type
/tmp/picky-jni-69ae83.s:1391: Warning: entity size for SHF_MERGE not specified
/tmp/picky-jni-69ae83.s:1391: Error: junk at end of line, first unrecognized character is `0'

never seen anything like that before, not sure how to fix that... I'm going to have to google around.

anyhoo. Again, not rush. but this is where I'm at so far...

UPDATE 2:

You can ignore the above regarding Picky and the middleware... I've have Picky built and I can build middleware.c with both the toolchain in your sources and the prebuilt toolchain in android-ndk, specifically; /opt/android-sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin

(although, I would imagine your middleware code should be ported to aarch64 / arm64? .. like the kernel code?)

Anyway, I have managed to get BinderFilter to work somewhat... I can actually get some output using ./binderfilter.py ... there are a few issues. Selinux being one of them, as newer devices have much stricter sepolicy than old devices.... For now, whenever I am testing, I am setting selinux to permissive. (I can inject sepolicy fixes later)

Here is a document that sort of outlines what is working/not working for me; https://pastebin.com/hMXcDG7U

I also had to modify printIpcBuffersOnce() to use root (in binderfilter.py), otherwise it doesn't have enough permissions.

def printIpcBuffersOnce():
checkIpcBuffersAndFilterEnabled()
cmd='adb shell su -c dmesg | grep "BINDERFILTER"'
call(cmd, shell=True)

After that, it works. Sample output; https://pastebin.com/wUscm90w

Where I am stuck is applying rules, it doesn't work as expected. I get this sort of thing;

android.permission.RECORD_AUDIO:10070:1:0:
Write_len: 48
Fatal error: Policy could not be successfully applied!
Policy expected: android.permission.RECORD_AUDIO:10070:1:0:
but was:

Reading GPS also throws and error;

./binderfilter.py --get-gps-bytes

Traceback (most recent call last):
File "./binderfilter.py", line 556, in
main(sys.argv[1:])
File "./binderfilter.py", line 532, in main
getGpsStringForBinderFilter(results.latitude, results.longitude)
File "./binderfilter.py", line 266, in getGpsStringForBinderFilter
bLat = bytearray(struct.pack("d", float(latitude)))
TypeError: float() argument must be a string or a number

I assume that I messed up with my kernel patching and/or middleware.c needs to be adjusted to get things working properly. (and possibly updating it for arm64)...

I'm not sure how to fix these problems, but if/when you have the time, I do think it would be great to have BinderFilter find a new life on modern phones/tablets. I'm definitely into helping in any way that I can. Possibly improving Picky, small changes to the middleware (shell stuff) and testing/resolving selinux denials.

Hey David,

I just thought I would give you a friendly nudge and see if you've had any time to look at porting BinderFilter to a newer kernel?. .... not trying to bug you. Just curious 😉

I'm still very interested inuriluzing BinderFilter. I did actually fork Picky and started on some code fixes, just light stuff, like code that LInt points out, but I figured if/when you managed getting BinderFilter working, I would then look at improving Picky's interface/gui, more substantial updating to the app...

myself, I've been working on other Projects; a youtube player for android that I've committed a number of fixes, improvements and features to... and also getting Linaro's Energy Aware Scheduler up and running on the Pixel. It's actually pretty exciting, I've backported most of the code needed from MSM8996/linux-4.4(pixel 2/Op5 devices) to MSM8996/linux-3.18(Pixel 1)...

so there hasn't been any rush or anything, but still. I would love to be able to make use of BinderFilter.

I hope all is well. ttys

dxwu commented

Hey,

I've looked at your documentation- which is very helpful. I need to install the new kernel on my testing device and try to reproduce the issues you've been seeing, which I'm hoping to get around to this weekend. By the way, Picky the android app may be a little lacking compared to the python command-line tool (the command line tool was written more recently and has less complexity when it comes to UI).

Also, if you want to, printk debugging the kernel module may shed some light on your errors
printk(KERN_INFO "BINDERFILTER: test\n");

Hey,

What is your testing device out of curiousity? Well, the nice thing about custom kernels is at least you don't need AOSP sources to do that - just an Arm/Aarch64 toolchain ;)

Regarding picky; I thought as much and I do prefer the commandline tool anyway. I just had thought having a gui app wouldn't hurt either. Maybe it can be extended in the future, but I would be happy even without it... Unreleated, but I had also considered making bilterfilter a proper service in my init.rc script that I generate in Anykernel2 which creating a flashable zip for the kernel. Pretty sure we can set sepolicy there and then inject any additional policies (as an aside)

I'll take a look at adding back binderfilter to my current kernel locally and take a closer look at my errors...

Let me know how things go! and good luck.

I really appreciate you getting back to me, Thanks a lot!

dxwu commented

Hi,

I've updated the binderfilter.py file and that should fix some of your problems. Note that --get-gps-bytes needs some arguments passed to it (see below for proper usage). If your --print-buffers-once functionality works (see below for sample output), then that is most of the functionality and meat of the binderfilter project- this lets you see the buffer contents of all IPC messages, which contain very important information that app developers assume is secret ;). If you want to get the --print-system-context to work with GPS, then try opening google maps or something and asking an app for your location.

I will work more on the issues you're having with setting policy later this week.

root@dwu-VirtualBox:~/BinderFilter/cli# ./binderfilter.py --get-gps-bytes --latitude 43.704979 --longitude -72.287458
243.174.122.192.60.218.69.64.79.62.61.182.101.18.82.192.
root@dwu-VirtualBox:~/BinderFilter/cli# ./binderfilter.py -s -m "android.permission.ACCESS_FINE_LOCATION" -u 1000 -a 3 --modify-data 243.174.122.192.60.218.69.64.79.62.61.182.101.18.82.192.
android.permission.ACCESS_FINE_LOCATION:1000:3:0:243.174.122.192.60.218.69.64.79.62.61.182.101.18.82.192.:
[ 1170.119323] BINDERFILTER: buffer contents: {(0)(0)(1)(0)(30)(0)com.google.android.apps.photos(0)(0)(255)(255)(255)(255)(30)(211)(4)(16)(0)1.23.1.126715090(0)(0)(0)(0)(255)(255)(255)(255)(255)(255)(255)(255)(0)(0)(1)(0)(255)(255)(255)(255)(30)(0)com.google.android.apps.photos(0)(0)n(6)(16)(127)(1)(0)(255)(255)(255)(255)(2)(3)(127)(2)(3)(127)(255)(255)(255)(255)(0)(0)(240)(216)(255)(255)(30)(0)com.google.android.apps.photos(0)(0)(255)(255)(255)(255)(30)(0)com.google.android.apps.photos(0)(0)4(0)com.google.android.apps.photos.app.PhotosAppli}
[ 1170.119781] BINDERFILTER: offsets
[ 1170.119903] BINDERFILTER: buffer contents: (null)
[ 1170.120300] BINDERFILTER: flat binder
[ 1170.121917] BINDERFILTER: BC_TRANSACTION
[ 1170.122070] BINDERFILTER: uid: 1000
[ 1170.122131] BINDERFILTER: data
[ 1170.122192] BINDERFILTER: buffer contents: {(0)@"(0)android.gui.DisplayEventConnection(0)(0)}
[ 1170.122375] BINDERFILTER: offsets
[ 1170.122436] BINDERFILTER: buffer contents: (null)
[ 1170.122589] BINDERFILTER: flat binder
[ 1170.130065] BINDERFILTER: BC_TRANSACTION
[ 1170.130187] BINDERFILTER: uid: 10064
[ 1170.130310] BINDERFILTER: data
[ 1170.130371] BINDERFILTER: buffer contents: {(4)H(28)(0)android.app.IActivityManager(0)(0)(133)*bs(127)(1)(0)(128)0(16)(171) (193)(18)(171) (0)com.google.android.gsf.gservices(0)(0)(0)(0)(0)(0)}
[ 1170.130615] BINDERFILTER: offsets
[ 1170.130676] BINDERFILTER: buffer contents: {D(0)}
[ 1170.130767] BINDERFILTER: flat binder
[ 1170.131958] BINDERFILTER: BC_TRANSACTION
[ 1170.132080] BINDERFILTER: uid: 1000
[ 1170.132141] BINDERFILTER: data
[ 1170.132202] BINDERFILTER: buffer contents: {(4)H(30)(0)android.app.IApplicationThread(0)(0)(2)(0)}
[ 1170.132385] BINDERFILTER: offsets
[ 1170.132476] BINDERFILTER: buffer contents: (null)
[ 1170.132598] BINDERFILTER: flat binder
[ 1170.134796] BINDERFILTER: BC_TRANSACTION
[ 1170.134948] BINDERFILTER: uid: 1000
[ 1170.135009] BINDERFILTER: data
[ 1170.135070] BINDERFILTER: buffer contents: {(0)@(28)(0)android.app.IProcessObserver(0)(0)D(4)(0)(24)'(0)(2)(0)}
[ 1170.135253] BINDERFILTER: offsets
[ 1170.135314] BINDERFILTER: buffer contents: (null)
[ 1170.135467] BINDERFILTER: flat binder
[ 1170.135681] BINDERFILTER: BC_REPLY
[ 1170.135803] BINDERFILTER: uid: 1000
[ 1170.135925] BINDERFILTER: data
[ 1170.135986] BINDERFILTER: data size 1744 too large (max size 500)
[ 1170.136169] BINDERFILTER: buffer contents: {(0)(0)(1)(0)2(0)com.google.android.gsf.gservices.GservicesProvider(0)(0)(22)(0)com.google.android.gsf(0)(0)(0)(0)(1)(0)(255)(255)(255)(255)(0)(0)(0)(0)(255)(255)(255)(255)(0)(0)(240)(216)(255)(255)(255)(255)(255)(255)(22)(0)com.google.android.gsf(0)(0)D(11)(127)(1)(0)(255)(255)(255)(255)(0)(0)(0)(0)(255)(255)(255)(255)(0)(0)(240)(216)(255)(255)(22)(0)com.google.android.gsf(0)(0)(255)(255)(255)(255)(24)(0)com.google.process.gapps(0)(0)(255)(255)(255)(255)(0)(0)E>(136)(24)(8)(0)(0)(0)(0)(0)(0)(0)(}
[ 1170.136505] BINDERFILTER: offsets
[ 1170.136566] BINDERFILTER: buffer contents: {(172)(6)(0)(188)(6)(0)}
[ 1170.136749] BINDERFILTER: flat binder
[ 1170.137359] BINDERFILTER: BC_TRANSACTION
[ 1170.137481] BINDERFILTER: uid: 10064
[ 1170.137573] BINDERFILTER: data
[ 1170.137664] BINDERFILTER: buffer contents: {(4)H (0)android.content.IContentProvider(0)(0)(30)(0)com.google.android.apps.photos(0)(0)(1)(0)*(0)content://com.google.android.gsf.gservices(0)(0)(0)(0)(255)(255)(255)(255)(1)(0)%(0)moviemaker:aam_events_logging_enabled(0)(255)(255)(255)(255)(133)*bs(127)(1)(0)(208)(#(171)@(233)(195)(172)(133)*bs(127)(1)(0)(0)(0)(0)(0)}
[ 1170.137939] BINDERFILTER: offsets
[ 1170.138000] BINDERFILTER: buffer contents: {P(1)(0)}
[ 1170.138183] BINDERFILTER: flat binder
[ 1170.138763] BINDERFILTER: BC_TRANSACTION
[ 1170.138916] BINDERFILTER: uid: 10008
[ 1170.139007] BINDERFILTER: data
[ 1170.139160] BINDERFILTER: buffer contents: {(4)H(28)(0)android.app.IActivityManager(0)(0):(0)com.google.android.providers.gsf.permission.READ_GSERVICES(0)(0)(129)!(0)P'(0)(133)*bs(127)(1)(0)(0)(0)(0)(0)}
[ 1170.139404] BINDERFILTER: offsets
[ 1170.139526] BINDERFILTER: buffer contents: (null)
[ 1170.139678] BINDERFILTER: flat binder
[ 1170.139984] BINDERFILTER: BC_REPLY
dxwu commented

Can you send me the output of the following commands?

adb shell "su -c ls -l /data/local/tmp/bf.policy"
adb shell "su -c cat /data/local/tmp/bf.policy"
adb shell "su -c ls -l /data/local/tmp/middleware"
adb shell "su -c '/data/local/tmp/middleware -a 1 -u 1000 -m binderfiltertest -c 0'"

Hey David,

The output from the above;

[ninez@nine7x cli]$ adb shell "su -c ls -l /data/local/tmp/bf.policy"
-rwxrwxrwx 1 root root 0 2017-11-05 21:07 /data/local/tmp/bf.policy
[ninez@nine7x cli]$ adb shell "su -c cat /data/local/tmp/bf.policy"
[ninez@nine7x cli]$ adb shell "su -c ls -l /data/local/tmp/middleware"
-rwxrwx--x 1 root root 11080 2017-11-05 20:48 /data/local/tmp/middleware
[ninez@nine7x cli]$ adb shell "su -c '/data/local/tmp/middleware -a 1 -u 1000 -m binderfiltertest -c 0'"
Write_len: 48

Appears to be ok, but when actually applying a rule;

[ninez@nine7x cli]$ ./binderfilter.py -s -m "android.permission.RECORD_AUDIO" -u 10177 -a 1
android.permission.RECORD_AUDIO:10177:1:0:
Write_len: 48
Fatal error: Policy could not be successfully applied!
Policy expected: android.permission.RECORD_AUDIO:10177:1:0:
	but was: 

So it still fails... My binder filter is still a bit different from yours. You get this nice clean view, like;

[ 1170.135070] BINDERFILTER: buffer contents: {(0)@(28)(0)android.app.IProcessObserver(0)(0)D(4)(0)(24)'(0)(2)(0)}

Mine is like this; (looks wrong to me)

3307.545522] BINDERFILTER: buffer contents: {(0\xff)@"(0\xff)android.content.pm.IPackageManager(0\xff)(0\xff)&(0\xff)android.permission.UPDATE_DEVICE_STATS(0\xff)(0\xff)(22)(0)com.google.android.gms(0)(0)(0)(0)}

more output; https://pastebin.com/7UwtEdHQ

I think my patch on the kernel is wrong. (?)

If you recall, gcc complained when compiling about arguments being different (documented by me above)... IIRC;

your binder c;

#include "binder_filter.h"
extern int filter_binder_message(unsigned long, signed long, int, size_t, void*, size_t);

my binder.c

#include "binder_filter.h"
extern int filter_binder_message(unsigned long, signed long, int, kuid_t, void*, size_t);

(forth argument was size_t, but replaced with kuid_t)

I didn't actually change the 'hook' in binder_transaction....

Then in binder_filter.c; https://pastebin.com/pqBEXg6n
and binder_filter.h; https://pastebin.com/9K6EmgV8

The only other changes I made to any of your sources, was adding 'su' to use dmesg in the binderfilter.py script, as i mentioned...

and I pointed ccAndMove.sh to use a local toolchain from the NDK; https://pastebin.com/gJfS55yx

My thought here was that carrying around an old toolchain is kind of a hassle - easier to just use a standard one... but I suppose I could try using the old one, if you think that actually makes a difference?

side note: (and part of the reason I asked about your testing device).

Is it possible that some of the work being done on hardening the kernel could be interfering with binderfilter.py failing to apply rules?? (assuming there is nothing wrong with my kernel patching to binder?

https://source.android.com/devices/architecture/kernel/hardening
https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project/Recommended_Settings

some of these are linux-4.4+, so don't apply (completely to my 3.18 marlin kernel)...

a lot of the Grsec/Pax security/hardening patches (or code that accomplishes the same) is making it's way into linux and and android. Not sure if anything so far would break binder filter or not.

dxwu commented

Yeah that's interesting- I'll look into that param change this weekend. It is also possible that the kernel hardening affected the project, but I don't think it would reach as deep as the kernel module layer (compiling changes to the kernel layer should be trusted as an attacker can only recompile the kernel if they have root access and an unlocked bootloader).

My testing device is a 2013 nexus 7 (quite old at this point, but the pure android device I have).

The binder buffer content changes are probably just changing (char) to its hex representation. Remember that the python script is just a command line driver for the underlying middleware on the device- which seems to be working fine.

Can you try the following (applying a rule directly through middleware, then seeing if that rule was applied)

adb shell "su -c '/data/local/tmp/middleware -a 1 -u 1000 -m binderfiltertest -c 0'"
adb shell "su -c cat /data/local/tmp/bf.policy"

Hey,

slow / late response. Life gets a bit busy sometimes - but 100% still interested in Binder Filter... Later this afternoon ~ I'm going to patch (and commit) binder filter into one of my branches ~ so I don't need to keep doing it and can just cherry-pick the commits for Binder-filter....

I don't want to keep it in my main Pixel kernel branch. I also have been working on porting the newest binder code to my kernel - Have not yet tested Binder filter with it, but I expect it shouldn't be much different, as in where it hooks, arguments, etc....

I'll then try just using the middleware to apply rules and see if I have any success there. Because, as you say; the middleware does seem to be working.... I'll let you know later on! :-)

I hope all is well! ttys

dxwu commented

Hope it goes well! Yeah it seems like the middleware is working (which would be great news since the python-middleware interaction is a lot easier to debug than the kernel layer). You could confirm with something like this:

adb shell "su -c '/data/local/tmp/middleware -a 1 -u 1000 -m binderfiltertest -c 0'"
adb shell "su -c cat /data/local/tmp/bf.policy"