Introduction to Patch Diffing for Android Kernel Exploits
Patch diffing is a highly effective methodology in offensive security, particularly for uncovering kernel vulnerabilities. By comparing different versions of a kernel’s source code, security researchers can pinpoint changes that indicate bug fixes, sometimes revealing the very bugs they were designed to patch. For Android kernel exploitation, this technique is invaluable, allowing us to identify Use-After-Free (UAF) vulnerabilities – a class of memory corruption bugs often leading to powerful arbitrary code execution capabilities within the kernel context.
This tutorial will guide you through the process of setting up a patch diffing environment for Android kernels, obtaining relevant sources, performing the diff, and critically analyzing the output to identify potential UAF fixes that can be reverse-engineered into exploitable vulnerabilities.
Prerequisites and Environment Setup
Before diving into the intricate world of kernel patch diffing, ensure you have the following prerequisites and a suitable environment:
- Linux Workstation: A powerful Linux machine (Ubuntu, Debian, Fedora) is recommended.
- Disk Space: Android kernel sources and build artifacts require significant disk space (50-100GB).
- Toolchain: An ARM64/AArch64 cross-compilation toolchain. The Android NDK often provides suitable toolchains, or you can use a pre-built one like
aarch64-linux-gnu-gcc. - Kernel Sources: You’ll need at least two versions of the target Android kernel. Typically, this involves a vulnerable version and a patched version.
- Familiarity: Basic understanding of C, Linux kernel internals, and Git.
Setting Up the Toolchain
One way to get a reliable toolchain is to use the Android NDK. Download and extract it:
wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip
unzip android-ndk-r25b-linux.zip
export PATH=$PATH:$(pwd)/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin/
Alternatively, use a system-provided toolchain if available:
sudo apt update
sudo apt install crossbuild-essential-arm64
Verify your setup:
aarch64-linux-android-gcc --version
# or
aarch64-linux-gnu-gcc --version
Obtaining Kernel Sources and Patches
The first crucial step is acquiring the kernel source code for the versions you intend to compare. For Android devices, these often come from two primary sources:
- Android Open Source Project (AOSP): Google releases kernel source for Pixel devices and generic Android builds.
- Device Manufacturers (OEMs): OEMs like Samsung, Xiaomi, etc., often provide their kernel sources, usually on dedicated developer portals or through their Git repositories.
Cloning AOSP Kernel Sources
For a common AOSP kernel, like the one for Pixel devices (e.g., android-msm-pixel-4.9), you would clone the relevant branches. Let’s assume we’re looking at a patch between android-msm-pixel-4.9-q-r1 (vulnerable) and android-msm-pixel-4.9-q-r2 (patched).
git clone https://android.googlesource.com/kernel/msm.git msm_kernel_vulnerable
cd msm_kernel_vulnerable
git checkout android-msm-pixel-4.9-q-r1
cd ..
git clone https://android.googlesource.com/kernel/msm.git msm_kernel_patched
cd msm_kernel_patched
git checkout android-msm-pixel-4.9-q-r2
cd ..
Ensure both repositories are fully checked out to their respective stable tags or commits representing the versions you wish to compare. It’s often helpful to build both kernels once to ensure all dependencies are met and the environments are functional, although not strictly necessary for simple patch diffing.
Performing the Diff
Once you have both kernel source trees, the diffing process is straightforward. The diff utility with specific flags is your best friend for a recursive, human-readable comparison.
diff -Naur msm_kernel_vulnerable/ msm_kernel_patched/ > kernel_patch.diff
-N: Treat absent files as empty.-a: Treat all files as text.-u: Output in unified format (context lines).-r: Recursively compare directories.
The kernel_patch.diff file will contain a comprehensive record of every change between the two kernel versions. This file can be thousands or even tens of thousands of lines long. For targeted analysis, it’s often more practical to focus on specific subsystems or files known to be common sources of vulnerabilities, such as drivers, network stack components, or IPC mechanisms.
Analyzing Diffs for Use-After-Free Vulnerabilities
The real art of patch diffing lies in intelligently sifting through the diff output to identify security-relevant changes. When hunting for UAFs, we’re looking for modifications that affect object lifetimes, memory allocations, and deallocations.
Key Indicators of UAF Fixes
Focus your attention on code areas where changes involve:
- Memory Allocation/Deallocation: Look for additions or removals of
kmalloc,kfree,kzalloc,kmem_cache_alloc,kmem_cache_free,rcu_dereference,synchronize_rcu, etc. - Reference Counting: Patches often introduce or fix improper reference counting (e.g.,
kref_get,kref_put) to prevent an object from being freed while still in use. Look for newkref_getbefore a use orkref_putafter a use that wasn’t there before. - Object State Transitions: Changes in state machines where an object might transition to a “freed” or “invalid” state while still reachable or used by another code path.
- NULL Checks: The addition of
if (ptr == NULL)checks before dereferencing a pointer, especially after akfreecall, can indicate a UAF attempt was prevented. - Locking Mechanisms: Changes in mutexes, spinlocks, or semaphores might indicate an attempt to synchronize access to shared resources and prevent race conditions that could lead to UAF.
Example Pattern: RCU-Protected Objects
A common pattern for UAF is improper handling of RCU-protected objects. Consider a diff showing changes around rcu_dereference and synchronize_rcu:
--- a/drivers/char/foo_driver.c
+++ b/drivers/char/foo_driver.c
@@ -100,6 +100,7 @@
struct foo_device *foo_dev_get(int id)
{
struct foo_device *dev;
+ rcu_read_lock();
list_for_each_entry_rcu(dev, &foo_list, list) {
if (dev->id == id)
return dev;
@@ -112,6 +113,7 @@
if (!dev)
return ERR_PTR(-ENODEV);
kref_get(&dev->refcount);
+ rcu_read_unlock();
return dev;
}
@@ -120,6 +122,7 @@
{
if (kref_put(&dev->refcount, foo_dev_release)) {
list_del_rcu(&dev->list);
+ synchronize_rcu(); /* Ensures no more readers */
kfree(dev);
}
}
In this hypothetical diff, the patched version (+++) introduces rcu_read_lock()/rcu_read_unlock() around foo_dev_get and synchronize_rcu() before kfree(dev) in foo_dev_put. This suggests that foo_dev_release might have been freeing dev while an RCU reader could still hold a reference, leading to a UAF. The synchronize_rcu() ensures all existing RCU read-side critical sections have completed before the memory is freed, preventing the UAF.
By analyzing the context of these changes, an attacker can understand how the original bug worked, potentially enabling them to trigger it in the unpatched kernel version.
Reproducing and Exploiting the Vulnerability
Once a potential UAF fix is identified, the next steps involve:
- Understand the Original Bug: Based on the patch, reconstruct the conditions under which the UAF could occur in the vulnerable kernel.
- Develop a Proof-of-Concept (PoC): Write a kernel module or user-space program to trigger the UAF. This often involves specific timing, concurrent operations, or misuse of API calls.
- Heap Spraying and Object Reclaiming: For a UAF, the goal is often to reclaim the freed memory with a controlled object. This requires understanding kernel heap grooming techniques.
- Achieve Primitive: Turn the UAF into a more powerful primitive, such as arbitrary read/write, or control over a function pointer, ultimately leading to root privileges.
This phase often involves deep kernel debugging (e.g., using gdb with QEMU or a physical device) to observe memory states and execution flow.
Conclusion
Patch diffing is a powerful, proactive methodology for discovering kernel vulnerabilities, especially UAFs, in Android. By meticulously analyzing the differences between kernel versions, security researchers can reverse-engineer bug fixes into exploitable flaws. This technique not only enhances understanding of kernel security but also provides a systematic approach for identifying critical vulnerabilities before they are widely known or actively exploited. Mastering this skill is a cornerstone for advanced Android kernel exploit development.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →