CVE-2018-9416 is a critical vulnerability in Android’s SCSI Generic (sg) driver (scsi/sg.c), discovered in 2018. It allows a local attacker to escalate privileges up to the system level by exploiting a rare memory corruption bug. This article explains the root cause, shows code snippets, and gives an easy-to-understand exploit walkthrough. If you care about Android security or how kernel bugs happen, read on for exclusive insights.
Background
Android, like Linux, uses kernel drivers to talk to hardware. The SCSI Generic driver (sg) helps with interactions between the system and SCSI storage devices like hard drives or USB sticks.
The kernel, as you know, is the core of the operating system. Any bug here can let an attacker control the device.
ID: CVE-2018-9416
- Component: SCSI Generic Driver (scsi/sg.c)
- Type: Use-after-free / memory corruption
Access: Local (needs to run code on device)
Google’s official page:
https://source.android.com/security/bulletin/2018-10-01#kernel-components
The Root Cause Explained
At the heart of the issue is the sg_remove_scat function.
This function is supposed to clean up memory (called "scatter-gather" lists) that were used during data transfers.
But there’s a rare edge case:
If an error happens during cleanup, the function might try to free the same memory twice (“double free”), corrupting memory and letting an attacker hijack execution.
In reality, an attacker can use this to write controlled data where they shouldn’t—ultimately hijacking the kernel.
> No user action is required for this to work.
> Only SYSTEM permissions are needed (like a common app with those rights), making this dangerous.
Original References
- Google Android Security Bulletin - October 2018
- Android Patch (AOSP) — commit
- Mitre CVE page
Let’s look at the critical part of the code (simplified for clarity)
// sg_remove_scat function from scsi/sg.c
static void sg_remove_scat(struct sg_request *srp)
{
int k;
if (!srp->sglist)
return;
for (k = ; k < srp->sg_count; ++k) {
if (srp->sglist[k].page)
__free_page(srp->sglist[k].page);
}
kfree(srp->sglist);
srp->sglist = NULL; // <-- bug: might not always be cleared in all cases!
}
The problem is, if sg_remove_scat is called in just the wrong way (when cleaning up after an error), it may double-free memory, or leave a pointer to freed memory. Attackers can abuse this for code execution in kernel mode.
Here’s a simplified attack flow
1. Allocate a scatter-gather list from user space via the /dev/sg* interface (devices present on many phones).
Trigger an error to make the sg_remove_scat function run cleanup code for your request.
3. Race timing or replay operations so that memory already freed is freed again, or used after being freed.
Plant controlled data in this memory via another syscall, overwriting kernel data structures.
5. Hijack execution: The overwritten data’s function pointers or control fields can lead to privilege escalation.
Proof-of-Concept (PoC) Sketch
*Here's a *conceptual* PoC that shows how memory could be corrupted (for educational purposes—the real exploit is much more detailed and hardware-dependent):*
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/sg.h>
#define DEVICE "/dev/sg1" // or any valid SCSI device
int main() {
int fd = open(DEVICE, O_RDWR);
struct sg_io_hdr io_hdr;
unsigned char cdb[6] = {}; // dummy command
unsigned char data[4096];
if (fd < ) { perror("open"); return 1; }
// Set up a flawed request (e.g. too-large size, invalid params)
memset(&io_hdr, , sizeof(io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmdp = cdb;
io_hdr.cmd_len = sizeof(cdb);
io_hdr.dxferp = data;
io_hdr.dxfer_len = 4096;
io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
io_hdr.timeout = 200;
// Send request to trigger error and force driver cleanup
int r = ioctl(fd, SG_IO, &io_hdr);
if (r < ) perror("ioctl");
close(fd);
return ;
}
*This alone won’t escalate privileges—it just triggers the cleanup logic. But real exploits use this primitive to corrupt memory and gain SYSTEM execution.*
Why it matters: This is a kernel-level bug, so you get full control of the device.
- Who can exploit it: Any app with SYSTEM privileges (like some OEM or preinstalled apps, or attackers who manage to get that far via app bugs).
How to Stay Safe
- Apply patches: Android fixed this in all supported versions after October 2018. Upgrade now if you haven't yet.
Restrict SYSTEM privilege: Only trusted apps should ever have SYSTEM rights.
- Disable or restrict access to /dev/sg* devices if possible.
Bottom Line
CVE-2018-9416 is a scary, real-world example of how a tiny code bug (moving a pointer at the wrong time) can open up Android devices to local privilege escalation. Understanding these root causes helps us all build and audit safer systems.
References
- Google: Android Security Bulletin—October 2018
- Mitre CVE-2018-9416
- AOSP Patch Commit
*Written for the community by a cybersecurity enthusiast—please share and stay safe!*
Timeline
Published on: 12/05/2024 00:15:18 UTC
Last modified on: 12/18/2024 20:49:22 UTC