How an unchecked ring-buffer boundary read in Qualcomm's kgsl GPU driver allowed targeted mobile spyware to corrupt Android kernel memory.
Imagine a scoreboard operator at a stadium who reads game scores from a paper tape. An attacker sends a tape that says 'Jump 500 lines forward and read the score'. The operator blindly jumps off the edge of the paper into the stadium's electrical wiring diagram, reading and overwriting the master power switches.
An untrusted app opens /dev/kgsl-3d0.
The app submits a IOCTL_KGSL_GPU_COMMAND payload with a forged command packet offset.
The driver adds the offset to the ring-buffer base without validating the maximum command length.
The GPU executes the command, writing memory across adjacent kernel heap structures.
Entregado en código fuente legible de alto nivel (sin ensamblador ni diffs binarios).
// VULNERABLE: drivers/gpu/msm/kgsl.c before patch
int kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv, void *data) {
struct kgsl_gpu_command *cmd = data;
// ROOT CAUSE:
// Adds user-controlled offset to ringbuffer without boundary bounds verification!
void *cmd_ptr = dev_priv->ringbuffer.base + cmd->offset;
// Writes user command directly into arbitrary memory!
memcpy(cmd_ptr, cmd->commands, cmd->size);
return 0;
}
// SECURE: drivers/gpu/msm/kgsl.c patch
int kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv, void *data) {
struct kgsl_gpu_command *cmd = data;
// 1. Validate that offset and size do not overflow ringbuffer boundaries
size_t end_offset;
if (check_add_overflow(cmd->offset, cmd->size, &end_offset)) {
return -EINVAL;
}
if (end_offset > dev_priv->ringbuffer.max_size) {
return -EINVAL; // Strictly reject out-of-bounds pointer!
}
void *cmd_ptr = dev_priv->ringbuffer.base + cmd->offset;
memcpy(cmd_ptr, cmd->commands, cmd->size);
return 0;
}