Driver Manager v2.0.0 - LSPosed-style rewrite
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>
This commit is contained in:
101
customize.sh
Normal file
101
customize.sh
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Installation Script
|
||||
# Runs during KernelSU module installation
|
||||
|
||||
MODDIR=${MODPATH:-/data/adb/modules/driver-manager}
|
||||
CONFIGDIR="$MODDIR/config"
|
||||
MODULESDIR="$MODDIR/modules"
|
||||
DRIVERSDIR="$MODDIR/drivers"
|
||||
BACKUPDIR="$MODDIR/backup"
|
||||
LOGFILE="$MODDIR/install.log"
|
||||
|
||||
log() { echo "[driver-manager] $1" >> "$LOGFILE" 2>/dev/null; ui_print "$1"; }
|
||||
|
||||
ui_print "================================================"
|
||||
ui_print " Driver Manager v2.0.0"
|
||||
ui_print " LSPosed-style driver management"
|
||||
ui_print "================================================"
|
||||
|
||||
# --- Detect Hardware ---
|
||||
DEVICE=$(getprop ro.product.device 2>/dev/null || echo "unknown")
|
||||
MODEL=$(getprop ro.product.model 2>/dev/null || echo "unknown")
|
||||
SOC=$(getprop ro.hardware.chipname 2>/dev/null || getprop ro.board.platform 2>/dev/null || echo "unknown")
|
||||
ARCH=$(getprop ro.product.cpu.abi 2>/dev/null || echo "arm64-v8a")
|
||||
API=$(getprop ro.build.version.sdk 2>/dev/null || echo "35")
|
||||
KERNEL=$(uname -r 2>/dev/null || echo "unknown")
|
||||
|
||||
ui_print " Device: $MODEL ($DEVICE)"
|
||||
ui_print " SoC: $SOC"
|
||||
ui_print " Arch: $ARCH"
|
||||
ui_print " API: $API"
|
||||
ui_print " Kernel: $KERNEL"
|
||||
ui_print "------------------------------------------------"
|
||||
|
||||
# --- Create directories ---
|
||||
mkdir -p "$CONFIGDIR"
|
||||
mkdir -p "$MODULESDIR"
|
||||
mkdir -p "$DRIVERSDIR"
|
||||
mkdir -p "$BACKUPDIR"
|
||||
mkdir -p "$MODDIR/run"
|
||||
mkdir -p "$MODDIR/logs"
|
||||
|
||||
# --- Device profile ---
|
||||
cat > "$CONFIGDIR/device.json" << DEVEOF
|
||||
{
|
||||
"device": "$DEVICE",
|
||||
"model": "$MODEL",
|
||||
"soc": "$SOC",
|
||||
"arch": "$ARCH",
|
||||
"api": $API,
|
||||
"kernel": "$KERNEL",
|
||||
"install_time": "$(date -Iseconds 2>/dev/null || date)"
|
||||
}
|
||||
DEVEOF
|
||||
|
||||
# --- Default configuration ---
|
||||
cat > "$CONFIGDIR/settings.json" << SETEOF
|
||||
{
|
||||
"protection_mode": "monitor",
|
||||
"protection_interval": 300,
|
||||
"scope_mode": "app",
|
||||
"log_level": "info",
|
||||
"auto_apply_scopes": true,
|
||||
"monitor_zygote": true
|
||||
}
|
||||
SETEOF
|
||||
|
||||
# --- Initialize empty scopes ---
|
||||
[ ! -f "$CONFIGDIR/scopes.json" ] && echo '{"scopes":[]}' > "$CONFIGDIR/scopes.json"
|
||||
|
||||
# --- Initialize empty autoload ---
|
||||
[ ! -f "$CONFIGDIR/autoload.conf" ] && touch "$CONFIGDIR/autoload.conf"
|
||||
|
||||
# --- Scan and register system drivers ---
|
||||
ui_print " Scanning system drivers..."
|
||||
if [ -f "$MODDIR/scripts/driver_registry.sh" ]; then
|
||||
sh "$MODDIR/scripts/driver_registry.sh" scan 2>> "$LOGFILE"
|
||||
DRIVER_COUNT=$(sh "$MODDIR/scripts/driver_registry.sh" count 2>/dev/null || echo "0")
|
||||
ui_print " Found $DRIVER_COUNT driver categories"
|
||||
else
|
||||
ui_print " [WARN] driver_registry.sh not found, will scan on first boot"
|
||||
fi
|
||||
|
||||
# --- Create protection baseline ---
|
||||
ui_print " Creating driver protection baseline..."
|
||||
if [ -f "$MODDIR/scripts/protect.sh" ]; then
|
||||
sh "$MODDIR/scripts/protect.sh" baseline 2>> "$LOGFILE"
|
||||
ui_print " Protection baseline created"
|
||||
else
|
||||
ui_print " [WARN] protect.sh not found, will baseline on first boot"
|
||||
fi
|
||||
|
||||
# --- Set permissions ---
|
||||
set_perm_recursive $MODDIR/scripts 0 0 0755 0755
|
||||
set_perm $MODDIR/service.sh 0 0 0755
|
||||
set_perm $MODDIR/post-fs-data.sh 0 0 0755
|
||||
set_perm $MODDIR/uninstall.sh 0 0 0755
|
||||
|
||||
ui_print "------------------------------------------------"
|
||||
ui_print " Installation complete!"
|
||||
ui_print " Open KernelSU WebUI to manage drivers"
|
||||
ui_print "================================================"
|
||||
6
module.prop
Normal file
6
module.prop
Normal file
@@ -0,0 +1,6 @@
|
||||
id=driver-manager
|
||||
name=Driver Manager
|
||||
version=v2.0.0
|
||||
versionCode=200
|
||||
author=sssnake
|
||||
description=LSPosed-style driver manager with per-app scoping, .ko module management, and driver protection for Pixel devices
|
||||
25
post-fs-data.sh
Normal file
25
post-fs-data.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Early Boot Script
|
||||
# Runs before most system services start
|
||||
# Keep minimal to avoid boot delays
|
||||
|
||||
MODDIR=${0%/*}
|
||||
LOGFILE="$MODDIR/logs/boot.log"
|
||||
|
||||
echo "[$(date)] post-fs-data: starting" > "$LOGFILE"
|
||||
|
||||
# Load any kernel modules marked for early loading
|
||||
if [ -f "$MODDIR/config/autoload.conf" ]; then
|
||||
while IFS= read -r mod; do
|
||||
[ -z "$mod" ] && continue
|
||||
[ "${mod#\#}" != "$mod" ] && continue
|
||||
MODFILE="$MODDIR/modules/$mod"
|
||||
if [ -f "$MODFILE" ]; then
|
||||
insmod "$MODFILE" 2>> "$LOGFILE" && \
|
||||
echo "[$(date)] Loaded early module: $mod" >> "$LOGFILE" || \
|
||||
echo "[$(date)] FAILED to load early module: $mod" >> "$LOGFILE"
|
||||
fi
|
||||
done < "$MODDIR/config/autoload.conf"
|
||||
fi
|
||||
|
||||
echo "[$(date)] post-fs-data: complete" >> "$LOGFILE"
|
||||
148
scripts/api.sh
Normal file
148
scripts/api.sh
Normal file
@@ -0,0 +1,148 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - WebUI API Handler
|
||||
# Processes commands from KernelSU WebUI via ksu.exec()
|
||||
|
||||
MODDIR=${MODDIR:-/data/adb/modules/driver-manager}
|
||||
. "$MODDIR/scripts/core.sh"
|
||||
|
||||
CONFIGDIR="$MODDIR/config"
|
||||
|
||||
# Route: system
|
||||
api_system() {
|
||||
case "$1" in
|
||||
info)
|
||||
local device=$(cat "$CONFIGDIR/device.json" 2>/dev/null || echo '{}')
|
||||
local kernel=$(uname -r 2>/dev/null)
|
||||
local uptime=$(cat /proc/uptime 2>/dev/null | awk '{print $1}')
|
||||
echo "{\"device\": $device, \"kernel\": \"$kernel\", \"uptime\": \"$uptime\"}"
|
||||
;;
|
||||
logs)
|
||||
local logfile="${2:-service}"
|
||||
local lines="${3:-100}"
|
||||
local f="$LOGDIR/${logfile}.log"
|
||||
if [ -f "$f" ]; then
|
||||
local content=$(tail -n "$lines" "$f" | sed 's/"/\\"/g' | tr '\n' '|')
|
||||
echo "{\"log\": \"$content\", \"file\": \"$logfile\"}"
|
||||
else
|
||||
echo '{"log": "", "file": "'"$logfile"'"}'
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo '{"error": "Unknown system command"}'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Route: drivers
|
||||
api_drivers() {
|
||||
case "$1" in
|
||||
list) sh "$MODDIR/scripts/driver_registry.sh" list ;;
|
||||
scan) sh "$MODDIR/scripts/driver_registry.sh" scan ;;
|
||||
get) sh "$MODDIR/scripts/driver_registry.sh" get "$2" ;;
|
||||
count) echo "{\"count\": $(sh "$MODDIR/scripts/driver_registry.sh" count)}" ;;
|
||||
verify) sh "$MODDIR/scripts/driver_registry.sh" verify "$2" ;;
|
||||
add_variant) sh "$MODDIR/scripts/driver_registry.sh" add_variant "$2" "$3" "$4" ;;
|
||||
*) echo '{"error": "Unknown drivers command"}' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Route: scope
|
||||
api_scope() {
|
||||
case "$1" in
|
||||
list) sh "$MODDIR/scripts/scope_manager.sh" list ;;
|
||||
set) sh "$MODDIR/scripts/scope_manager.sh" set "$2" "$3" "$4" "$5" "$6" ;;
|
||||
remove) sh "$MODDIR/scripts/scope_manager.sh" remove "$2" ;;
|
||||
apply) sh "$MODDIR/scripts/scope_manager.sh" apply ;;
|
||||
unmount) sh "$MODDIR/scripts/scope_manager.sh" unmount_all ;;
|
||||
*) echo '{"error": "Unknown scope command"}' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Route: ko (kernel modules)
|
||||
api_ko() {
|
||||
case "$1" in
|
||||
list) sh "$MODDIR/scripts/ko_manager.sh" list ;;
|
||||
load) sh "$MODDIR/scripts/ko_manager.sh" load "$2" "$3" ;;
|
||||
unload) sh "$MODDIR/scripts/ko_manager.sh" unload "$2" ;;
|
||||
unload_all) sh "$MODDIR/scripts/ko_manager.sh" unload_all ;;
|
||||
info) sh "$MODDIR/scripts/ko_manager.sh" info "$2" ;;
|
||||
autoload) sh "$MODDIR/scripts/ko_manager.sh" set_autoload "$2" "$3" ;;
|
||||
*) echo '{"error": "Unknown ko command"}' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Route: protect
|
||||
api_protect() {
|
||||
case "$1" in
|
||||
status) sh "$MODDIR/scripts/protect.sh" status ;;
|
||||
check) sh "$MODDIR/scripts/protect.sh" check ;;
|
||||
baseline) sh "$MODDIR/scripts/protect.sh" baseline ;;
|
||||
mode) sh "$MODDIR/scripts/protect.sh" mode "$2" ;;
|
||||
driver) sh "$MODDIR/scripts/protect.sh" protect "$2" "$3" ;;
|
||||
changelog) sh "$MODDIR/scripts/protect.sh" changelog "$2" ;;
|
||||
*) echo '{"error": "Unknown protect command"}' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Route: apps
|
||||
api_apps() {
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"apps":['
|
||||
local first=true
|
||||
# List installed packages with labels
|
||||
pm list packages -f 2>/dev/null | while IFS= read -r line; do
|
||||
local apk=$(echo "$line" | sed 's/package:\(.*\)=\(.*\)/\1/')
|
||||
local pkg=$(echo "$line" | sed 's/package:\(.*\)=\(.*\)/\2/')
|
||||
[ -z "$pkg" ] && continue
|
||||
|
||||
# Get app label via dumpsys (fast path)
|
||||
local label=$(dumpsys package "$pkg" 2>/dev/null | grep -m1 'applicationInfo' -A5 | grep -o 'label=[^ ]*' | cut -d= -f2)
|
||||
[ -z "$label" ] && label="$pkg"
|
||||
|
||||
# Check if system app
|
||||
local system="false"
|
||||
echo "$apk" | grep -q '/system/' && system="true"
|
||||
|
||||
[ "$first" = true ] && first=false || echo ","
|
||||
echo " {\"package\": \"$pkg\", \"label\": \"$label\", \"system\": $system}"
|
||||
done
|
||||
echo ']}'
|
||||
;;
|
||||
*)
|
||||
echo '{"error": "Unknown apps command"}'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Route: settings
|
||||
api_settings() {
|
||||
case "$1" in
|
||||
get)
|
||||
cat "$CONFIGDIR/settings.json" 2>/dev/null || echo '{}'
|
||||
;;
|
||||
set)
|
||||
local key="$2" value="$3"
|
||||
json_set "$CONFIGDIR/settings.json" "$key" "$value"
|
||||
echo "{\"status\": \"ok\", \"$key\": \"$value\"}"
|
||||
;;
|
||||
*)
|
||||
echo '{"error": "Unknown settings command"}'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Main router ---
|
||||
ROUTE="$1"
|
||||
shift
|
||||
|
||||
case "$ROUTE" in
|
||||
system) api_system "$@" ;;
|
||||
drivers) api_drivers "$@" ;;
|
||||
scope) api_scope "$@" ;;
|
||||
ko) api_ko "$@" ;;
|
||||
protect) api_protect "$@" ;;
|
||||
apps) api_apps "$@" ;;
|
||||
settings) api_settings "$@" ;;
|
||||
*) echo '{"error": "Unknown route. Routes: system, drivers, scope, ko, protect, apps, settings"}' ;;
|
||||
esac
|
||||
85
scripts/core.sh
Normal file
85
scripts/core.sh
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Core Utilities
|
||||
# Shared functions for all scripts
|
||||
|
||||
MODDIR=${MODDIR:-/data/adb/modules/driver-manager}
|
||||
CONFIGDIR="$MODDIR/config"
|
||||
LOGDIR="$MODDIR/logs"
|
||||
RUNDIR="$MODDIR/run"
|
||||
|
||||
# --- Logging ---
|
||||
_LOGFILE=""
|
||||
|
||||
log_init() {
|
||||
_LOGFILE="$1"
|
||||
mkdir -p "$(dirname "$_LOGFILE")" 2>/dev/null
|
||||
}
|
||||
|
||||
log() {
|
||||
local msg="[$(date '+%H:%M:%S')] $1"
|
||||
[ -n "$_LOGFILE" ] && echo "$msg" >> "$_LOGFILE"
|
||||
}
|
||||
|
||||
log_error() { log "ERROR: $1"; }
|
||||
|
||||
# --- JSON helpers (minimal, no jq dependency) ---
|
||||
# Read a string value from a JSON file
|
||||
json_get() {
|
||||
local file="$1" key="$2"
|
||||
grep -o "\"$key\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$file" 2>/dev/null | \
|
||||
head -1 | sed 's/.*:[[:space:]]*"\([^"]*\)"/\1/'
|
||||
}
|
||||
|
||||
# Read a number/bool value from a JSON file
|
||||
json_get_raw() {
|
||||
local file="$1" key="$2"
|
||||
grep -o "\"$key\"[[:space:]]*:[[:space:]]*[^,}]*" "$file" 2>/dev/null | \
|
||||
head -1 | sed 's/.*:[[:space:]]*//' | tr -d ' '
|
||||
}
|
||||
|
||||
# Set a string value in a JSON file
|
||||
json_set() {
|
||||
local file="$1" key="$2" value="$3"
|
||||
if grep -q "\"$key\"" "$file" 2>/dev/null; then
|
||||
sed -i "s|\"$key\"[[:space:]]*:[[:space:]]*\"[^\"]*\"|\"$key\": \"$value\"|" "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- File helpers ---
|
||||
sha256() {
|
||||
sha256sum "$1" 2>/dev/null | cut -d' ' -f1
|
||||
}
|
||||
|
||||
get_selinux_context() {
|
||||
ls -Z "$1" 2>/dev/null | awk '{print $1}'
|
||||
}
|
||||
|
||||
file_size() {
|
||||
stat -c%s "$1" 2>/dev/null || wc -c < "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
# --- Process helpers ---
|
||||
pid_of() {
|
||||
pidof "$1" 2>/dev/null || pgrep -f "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
is_running() {
|
||||
[ -f "$RUNDIR/$1.pid" ] && kill -0 $(cat "$RUNDIR/$1.pid") 2>/dev/null
|
||||
}
|
||||
|
||||
kill_by_pidfile() {
|
||||
local pidfile="$RUNDIR/$1.pid"
|
||||
if [ -f "$pidfile" ]; then
|
||||
kill $(cat "$pidfile") 2>/dev/null
|
||||
rm -f "$pidfile"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Settings helpers ---
|
||||
get_setting() {
|
||||
json_get "$CONFIGDIR/settings.json" "$1"
|
||||
}
|
||||
|
||||
get_setting_raw() {
|
||||
json_get_raw "$CONFIGDIR/settings.json" "$1"
|
||||
}
|
||||
309
scripts/driver_registry.sh
Normal file
309
scripts/driver_registry.sh
Normal file
@@ -0,0 +1,309 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Driver Registry
|
||||
# Discovers, catalogs, and manages system drivers
|
||||
|
||||
MODDIR=${MODDIR:-/data/adb/modules/driver-manager}
|
||||
. "$MODDIR/scripts/core.sh"
|
||||
log_init "$LOGDIR/registry.log"
|
||||
|
||||
REGISTRY="$CONFIGDIR/drivers.json"
|
||||
|
||||
# --- Driver discovery paths by category ---
|
||||
scan_drivers() {
|
||||
log "Starting driver scan"
|
||||
local tmp="$CONFIGDIR/.drivers_tmp.json"
|
||||
|
||||
cat > "$tmp" << 'HEADER'
|
||||
{"drivers":[
|
||||
HEADER
|
||||
|
||||
local first=true
|
||||
|
||||
# GPU drivers
|
||||
for path in /vendor/lib64/egl /vendor/lib/egl /system/lib64/egl; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/lib*.so; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f" .so)
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "gpu-$name",
|
||||
"name": "$name",
|
||||
"category": "gpu",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": true,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# Vulkan ICD
|
||||
for path in /vendor/lib64/hw /vendor/lib/hw; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/vulkan.*.so; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f" .so)
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "vulkan-$name",
|
||||
"name": "$name",
|
||||
"category": "gpu",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": true,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# WiFi firmware
|
||||
for path in /vendor/firmware /vendor/etc/wifi /lib/firmware; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/fw_bcm*.bin "$path"/fw_wcn*.bin "$path"/wlan_*.bin; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f")
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "wifi-$name",
|
||||
"name": "$name",
|
||||
"category": "wifi",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": true,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# Bluetooth firmware
|
||||
for path in /vendor/firmware /vendor/etc/bluetooth /lib/firmware; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/*.hcd "$path"/bt_fw*.bin "$path"/BCM*.hcd; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f")
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "bt-$name",
|
||||
"name": "$name",
|
||||
"category": "bluetooth",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": true,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# Audio HAL
|
||||
for path in /vendor/lib64/hw /vendor/lib/hw; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/audio*.so; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f" .so)
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "audio-$name",
|
||||
"name": "$name",
|
||||
"category": "audio",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": true,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# Camera HAL
|
||||
for path in /vendor/lib64/hw /vendor/lib/hw; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/camera*.so; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f" .so)
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "camera-$name",
|
||||
"name": "$name",
|
||||
"category": "camera",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": false,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# Sensor HAL
|
||||
for path in /vendor/lib64/hw /vendor/lib/hw; do
|
||||
[ -d "$path" ] || continue
|
||||
for f in "$path"/sensors*.so; do
|
||||
[ -f "$f" ] || continue
|
||||
local name=$(basename "$f" .so)
|
||||
local hash=$(sha256 "$f")
|
||||
local ctx=$(get_selinux_context "$f")
|
||||
local sz=$(file_size "$f")
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "sensor-$name",
|
||||
"name": "$name",
|
||||
"category": "sensor",
|
||||
"path": "$f",
|
||||
"hash": "$hash",
|
||||
"selinux": "$ctx",
|
||||
"size": $sz,
|
||||
"protected": false,
|
||||
"variants": [{"name": "stock", "path": "$f", "hash": "$hash", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done
|
||||
done
|
||||
|
||||
# Kernel modules currently loaded
|
||||
if [ -f /proc/modules ]; then
|
||||
while read -r name rest; do
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"id": "kmod-$name",
|
||||
"name": "$name",
|
||||
"category": "kernel",
|
||||
"path": "/proc/modules",
|
||||
"hash": "",
|
||||
"selinux": "",
|
||||
"size": 0,
|
||||
"protected": false,
|
||||
"variants": [{"name": "loaded", "path": "", "hash": "", "active": true}]
|
||||
}
|
||||
ENTRY
|
||||
done < /proc/modules
|
||||
fi
|
||||
|
||||
echo "" >> "$tmp"
|
||||
echo "]}" >> "$tmp"
|
||||
|
||||
mv "$tmp" "$REGISTRY"
|
||||
log "Driver scan complete"
|
||||
}
|
||||
|
||||
# --- Count drivers ---
|
||||
count_drivers() {
|
||||
if [ -f "$REGISTRY" ]; then
|
||||
grep -c '"id"' "$REGISTRY" 2>/dev/null || echo "0"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- List drivers as JSON ---
|
||||
list_drivers() {
|
||||
[ -f "$REGISTRY" ] && cat "$REGISTRY" || echo '{"drivers":[]}'
|
||||
}
|
||||
|
||||
# --- Get single driver info ---
|
||||
get_driver() {
|
||||
local id="$1"
|
||||
if [ -f "$REGISTRY" ]; then
|
||||
# Extract the driver block matching the id
|
||||
awk -v id="$id" '
|
||||
/"id".*:.*"/ { found = ($0 ~ "\"" id "\"") }
|
||||
found && /\{/ { depth++ }
|
||||
found && depth > 0 { print }
|
||||
found && /\}/ { depth--; if (depth == 0) { found=0 } }
|
||||
' "$REGISTRY"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Add a custom variant to a driver ---
|
||||
add_variant() {
|
||||
local driver_id="$1"
|
||||
local variant_name="$2"
|
||||
local variant_path="$3"
|
||||
|
||||
if [ ! -f "$variant_path" ]; then
|
||||
echo '{"error": "Variant file not found"}'
|
||||
return 1
|
||||
fi
|
||||
|
||||
local hash=$(sha256 "$variant_path")
|
||||
log "Adding variant '$variant_name' to driver '$driver_id': $variant_path (hash: $hash)"
|
||||
|
||||
# Copy variant to drivers directory
|
||||
local dest="$MODDIR/drivers/${driver_id}_${variant_name}_$(basename "$variant_path")"
|
||||
cp "$variant_path" "$dest"
|
||||
chmod 644 "$dest"
|
||||
|
||||
echo "{\"status\": \"ok\", \"driver\": \"$driver_id\", \"variant\": \"$variant_name\", \"path\": \"$dest\", \"hash\": \"$hash\"}"
|
||||
}
|
||||
|
||||
# --- Verify a driver's current hash matches registry ---
|
||||
verify_driver() {
|
||||
local id="$1"
|
||||
local reg_path=$(grep -A5 "\"$id\"" "$REGISTRY" 2>/dev/null | grep '"path"' | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
local reg_hash=$(grep -A5 "\"$id\"" "$REGISTRY" 2>/dev/null | grep '"hash"' | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
|
||||
if [ -z "$reg_path" ] || [ -z "$reg_hash" ]; then
|
||||
echo '{"status": "unknown", "reason": "driver not in registry"}'
|
||||
return 1
|
||||
fi
|
||||
|
||||
local cur_hash=$(sha256 "$reg_path")
|
||||
if [ "$cur_hash" = "$reg_hash" ]; then
|
||||
echo "{\"status\": \"ok\", \"driver\": \"$id\", \"hash\": \"$cur_hash\"}"
|
||||
else
|
||||
echo "{\"status\": \"changed\", \"driver\": \"$id\", \"expected\": \"$reg_hash\", \"actual\": \"$cur_hash\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
case "$1" in
|
||||
scan) scan_drivers ;;
|
||||
count) count_drivers ;;
|
||||
list) list_drivers ;;
|
||||
get) get_driver "$2" ;;
|
||||
add_variant) add_variant "$2" "$3" "$4" ;;
|
||||
verify) verify_driver "$2" ;;
|
||||
*) echo "Usage: driver_registry.sh {scan|count|list|get|add_variant|verify} [args]" ;;
|
||||
esac
|
||||
228
scripts/ko_manager.sh
Normal file
228
scripts/ko_manager.sh
Normal file
@@ -0,0 +1,228 @@
|
||||
#!/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
|
||||
233
scripts/protect.sh
Normal file
233
scripts/protect.sh
Normal file
@@ -0,0 +1,233 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Driver Integrity Protection
|
||||
# Monitor system drivers for unauthorized changes
|
||||
|
||||
MODDIR=${MODDIR:-/data/adb/modules/driver-manager}
|
||||
. "$MODDIR/scripts/core.sh"
|
||||
log_init "$LOGDIR/protect.log"
|
||||
|
||||
BASELINE="$CONFIGDIR/baseline.json"
|
||||
REGISTRY="$CONFIGDIR/drivers.json"
|
||||
BACKUPDIR="$MODDIR/backup"
|
||||
CHANGELOG="$LOGDIR/changes.log"
|
||||
|
||||
# --- Create SHA256 baseline of all protected drivers ---
|
||||
create_baseline() {
|
||||
log "Creating protection baseline"
|
||||
[ ! -f "$REGISTRY" ] && { echo '{"error": "No driver registry. Run scan first."}'; return 1; }
|
||||
|
||||
local tmp="$CONFIGDIR/.baseline_tmp.json"
|
||||
echo '{"baseline":[' > "$tmp"
|
||||
local first=true
|
||||
|
||||
# Extract protected driver paths from registry
|
||||
local in_driver=false protected=false path="" hash=""
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*'"path"'*)
|
||||
path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"protected"'*true*)
|
||||
protected=true
|
||||
;;
|
||||
*'"protected"'*false*)
|
||||
protected=false
|
||||
;;
|
||||
*\}*)
|
||||
if [ "$protected" = true ] && [ -n "$path" ] && [ -f "$path" ]; then
|
||||
local cur_hash=$(sha256 "$path")
|
||||
local sz=$(file_size "$path")
|
||||
local ctx=$(get_selinux_context "$path")
|
||||
|
||||
[ "$first" = true ] && first=false || echo "," >> "$tmp"
|
||||
cat >> "$tmp" << ENTRY
|
||||
{
|
||||
"path": "$path",
|
||||
"hash": "$cur_hash",
|
||||
"size": $sz,
|
||||
"selinux": "$ctx",
|
||||
"time": "$(date -Iseconds 2>/dev/null || date)"
|
||||
}
|
||||
ENTRY
|
||||
|
||||
# Backup the file
|
||||
local bkdir="$BACKUPDIR/$(dirname "$path" | sed 's|^/||')"
|
||||
mkdir -p "$bkdir"
|
||||
cp -p "$path" "$bkdir/" 2>/dev/null
|
||||
fi
|
||||
path="" protected=false
|
||||
;;
|
||||
esac
|
||||
done < "$REGISTRY"
|
||||
|
||||
echo "" >> "$tmp"
|
||||
echo '], "created": "'"$(date -Iseconds 2>/dev/null || date)"'"}' >> "$tmp"
|
||||
mv "$tmp" "$BASELINE"
|
||||
|
||||
local count=$(grep -c '"path"' "$BASELINE" 2>/dev/null || echo 0)
|
||||
log "Baseline created: $count drivers protected"
|
||||
echo "{\"status\": \"ok\", \"protected_count\": $count}"
|
||||
}
|
||||
|
||||
# --- Check all protected drivers against baseline ---
|
||||
check_integrity() {
|
||||
[ ! -f "$BASELINE" ] && { echo '{"error": "No baseline. Run baseline first."}'; return 1; }
|
||||
|
||||
log "Running integrity check"
|
||||
local changes=0 checked=0 ok=0
|
||||
local results='{"results":['
|
||||
local first=true
|
||||
|
||||
local path="" expected_hash=""
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*'"path"'*)
|
||||
path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"hash"'*)
|
||||
expected_hash=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*\}*)
|
||||
if [ -n "$path" ] && [ -n "$expected_hash" ]; then
|
||||
checked=$((checked + 1))
|
||||
local status="ok"
|
||||
|
||||
if [ ! -f "$path" ]; then
|
||||
status="missing"
|
||||
changes=$((changes + 1))
|
||||
echo "[$(date)] MISSING: $path" >> "$CHANGELOG"
|
||||
log_error "Protected driver missing: $path"
|
||||
else
|
||||
local cur_hash=$(sha256 "$path")
|
||||
if [ "$cur_hash" != "$expected_hash" ]; then
|
||||
status="changed"
|
||||
changes=$((changes + 1))
|
||||
echo "[$(date)] CHANGED: $path (expected: $expected_hash, got: $cur_hash)" >> "$CHANGELOG"
|
||||
log_error "Protected driver changed: $path"
|
||||
|
||||
# Auto-restore in enforce mode
|
||||
local mode=$(get_setting "protection_mode")
|
||||
if [ "$mode" = "enforce" ]; then
|
||||
local backup="$BACKUPDIR/${path#/}"
|
||||
if [ -f "$backup" ]; then
|
||||
cp -p "$backup" "$path" 2>/dev/null
|
||||
log "Auto-restored: $path"
|
||||
echo "[$(date)] RESTORED: $path" >> "$CHANGELOG"
|
||||
status="restored"
|
||||
else
|
||||
log_error "Cannot restore $path: no backup"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
ok=$((ok + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
[ "$first" = true ] && first=false || results="$results,"
|
||||
results="$results{\"path\":\"$path\",\"status\":\"$status\"}"
|
||||
fi
|
||||
path="" expected_hash=""
|
||||
;;
|
||||
esac
|
||||
done < "$BASELINE"
|
||||
|
||||
results="$results],\"checked\":$checked,\"ok\":$ok,\"changes\":$changes,\"time\":\"$(date -Iseconds 2>/dev/null || date)\"}"
|
||||
log "Integrity check: $checked checked, $ok ok, $changes changes"
|
||||
echo "$results"
|
||||
}
|
||||
|
||||
# --- Get protection status ---
|
||||
get_status() {
|
||||
local mode=$(get_setting "protection_mode")
|
||||
local protected=0 last_check="never"
|
||||
|
||||
[ -f "$BASELINE" ] && protected=$(grep -c '"path"' "$BASELINE" 2>/dev/null || echo 0)
|
||||
|
||||
# Get last check time from changelog
|
||||
if [ -f "$CHANGELOG" ]; then
|
||||
last_check=$(tail -1 "$CHANGELOG" 2>/dev/null | grep -o '^\[[^]]*\]' | tr -d '[]')
|
||||
fi
|
||||
|
||||
local watcher_running="false"
|
||||
is_running "protect" && watcher_running="true"
|
||||
|
||||
echo "{\"mode\": \"$mode\", \"protected_count\": $protected, \"last_check\": \"$last_check\", \"watcher_running\": $watcher_running}"
|
||||
}
|
||||
|
||||
# --- Set protection mode ---
|
||||
set_mode() {
|
||||
local mode="$1"
|
||||
case "$mode" in
|
||||
off|monitor|enforce)
|
||||
json_set "$CONFIGDIR/settings.json" "protection_mode" "$mode"
|
||||
log "Protection mode set to: $mode"
|
||||
|
||||
if [ "$mode" = "off" ]; then
|
||||
kill_by_pidfile "protect"
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"ok\", \"mode\": \"$mode\"}"
|
||||
;;
|
||||
*)
|
||||
echo '{"error": "Invalid mode. Use: off, monitor, enforce"}'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Toggle protection for a specific driver ---
|
||||
set_driver_protection() {
|
||||
local driver_id="$1"
|
||||
local protected="$2"
|
||||
|
||||
if [ -f "$REGISTRY" ]; then
|
||||
if [ "$protected" = "true" ]; then
|
||||
sed -i "/$driver_id/,/protected/{s/\"protected\": false/\"protected\": true/}" "$REGISTRY"
|
||||
else
|
||||
sed -i "/$driver_id/,/protected/{s/\"protected\": true/\"protected\": false/}" "$REGISTRY"
|
||||
fi
|
||||
log "Driver $driver_id protection: $protected"
|
||||
echo "{\"status\": \"ok\", \"driver\": \"$driver_id\", \"protected\": $protected}"
|
||||
else
|
||||
echo '{"error": "No driver registry"}'
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Watch loop (runs as background daemon) ---
|
||||
watch_loop() {
|
||||
log "Protection watcher started"
|
||||
while true; do
|
||||
local interval=$(get_setting_raw "protection_interval")
|
||||
[ -z "$interval" ] && interval=300
|
||||
|
||||
sleep "$interval"
|
||||
|
||||
local mode=$(get_setting "protection_mode")
|
||||
[ "$mode" = "off" ] && { log "Protection disabled, watcher exiting"; break; }
|
||||
|
||||
check_integrity > /dev/null 2>&1
|
||||
done
|
||||
}
|
||||
|
||||
# --- Get change log ---
|
||||
get_changelog() {
|
||||
local lines="${2:-50}"
|
||||
if [ -f "$CHANGELOG" ]; then
|
||||
tail -n "$lines" "$CHANGELOG"
|
||||
else
|
||||
echo "No changes detected"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
case "$1" in
|
||||
baseline) create_baseline ;;
|
||||
check) check_integrity ;;
|
||||
status) get_status ;;
|
||||
mode) set_mode "$2" ;;
|
||||
protect) set_driver_protection "$2" "$3" ;;
|
||||
watch) watch_loop ;;
|
||||
changelog) get_changelog "$2" ;;
|
||||
*) echo "Usage: protect.sh {baseline|check|status|mode|protect|watch|changelog} [args]" ;;
|
||||
esac
|
||||
342
scripts/scope_manager.sh
Normal file
342
scripts/scope_manager.sh
Normal file
@@ -0,0 +1,342 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Per-App & System-Wide Scope Manager
|
||||
# LSPosed-style driver scoping via mount namespace isolation
|
||||
|
||||
MODDIR=${MODDIR:-/data/adb/modules/driver-manager}
|
||||
. "$MODDIR/scripts/core.sh"
|
||||
log_init "$LOGDIR/scope.log"
|
||||
|
||||
SCOPES_FILE="$CONFIGDIR/scopes.json"
|
||||
REGISTRY="$CONFIGDIR/drivers.json"
|
||||
|
||||
# --- Clone file metadata from stock to custom ---
|
||||
clone_metadata() {
|
||||
local stock="$1" custom="$2"
|
||||
# Copy ownership
|
||||
local owner=$(stat -c '%u:%g' "$stock" 2>/dev/null)
|
||||
[ -n "$owner" ] && chown "$owner" "$custom" 2>/dev/null
|
||||
# Copy permissions
|
||||
local perms=$(stat -c '%a' "$stock" 2>/dev/null)
|
||||
[ -n "$perms" ] && chmod "$perms" "$custom" 2>/dev/null
|
||||
# Copy SELinux context
|
||||
local ctx=$(get_selinux_context "$stock")
|
||||
[ -n "$ctx" ] && chcon "$ctx" "$custom" 2>/dev/null
|
||||
# Copy timestamps
|
||||
touch -r "$stock" "$custom" 2>/dev/null
|
||||
}
|
||||
|
||||
# --- Apply a bind mount for a specific process (per-app scope) ---
|
||||
scope_for_process() {
|
||||
local pkg="$1"
|
||||
local stock_path="$2"
|
||||
local custom_path="$3"
|
||||
|
||||
if [ ! -f "$custom_path" ]; then
|
||||
log_error "Custom driver not found: $custom_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
clone_metadata "$stock_path" "$custom_path"
|
||||
|
||||
# Find all PIDs for this package
|
||||
local pids=$(pgrep -f "$pkg" 2>/dev/null)
|
||||
if [ -z "$pids" ]; then
|
||||
log "No running processes for $pkg, scope will apply on next launch"
|
||||
return 0
|
||||
fi
|
||||
|
||||
for pid in $pids; do
|
||||
nsenter --mount=/proc/$pid/ns/mnt -- mount --bind "$custom_path" "$stock_path" 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
log "Scoped $stock_path -> $custom_path for PID $pid ($pkg)"
|
||||
else
|
||||
log_error "Failed to scope for PID $pid ($pkg)"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# --- Apply a system-wide bind mount ---
|
||||
scope_system() {
|
||||
local stock_path="$1"
|
||||
local custom_path="$2"
|
||||
|
||||
if [ ! -f "$custom_path" ]; then
|
||||
log_error "Custom driver not found: $custom_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
clone_metadata "$stock_path" "$custom_path"
|
||||
mount --bind "$custom_path" "$stock_path" 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
log "System-wide scope: $stock_path -> $custom_path"
|
||||
else
|
||||
log_error "Failed system-wide scope: $stock_path"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Unmount a scope ---
|
||||
unscope() {
|
||||
local stock_path="$1"
|
||||
local pkg="$2"
|
||||
|
||||
if [ -n "$pkg" ] && [ "$pkg" != "system" ]; then
|
||||
local pids=$(pgrep -f "$pkg" 2>/dev/null)
|
||||
for pid in $pids; do
|
||||
nsenter --mount=/proc/$pid/ns/mnt -- umount "$stock_path" 2>/dev/null
|
||||
done
|
||||
log "Unscoped $stock_path for $pkg"
|
||||
else
|
||||
umount "$stock_path" 2>/dev/null
|
||||
log "Unscoped system-wide: $stock_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Apply all configured scopes ---
|
||||
apply_all() {
|
||||
[ ! -f "$SCOPES_FILE" ] && return 0
|
||||
|
||||
log "Applying all scopes"
|
||||
# Parse scopes.json - each scope: { driver_id, variant, mode, apps[] }
|
||||
local count=0
|
||||
|
||||
# Use a simple line-by-line parser for the scopes array
|
||||
local in_scope=false
|
||||
local driver_id="" variant="" mode="" stock_path="" custom_path=""
|
||||
local apps=""
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*'"driver_id"'*)
|
||||
driver_id=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"variant_path"'*)
|
||||
custom_path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"stock_path"'*)
|
||||
stock_path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"mode"'*)
|
||||
mode=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"apps"'*\[*)
|
||||
apps=""
|
||||
;;
|
||||
*'"'*'"'*)
|
||||
if [ -n "$stock_path" ] && [ -z "$mode" -o "$mode" = "app" ]; then
|
||||
local app=$(echo "$line" | sed 's/.*"\([^"]*\)".*/\1/')
|
||||
[ -n "$app" ] && apps="$apps $app"
|
||||
fi
|
||||
;;
|
||||
*\}*)
|
||||
if [ -n "$driver_id" ] && [ -n "$stock_path" ] && [ -n "$custom_path" ]; then
|
||||
if [ "$mode" = "system" ]; then
|
||||
scope_system "$stock_path" "$custom_path"
|
||||
count=$((count + 1))
|
||||
elif [ -n "$apps" ]; then
|
||||
for app in $apps; do
|
||||
scope_for_process "$app" "$stock_path" "$custom_path"
|
||||
count=$((count + 1))
|
||||
done
|
||||
fi
|
||||
fi
|
||||
driver_id="" variant="" mode="" stock_path="" custom_path="" apps=""
|
||||
;;
|
||||
esac
|
||||
done < "$SCOPES_FILE"
|
||||
|
||||
log "Applied $count scopes"
|
||||
}
|
||||
|
||||
# --- Unmount all active scopes ---
|
||||
unmount_all() {
|
||||
log "Unmounting all scopes"
|
||||
[ ! -f "$SCOPES_FILE" ] && return 0
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*'"stock_path"'*)
|
||||
local path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
[ -n "$path" ] && umount "$path" 2>/dev/null
|
||||
;;
|
||||
esac
|
||||
done < "$SCOPES_FILE"
|
||||
|
||||
log "All scopes unmounted"
|
||||
}
|
||||
|
||||
# --- Set a scope (called from API) ---
|
||||
# Usage: scope_manager.sh set <driver_id> <stock_path> <variant_path> <mode> [app1,app2,...]
|
||||
set_scope() {
|
||||
local driver_id="$1"
|
||||
local stock_path="$2"
|
||||
local variant_path="$3"
|
||||
local mode="$4"
|
||||
local apps_csv="$5"
|
||||
|
||||
# Build apps JSON array
|
||||
local apps_json="[]"
|
||||
if [ -n "$apps_csv" ] && [ "$mode" = "app" ]; then
|
||||
apps_json="[$(echo "$apps_csv" | sed 's/,/","/g' | sed 's/^/"/;s/$/"/' )]"
|
||||
fi
|
||||
|
||||
# Check if scope already exists for this driver, update it
|
||||
if grep -q "\"$driver_id\"" "$SCOPES_FILE" 2>/dev/null; then
|
||||
# Remove existing scope for this driver and re-add
|
||||
remove_scope "$driver_id"
|
||||
fi
|
||||
|
||||
# Append to scopes file
|
||||
local tmp="$CONFIGDIR/.scopes_tmp.json"
|
||||
if [ -f "$SCOPES_FILE" ] && [ -s "$SCOPES_FILE" ]; then
|
||||
# Insert before the closing ]}
|
||||
sed '$ s/\]}//' "$SCOPES_FILE" > "$tmp"
|
||||
# Add comma if there are existing scopes
|
||||
if grep -q '"driver_id"' "$SCOPES_FILE" 2>/dev/null; then
|
||||
echo "," >> "$tmp"
|
||||
fi
|
||||
else
|
||||
echo '{"scopes":[' > "$tmp"
|
||||
fi
|
||||
|
||||
cat >> "$tmp" << SCOPE
|
||||
{
|
||||
"driver_id": "$driver_id",
|
||||
"stock_path": "$stock_path",
|
||||
"variant_path": "$variant_path",
|
||||
"mode": "$mode",
|
||||
"apps": $apps_json
|
||||
}
|
||||
]}
|
||||
SCOPE
|
||||
|
||||
mv "$tmp" "$SCOPES_FILE"
|
||||
log "Set scope for $driver_id (mode: $mode)"
|
||||
|
||||
# Apply immediately
|
||||
if [ "$mode" = "system" ]; then
|
||||
scope_system "$stock_path" "$variant_path"
|
||||
else
|
||||
local IFS=','
|
||||
for app in $apps_csv; do
|
||||
scope_for_process "$app" "$stock_path" "$variant_path"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"ok\", \"driver\": \"$driver_id\", \"mode\": \"$mode\"}"
|
||||
}
|
||||
|
||||
# --- Remove a scope ---
|
||||
remove_scope() {
|
||||
local driver_id="$1"
|
||||
[ ! -f "$SCOPES_FILE" ] && return 0
|
||||
|
||||
# Get stock_path before removing so we can unmount
|
||||
local stock_path=$(grep -A3 "\"$driver_id\"" "$SCOPES_FILE" | grep '"stock_path"' | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
[ -n "$stock_path" ] && umount "$stock_path" 2>/dev/null
|
||||
|
||||
# Rebuild scopes file without this driver
|
||||
local tmp="$CONFIGDIR/.scopes_tmp.json"
|
||||
echo '{"scopes":[' > "$tmp"
|
||||
local first=true skip=false
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*"\"$driver_id\""*)
|
||||
skip=true
|
||||
;;
|
||||
*\}*)
|
||||
if [ "$skip" = true ]; then
|
||||
skip=false
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
[ "$skip" = true ] && continue
|
||||
# Skip the scopes header/footer
|
||||
echo "$line" | grep -q '"scopes"' && continue
|
||||
echo "$line" | grep -qE '^\[|^\]' && continue
|
||||
echo "$line" >> "$tmp"
|
||||
done < "$SCOPES_FILE"
|
||||
|
||||
echo "]}" >> "$tmp"
|
||||
mv "$tmp" "$SCOPES_FILE"
|
||||
log "Removed scope for $driver_id"
|
||||
echo "{\"status\": \"ok\", \"removed\": \"$driver_id\"}"
|
||||
}
|
||||
|
||||
# --- List active scopes ---
|
||||
list_scopes() {
|
||||
[ -f "$SCOPES_FILE" ] && cat "$SCOPES_FILE" || echo '{"scopes":[]}'
|
||||
}
|
||||
|
||||
# --- Monitor Zygote for new app launches ---
|
||||
# Watches for new processes and applies per-app scopes
|
||||
monitor_zygote() {
|
||||
log "Zygote monitor started"
|
||||
local known_pids=""
|
||||
|
||||
while true; do
|
||||
sleep 5
|
||||
[ ! -f "$SCOPES_FILE" ] && continue
|
||||
|
||||
# Get list of scoped apps
|
||||
local scoped_apps=$(grep '"apps"' -A50 "$SCOPES_FILE" 2>/dev/null | grep -o '"[a-z][a-zA-Z0-9.]*"' | tr -d '"' | sort -u)
|
||||
[ -z "$scoped_apps" ] && continue
|
||||
|
||||
for app in $scoped_apps; do
|
||||
local pids=$(pgrep -f "$app" 2>/dev/null)
|
||||
[ -z "$pids" ] && continue
|
||||
|
||||
for pid in $pids; do
|
||||
# Skip if we already applied scope to this PID
|
||||
echo "$known_pids" | grep -q " $pid " && continue
|
||||
|
||||
# Find the scope config for this app
|
||||
local stock_path="" custom_path=""
|
||||
local in_scope=false app_match=false
|
||||
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*'"stock_path"'*)
|
||||
stock_path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*'"variant_path"'*)
|
||||
custom_path=$(echo "$line" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
||||
;;
|
||||
*"\"$app\""*)
|
||||
app_match=true
|
||||
;;
|
||||
*\}*)
|
||||
if [ "$app_match" = true ] && [ -n "$stock_path" ] && [ -n "$custom_path" ]; then
|
||||
nsenter --mount=/proc/$pid/ns/mnt -- mount --bind "$custom_path" "$stock_path" 2>/dev/null
|
||||
[ $? -eq 0 ] && log "Auto-scoped $app PID $pid"
|
||||
fi
|
||||
stock_path="" custom_path="" app_match=false
|
||||
;;
|
||||
esac
|
||||
done < "$SCOPES_FILE"
|
||||
|
||||
known_pids="$known_pids $pid "
|
||||
done
|
||||
done
|
||||
|
||||
# Clean dead PIDs from known list periodically
|
||||
local new_known=""
|
||||
for pid in $known_pids; do
|
||||
[ -d "/proc/$pid" ] && new_known="$new_known $pid "
|
||||
done
|
||||
known_pids="$new_known"
|
||||
done
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
case "$1" in
|
||||
apply) apply_all ;;
|
||||
set) set_scope "$2" "$3" "$4" "$5" "$6" ;;
|
||||
remove) remove_scope "$2" ;;
|
||||
list) list_scopes ;;
|
||||
unmount_all) unmount_all ;;
|
||||
monitor) monitor_zygote ;;
|
||||
*) echo "Usage: scope_manager.sh {apply|set|remove|list|unmount_all|monitor} [args]" ;;
|
||||
esac
|
||||
63
service.sh
Normal file
63
service.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Main Service
|
||||
# Runs after boot_completed
|
||||
|
||||
MODDIR=${0%/*}
|
||||
LOGFILE="$MODDIR/logs/service.log"
|
||||
CONFIGDIR="$MODDIR/config"
|
||||
|
||||
. "$MODDIR/scripts/core.sh"
|
||||
|
||||
log_init "$LOGFILE"
|
||||
log "Service starting"
|
||||
|
||||
# Wait for boot to complete
|
||||
while [ "$(getprop sys.boot_completed)" != "1" ]; do
|
||||
sleep 1
|
||||
done
|
||||
sleep 3
|
||||
log "Boot completed, initializing"
|
||||
|
||||
# --- Run driver scan if registry doesn't exist ---
|
||||
if [ ! -f "$CONFIGDIR/drivers.json" ] || [ ! -s "$CONFIGDIR/drivers.json" ]; then
|
||||
log "No driver registry found, running initial scan"
|
||||
sh "$MODDIR/scripts/driver_registry.sh" scan
|
||||
fi
|
||||
|
||||
# --- Create protection baseline if missing ---
|
||||
if [ ! -f "$CONFIGDIR/baseline.json" ] || [ ! -s "$CONFIGDIR/baseline.json" ]; then
|
||||
log "No protection baseline found, creating"
|
||||
sh "$MODDIR/scripts/protect.sh" baseline
|
||||
fi
|
||||
|
||||
# --- Load kernel modules from autoload list ---
|
||||
log "Loading kernel modules"
|
||||
sh "$MODDIR/scripts/ko_manager.sh" autoload
|
||||
|
||||
# --- Apply driver scopes ---
|
||||
log "Applying driver scopes"
|
||||
sh "$MODDIR/scripts/scope_manager.sh" apply
|
||||
|
||||
# --- Start protection monitor ---
|
||||
SETTINGS=$(cat "$CONFIGDIR/settings.json" 2>/dev/null)
|
||||
PROT_MODE=$(echo "$SETTINGS" | grep -o '"protection_mode"[[:space:]]*:[[:space:]]*"[^"]*"' | grep -o '"[^"]*"$' | tr -d '"')
|
||||
if [ "$PROT_MODE" = "monitor" ] || [ "$PROT_MODE" = "enforce" ]; then
|
||||
log "Starting protection monitor (mode: $PROT_MODE)"
|
||||
sh "$MODDIR/scripts/protect.sh" watch &
|
||||
echo $! > "$MODDIR/run/protect.pid"
|
||||
fi
|
||||
|
||||
# --- Monitor Zygote for new app launches (apply per-app scopes) ---
|
||||
MONITOR_ZYGOTE=$(echo "$SETTINGS" | grep -o '"monitor_zygote"[[:space:]]*:[[:space:]]*[a-z]*' | grep -o '[a-z]*$')
|
||||
if [ "$MONITOR_ZYGOTE" = "true" ]; then
|
||||
log "Starting Zygote process monitor for per-app scoping"
|
||||
sh "$MODDIR/scripts/scope_manager.sh" monitor &
|
||||
echo $! > "$MODDIR/run/scope_monitor.pid"
|
||||
fi
|
||||
|
||||
log "Service initialization complete"
|
||||
|
||||
# --- Keep service alive for API calls ---
|
||||
while true; do
|
||||
sleep 86400
|
||||
done
|
||||
9
system.prop
Normal file
9
system.prop
Normal file
@@ -0,0 +1,9 @@
|
||||
# Driver Manager v2 - System Properties
|
||||
# Minimal properties set; drivers managed dynamically via scoping
|
||||
|
||||
# USB OTG support for external drivers (SDR dongles, controllers)
|
||||
persist.sys.usb.otg=1
|
||||
|
||||
# Bluetooth profiles
|
||||
persist.bluetooth.a2dp_offload.disabled=false
|
||||
persist.bluetooth.enablenewavrcp=true
|
||||
9
system/etc/permissions/driver-manager.xml
Normal file
9
system/etc/permissions/driver-manager.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<permissions>
|
||||
<feature name="android.hardware.usb.host" />
|
||||
<feature name="android.hardware.usb.accessory" />
|
||||
<feature name="android.hardware.bluetooth" />
|
||||
<feature name="android.hardware.bluetooth_le" />
|
||||
<feature name="android.hardware.vulkan.level" version="1" />
|
||||
<feature name="android.hardware.opengles.aep" />
|
||||
</permissions>
|
||||
8
system/etc/sysconfig/driver-manager.xml
Normal file
8
system/etc/sysconfig/driver-manager.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<config>
|
||||
<feature name="android.hardware.usb.host" />
|
||||
<feature name="android.hardware.usb.accessory" />
|
||||
<feature name="android.hardware.bluetooth_le" />
|
||||
<feature name="android.hardware.wifi.direct" />
|
||||
<feature name="android.hardware.gamepad" />
|
||||
</config>
|
||||
23
uninstall.sh
Normal file
23
uninstall.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Manager v2 - Uninstall Script
|
||||
# Runs when module is removed via KernelSU
|
||||
|
||||
MODDIR=${0%/*}
|
||||
|
||||
# Kill running processes
|
||||
for pidfile in "$MODDIR"/run/*.pid; do
|
||||
[ -f "$pidfile" ] && kill $(cat "$pidfile") 2>/dev/null
|
||||
done
|
||||
|
||||
# Unmount any active driver scopes
|
||||
if [ -f "$MODDIR/scripts/scope_manager.sh" ]; then
|
||||
sh "$MODDIR/scripts/scope_manager.sh" unmount_all 2>/dev/null
|
||||
fi
|
||||
|
||||
# Unload managed kernel modules
|
||||
if [ -f "$MODDIR/scripts/ko_manager.sh" ]; then
|
||||
sh "$MODDIR/scripts/ko_manager.sh" unload_all 2>/dev/null
|
||||
fi
|
||||
|
||||
# Config and data stay in /data/adb/modules/driver-manager/
|
||||
# which KernelSU cleans up automatically
|
||||
1213
webroot/index.html
Normal file
1213
webroot/index.html
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user