Complete rewrite with: - Per-app driver scoping via mount namespace isolation (LSPosed-style) - System-wide driver mode selection - .ko kernel module manager with autoload and dependency tracking - Driver integrity protection (monitor/enforce modes) - Driver registry with auto-discovery and SHA256 hashing - LSPosed-style dark WebUI with 6 tabs: Dashboard, Drivers, Apps, Modules, Protection, Logs - RESTful API handler for WebUI communication - Zygote process monitor for auto-applying scopes to new app launches Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
229 lines
7.1 KiB
Bash
229 lines
7.1 KiB
Bash
#!/system/bin/sh
|
|
# Driver Manager v2 - Kernel Module (.ko) Manager
|
|
# Load, unload, and manage kernel modules
|
|
|
|
MODDIR=${MODDIR:-/data/adb/modules/driver-manager}
|
|
. "$MODDIR/scripts/core.sh"
|
|
log_init "$LOGDIR/ko.log"
|
|
|
|
MODULESDIR="$MODDIR/modules"
|
|
AUTOLOAD="$CONFIGDIR/autoload.conf"
|
|
KERNEL_VER=$(uname -r 2>/dev/null)
|
|
|
|
# --- List available .ko files and their status ---
|
|
list_modules() {
|
|
echo '{"modules":['
|
|
local first=true
|
|
|
|
# List .ko files in our modules directory
|
|
for ko in "$MODULESDIR"/*.ko; do
|
|
[ -f "$ko" ] || continue
|
|
local name=$(basename "$ko" .ko)
|
|
local modname=$(modinfo -F name "$ko" 2>/dev/null || echo "$name")
|
|
local desc=$(modinfo -F description "$ko" 2>/dev/null || echo "")
|
|
local ver=$(modinfo -F version "$ko" 2>/dev/null || echo "")
|
|
local author=$(modinfo -F author "$ko" 2>/dev/null || echo "")
|
|
local depends=$(modinfo -F depends "$ko" 2>/dev/null || echo "")
|
|
local vermagic=$(modinfo -F vermagic "$ko" 2>/dev/null || echo "")
|
|
local sz=$(file_size "$ko")
|
|
|
|
# Check if loaded
|
|
local loaded="false"
|
|
lsmod 2>/dev/null | grep -q "^${modname} " && loaded="true"
|
|
|
|
# Check if in autoload
|
|
local autoload="false"
|
|
grep -qx "$name.ko" "$AUTOLOAD" 2>/dev/null && autoload="true"
|
|
|
|
# Check kernel version compatibility
|
|
local compatible="unknown"
|
|
if [ -n "$vermagic" ]; then
|
|
local mod_kver=$(echo "$vermagic" | awk '{print $1}')
|
|
[ "$mod_kver" = "$KERNEL_VER" ] && compatible="true" || compatible="false"
|
|
fi
|
|
|
|
[ "$first" = true ] && first=false || echo ","
|
|
cat << ENTRY
|
|
{
|
|
"filename": "$(basename "$ko")",
|
|
"name": "$modname",
|
|
"description": "$desc",
|
|
"version": "$ver",
|
|
"author": "$author",
|
|
"depends": "$depends",
|
|
"vermagic": "$vermagic",
|
|
"size": $sz,
|
|
"loaded": $loaded,
|
|
"autoload": $autoload,
|
|
"compatible": $compatible
|
|
}
|
|
ENTRY
|
|
done
|
|
|
|
echo ']}'
|
|
}
|
|
|
|
# --- Load a kernel module ---
|
|
load_module() {
|
|
local ko="$1"
|
|
local params="$2"
|
|
|
|
# Accept either filename or path
|
|
if [ ! -f "$ko" ]; then
|
|
ko="$MODULESDIR/$ko"
|
|
fi
|
|
if [ ! -f "$ko" ]; then
|
|
echo '{"status": "error", "message": "Module file not found"}'
|
|
return 1
|
|
fi
|
|
|
|
local name=$(basename "$ko" .ko)
|
|
local modname=$(modinfo -F name "$ko" 2>/dev/null || echo "$name")
|
|
|
|
# Check if already loaded
|
|
if lsmod 2>/dev/null | grep -q "^${modname} "; then
|
|
echo "{\"status\": \"already_loaded\", \"module\": \"$modname\"}"
|
|
return 0
|
|
fi
|
|
|
|
# Check kernel version
|
|
local vermagic=$(modinfo -F vermagic "$ko" 2>/dev/null)
|
|
if [ -n "$vermagic" ]; then
|
|
local mod_kver=$(echo "$vermagic" | awk '{print $1}')
|
|
if [ "$mod_kver" != "$KERNEL_VER" ]; then
|
|
log_error "Kernel mismatch: module=$mod_kver running=$KERNEL_VER"
|
|
echo "{\"status\": \"error\", \"message\": \"Kernel version mismatch: module built for $mod_kver, running $KERNEL_VER\"}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Load dependencies first
|
|
local depends=$(modinfo -F depends "$ko" 2>/dev/null)
|
|
if [ -n "$depends" ]; then
|
|
local IFS=','
|
|
for dep in $depends; do
|
|
if ! lsmod 2>/dev/null | grep -q "^${dep} "; then
|
|
local dep_ko="$MODULESDIR/${dep}.ko"
|
|
if [ -f "$dep_ko" ]; then
|
|
log "Loading dependency: $dep"
|
|
insmod "$dep_ko" 2>> "$LOGDIR/ko.log"
|
|
else
|
|
log "Dependency $dep not in modules dir, trying modprobe"
|
|
modprobe "$dep" 2>> "$LOGDIR/ko.log"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Load the module
|
|
log "Loading module: $ko $params"
|
|
local output
|
|
output=$(insmod "$ko" $params 2>&1)
|
|
if [ $? -eq 0 ]; then
|
|
log "Loaded: $modname"
|
|
# Capture relevant dmesg
|
|
local dmesg_out=$(dmesg | tail -5 2>/dev/null)
|
|
echo "{\"status\": \"ok\", \"module\": \"$modname\", \"dmesg\": \"$(echo "$dmesg_out" | tr '\n' '|' | sed 's/"/\\"/g')\"}"
|
|
else
|
|
log_error "Failed to load $modname: $output"
|
|
echo "{\"status\": \"error\", \"module\": \"$modname\", \"message\": \"$(echo "$output" | tr '\n' ' ' | sed 's/"/\\"/g')\"}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# --- Unload a kernel module ---
|
|
unload_module() {
|
|
local name="$1"
|
|
name=$(echo "$name" | sed 's/\.ko$//')
|
|
|
|
if ! lsmod 2>/dev/null | grep -q "^${name} "; then
|
|
echo "{\"status\": \"not_loaded\", \"module\": \"$name\"}"
|
|
return 0
|
|
fi
|
|
|
|
log "Unloading module: $name"
|
|
local output
|
|
output=$(rmmod "$name" 2>&1)
|
|
if [ $? -eq 0 ]; then
|
|
log "Unloaded: $name"
|
|
echo "{\"status\": \"ok\", \"module\": \"$name\"}"
|
|
else
|
|
log_error "Failed to unload $name: $output"
|
|
echo "{\"status\": \"error\", \"module\": \"$name\", \"message\": \"$(echo "$output" | tr '\n' ' ' | sed 's/"/\\"/g')\"}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# --- Unload all managed modules ---
|
|
unload_all() {
|
|
log "Unloading all managed modules"
|
|
for ko in "$MODULESDIR"/*.ko; do
|
|
[ -f "$ko" ] || continue
|
|
local name=$(basename "$ko" .ko)
|
|
local modname=$(modinfo -F name "$ko" 2>/dev/null || echo "$name")
|
|
if lsmod 2>/dev/null | grep -q "^${modname} "; then
|
|
rmmod "$modname" 2>/dev/null
|
|
log "Unloaded: $modname"
|
|
fi
|
|
done
|
|
echo '{"status": "ok"}'
|
|
}
|
|
|
|
# --- Get detailed info for a module ---
|
|
info_module() {
|
|
local ko="$1"
|
|
if [ ! -f "$ko" ]; then
|
|
ko="$MODULESDIR/$ko"
|
|
fi
|
|
[ ! -f "$ko" ] && { echo '{"error": "not found"}'; return 1; }
|
|
|
|
modinfo "$ko" 2>/dev/null
|
|
}
|
|
|
|
# --- Toggle autoload for a module ---
|
|
set_autoload() {
|
|
local ko_filename="$1"
|
|
local enabled="$2"
|
|
|
|
if [ "$enabled" = "true" ] || [ "$enabled" = "1" ]; then
|
|
if ! grep -qx "$ko_filename" "$AUTOLOAD" 2>/dev/null; then
|
|
echo "$ko_filename" >> "$AUTOLOAD"
|
|
log "Autoload enabled: $ko_filename"
|
|
fi
|
|
echo "{\"status\": \"ok\", \"autoload\": true, \"module\": \"$ko_filename\"}"
|
|
else
|
|
sed -i "/^${ko_filename}$/d" "$AUTOLOAD" 2>/dev/null
|
|
log "Autoload disabled: $ko_filename"
|
|
echo "{\"status\": \"ok\", \"autoload\": false, \"module\": \"$ko_filename\"}"
|
|
fi
|
|
}
|
|
|
|
# --- Load all autoload modules ---
|
|
autoload_modules() {
|
|
[ ! -f "$AUTOLOAD" ] && return 0
|
|
log "Loading autoload modules"
|
|
|
|
while IFS= read -r ko; do
|
|
[ -z "$ko" ] && continue
|
|
[ "${ko#\#}" != "$ko" ] && continue
|
|
local kofile="$MODULESDIR/$ko"
|
|
if [ -f "$kofile" ]; then
|
|
load_module "$kofile" >/dev/null 2>&1
|
|
else
|
|
log_error "Autoload module not found: $ko"
|
|
fi
|
|
done < "$AUTOLOAD"
|
|
}
|
|
|
|
# --- Main ---
|
|
case "$1" in
|
|
list) list_modules ;;
|
|
load) load_module "$2" "$3" ;;
|
|
unload) unload_module "$2" ;;
|
|
unload_all) unload_all ;;
|
|
info) info_module "$2" ;;
|
|
autoload) autoload_modules ;;
|
|
set_autoload) set_autoload "$2" "$3" ;;
|
|
*) echo "Usage: ko_manager.sh {list|load|unload|unload_all|info|autoload|set_autoload} [args]" ;;
|
|
esac
|