DISCLAIMER: The things I describe below and fiddiling with executeable bits in general are only intended for people knowing what they are doing. It might introduce new bugs, prevent you from future updates, brick your phone and probably give your dog diarrhea while he is home alone.
So as you might have already learned Google messed up their patching leaving your Android device still vulnerable to nasty integer overflow vulnerabilities. Several blogposts already discussed this such as the ones from Exodus, Fortigate and Zimperium. There is a new CVE identifier CVE-2015-3864 adressing this.
Despite being fixed in the AOSP repositories until today I did not see any OTA patch that fixes CVE-2015-3864. Actually the majority of users is totally left alone by vendors that got money from them. I guess this says much about the importance of security for Android vendors including Google. Google even claims the bad patch is not so bad because you have ASLR. Following that logic they did not need to issue any patch at all…
This is really annoying me, especially since I got a few test devices here that I rely on, and which are still vulnerable. So I took some break and tried to fix at least some of the overflows.
If you want to fix stagefright yourself you basically have three options:
- Mititgation (some good advice from Zimperium)
- Compiling libstagefright from the AOSP sources
- Patching the libstagefright.so binary
The first two options were not good enough for me as most of the mitigations are incomplete and I don’t want to set up a full Android build environment (actually I can’t at all since for my device since it’s some custom Android build for which I don’t have the source).
So I went with option 3 and fired up my favorite patching tool Hopper.
As I would like to create the stagefright patch in my lunch break this means I don’t want to do too much magic on the binary. So the actually I want to avoid adding new code segments, hook any functions, instrument, etc. So let’s focus on modifications that we could do using a hex editor.
If you look at the original unpatched source code in media/libstagefright/MPEG4Extractor.cpp you will see that after creating the uint8_t buffer object, memcpy is guarded by “if (size > 0)”.
The check was probably inserted to speed up things (saving a function call) or (unlikely) because a call to memcpy with zero size and uninitialized pointers counts as undefined behaviour. Actually here the only possible uninitialized pointer argument could be “const void *data;” which should come from “mLastTrack->meta->findData(kKeyTextFormatData, &type, &data, &size)”. In practice however the Android (and GNU) implementation of memcpy will treat calls to memcpy with a size of zero and an uninitialized src-argument as a no-op.
So why not trade the “unnecessary” (please feel free to prove me wrong) check for one that will catch the overflow.
We disassemble the original “libstagefright.so” from a Lenovo device running Android 5 and look for the assembly resulting from the code above:
Okay great, at 0xb3634 “size” is loaded from the stack and put into r2 (third argument by calling convention used on Android-ARM). Next if r2 is zero the call to memcpy is skipped.
So if we don’t check “size > 0” we get one instruction for us to catch the overflow. But how to catch a numeric overflow in one instruction?
CPU flags and conditional branching to the rescue!
Using Hopper we change the assembly a bit:
By changing the add instruction at address 0xb3628 to adds (add with flags), the carry flag is set when the target register can not hold the result. We use a conditional branch instruction bhs (bcs) to bail out if that is the case.
Checking for arithmetic overflows in asm is pretty elegant right? Not the minefield that C/C++ represents in that in this regard.
So now we have before:
And afterwards CVE-2015-3864 is fixed:
Of course we are still vulnerable to the various other bugs with CVE’s that were detected besides this one integer overflow..still one bug less, and a good excercise!
Handling of this vulnerability shows that vendors don’t care about your security, so we need to take action!
If you are interested here is a version of libstagefright for the Lenovo Vibe X2 that has the patch:
If you create patches on your own for other devices, feel free to contact me.