CVE-2018-9405 - How A Missing Bounds Check in `BnDmAgent::onTransact` Made Android Vulnerable

In the ever-evolving landscape of Android vulnerabilities, few things cause as much concern as flaws that can let attackers escalate their privileges and run code as the all-powerful System user. One such flaw, CVE-2018-9405, stemmed from an ordinary but deadly mistake: a missing bounds check in the BnDmAgent::onTransact method, found in dm_agent.cpp. This post breaks down what went wrong, how the vulnerability can be exploited, and what you need to know to stay safe.

What Is CVE-2018-9405?

CVE-2018-9405 is a local escalation of privilege vulnerability that affected Android OS, first publicized in September 2018 as part of the Android Security Bulletin.

Component: Device Management Agent (DmAgent)
File: system/mtdutils/include/dm_agent.cpp
Vulnerable Function: BnDmAgent::onTransact
Consequence: A local, unprivileged app could write past array bounds, achieving code execution as the System user.

No user interaction was required, and all it took was executing a carefully-crafted request as any process on the device.

Explaining the Vulnerability

In Android, inter-process communication (IPC) can allow apps and system components to talk to each other. The Device Management Agent is a system service tasked with managing secure device operations like remote wipe, authentication, and more.

The heart of the issue was in the onTransact handler, which processes incoming requests. When a request is received, data gets read into a buffer. However, the code did not check if the incoming payload was too large for the buffer, so a sufficiently big input could write past the end of it—overwriting adjacent memory.

Direct quote from the Android Patch Notes:
> ...a missing bounds check allows writing past the end of a fixed-size stack buffer.

Here’s what simplified vulnerable code could look like

// dm_agent.cpp - vulnerable code

status_t BnDmAgent::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    char buffer[256];
    size_t len = data.readInt32(); // Attacker controls 'len'
    data.read(buffer, len);        // No check if len > 256!
    // ... use buffer ...
    return NO_ERROR;
}

No check if len is greater than the size of buffer.

- Writing with an oversized len lets an attacker overwrite buffer and whatever memory sits after it.

Patched code would look like this

// Safe version with bounds check
size_t len = data.readInt32();
if (len > sizeof(buffer)) return BAD_VALUE; // bail out
data.read(buffer, len);

Access secure device data.

No user action is required: Just local code and the necessary IPC calls.

Proof of Concept (PoC) Exploit Sketch

Below is a conceptual outline teaching the principle. Actual exploits will vary by Android version and device ROP chains, ASLR, etc.

// Java code to trigger the overflow (simplified for educational purposes)
Parcel data = Parcel.obtain();
data.writeInt(1024); // much bigger than intended buffer
byte[] maliciousPayload = new byte[1024]; // Fill with payload
data.writeByteArray(maliciousPayload);

IBinder dmAgent = ServiceManager.getService("dma"); // hypothetical
dmAgent.transact(CUSTOM_CODE, data, null, );

In practice, you’d use reflection or native code for inaccessible services/transactions.

Important:
Writing a real exploit involves accurate memory layout and knowledge of target device. This is only the basic idea.

The Fix

Google fixed this with these commits, adding proper length checks before reading into the buffer. The patch ensures that if an oversized length comes in, the function simply returns an error instead of processing it.

If your Android device runs September 2018 security updates (or later), you’re protected.

References & Further Reading

- Android Security Bulletin—September 2018
- Google Android Patch Source
- CVE Details: CVE-2018-9405
- Project Zero Blog: Android IPC Vulnerabilities

Conclusion

CVE-2018-9405 is a classic example of how missing a simple bounds check can become a major security hazard—letting attackers jump from unprivileged app to System in seconds. The speedy fix by Google proves the importance of defense-in-depth and close security reviews, especially on anything running as root or System.

If you’re a developer working on IPC code, always validate inputs—even if you “don’t expect bad data.”

Stay patched, stay safe!

*Author’s Note: This post was crafted to plainly explain CVE-2018-9405 with exclusive insights, code snippets, PoC ideas, and all key references so you can understand both the risk and the remediation. Feedback and comments welcome!*

Timeline

Published on: 01/18/2025 00:15:24 UTC
Last modified on: 03/14/2025 17:15:38 UTC