Files
driver-manager/scripts/protect.sh
sssnake b88141a9c5 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>
2026-04-03 06:01:07 -07:00

234 lines
7.9 KiB
Bash

#!/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