127 lines
5.9 KiB
Bash
127 lines
5.9 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# build-stock-gki.sh — build cellguard.ko against the STOCK Google GKI kernel
|
||
|
|
# that the target device is running, on an aarch64 build host (e.g. RPi5).
|
||
|
|
#
|
||
|
|
# Why this exists
|
||
|
|
# ---------------
|
||
|
|
# The device is a stock Pixel (rango / Tensor G5) running a stock GKI kernel:
|
||
|
|
# 6.6.102-android15-8-g6eb5b2a8c46b-ab14739656-4k (RANDSTRUCT_NONE, CFI_CLANG,
|
||
|
|
# MODVERSIONS, MODULE_SIG_PROTECT, LTO_NONE)
|
||
|
|
#
|
||
|
|
# For an out-of-tree module to LOAD there:
|
||
|
|
# 1. It must match the kernel ABI: same vermagic *flags* (the release string is
|
||
|
|
# ignored under MODVERSIONS) and matching symbol CRCs. => build against the
|
||
|
|
# exact stock source @ the build's git SHA + the build's vmlinux.symvers.
|
||
|
|
# 2. It must not import GKI *protected* symbols (kernel_read/kernel_write). The
|
||
|
|
# module resolves those at runtime via a kprobe->kallsyms bootstrap instead
|
||
|
|
# (see cellguard.c: cg_resolve_protected). Nothing to do here, just noting it.
|
||
|
|
#
|
||
|
|
# This does NOT require Google's signing key: MODULE_SIG_FORCE is off, so an
|
||
|
|
# unsigned module loads as long as it imports no protected symbols.
|
||
|
|
#
|
||
|
|
# Usage
|
||
|
|
# -----
|
||
|
|
# ./build-stock-gki.sh # auto-detect build info from adb device
|
||
|
|
# BID=14739656 KREL=6.6.102-android15-8-g6eb5b2a8c46b-ab14739656-4k \
|
||
|
|
# KSHA=6eb5b2a8c46b6393ccde67a51f2e2f56277791c6 KBRANCH=android15-6.6-2025-10 \
|
||
|
|
# ./build-stock-gki.sh # or pin everything explicitly
|
||
|
|
#
|
||
|
|
# Requires (Debian/RPiOS): clang lld llvm bc bison flex libssl-dev libelf-dev git curl
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
# ---- locations -------------------------------------------------------------
|
||
|
|
HERE="$(cd "$(dirname "$0")" && pwd)" # .../CellGuard/common/kmod
|
||
|
|
WORK="${WORK:-$HERE/.gki-build}" # persistent build workspace
|
||
|
|
SRC="$WORK/common" # kernel source tree
|
||
|
|
ART="$WORK/artifacts" # downloaded GKI artifacts
|
||
|
|
mkdir -p "$WORK" "$ART"
|
||
|
|
|
||
|
|
# ---- 1. determine target build --------------------------------------------
|
||
|
|
# KREL = full kernel release; BID = ci.android.com build number; KSHA = kernel
|
||
|
|
# common git sha; KBRANCH = the kernel/common branch to fetch the sha from.
|
||
|
|
if [ -z "${KREL:-}" ] && command -v adb >/dev/null && adb get-state >/dev/null 2>&1; then
|
||
|
|
KREL="$(adb shell 'uname -r' | tr -d '\r')"
|
||
|
|
echo "[*] device kernel release: $KREL"
|
||
|
|
fi
|
||
|
|
: "${KREL:?set KREL (e.g. 6.6.102-android15-8-g<sha12>-ab<bid>-4k) or connect adb}"
|
||
|
|
|
||
|
|
# derive BID (ab#######) and short sha (g############) from the release string
|
||
|
|
BID="${BID:-$(printf '%s' "$KREL" | sed -nE 's/.*-ab([0-9]+)-.*/\1/p')}"
|
||
|
|
GSHORT="$(printf '%s' "$KREL" | sed -nE 's/.*-g([0-9a-f]{12,}).*/\1/p')"
|
||
|
|
: "${BID:?could not derive BID from KREL; pass BID=...}"
|
||
|
|
: "${KBRANCH:=android15-6.6}" # override if the build used a dated branch, e.g. android15-6.6-2025-10
|
||
|
|
|
||
|
|
echo "[*] BID=$BID gsha=$GSHORT branch=$KBRANCH"
|
||
|
|
|
||
|
|
# ---- 2. download stock GKI artifacts for this exact build ------------------
|
||
|
|
# kernel-headers.tar.gz (source headers), vmlinux.symvers (symbol CRCs = our
|
||
|
|
# Module.symvers), abi_symbollist.raw (KMI allow-list), manifest (pins KSHA).
|
||
|
|
RAW="https://ci.android.com/builds/submitted/${BID}/kernel_aarch64/latest/raw"
|
||
|
|
fetch() { # fetch <artifact> -> $ART/<artifact>
|
||
|
|
[ -s "$ART/$1" ] && { echo " cached $1"; return; }
|
||
|
|
echo " download $1"
|
||
|
|
curl -fsSL -o "$ART/$1" "$RAW/$1"
|
||
|
|
}
|
||
|
|
echo "[*] fetching GKI artifacts for ab$BID"
|
||
|
|
fetch "vmlinux.symvers"
|
||
|
|
fetch "abi_symbollist.raw"
|
||
|
|
fetch "manifest_${BID}.xml"
|
||
|
|
fetch "kernel-headers.tar.gz" # not strictly needed (we clone full source) but handy
|
||
|
|
|
||
|
|
# exact kernel/common sha: prefer manifest, fall back to KSHA env
|
||
|
|
if [ -z "${KSHA:-}" ]; then
|
||
|
|
KSHA="$(sed -nE 's/.*path="common"[^>]*revision="([0-9a-f]{40})".*/\1/p' "$ART/manifest_${BID}.xml" | head -1)"
|
||
|
|
fi
|
||
|
|
: "${KSHA:?could not determine kernel sha; pass KSHA=<40hex>}"
|
||
|
|
echo "[*] kernel/common sha: $KSHA"
|
||
|
|
|
||
|
|
# ---- 3. get the exact stock source ----------------------------------------
|
||
|
|
if [ ! -d "$SRC/.git" ]; then
|
||
|
|
echo "[*] cloning kernel/common (shallow) ..."
|
||
|
|
git clone --depth 1 -b "$KBRANCH" \
|
||
|
|
https://android.googlesource.com/kernel/common "$SRC"
|
||
|
|
fi
|
||
|
|
if [ "$(git -C "$SRC" rev-parse HEAD)" != "$KSHA" ]; then
|
||
|
|
echo "[*] fetching exact sha $KSHA ..."
|
||
|
|
git -C "$SRC" fetch --depth 1 origin "$KSHA"
|
||
|
|
git -C "$SRC" checkout -q "$KSHA"
|
||
|
|
fi
|
||
|
|
echo "[*] source at $(git -C "$SRC" rev-parse HEAD)"
|
||
|
|
|
||
|
|
# ---- 4. configure with the DEVICE's real .config --------------------------
|
||
|
|
# Pull /proc/config.gz from the device for a byte-exact config (RANDSTRUCT off,
|
||
|
|
# CFI on, MODVERSIONS on, etc). Fall back to a saved copy if adb is unavailable.
|
||
|
|
if command -v adb >/dev/null && adb get-state >/dev/null 2>&1; then
|
||
|
|
echo "[*] pulling device .config"
|
||
|
|
adb exec-out 'su -c "cat /proc/config.gz"' 2>/dev/null | zcat > "$SRC/.config" \
|
||
|
|
|| adb exec-out 'cat /proc/config.gz' | zcat > "$SRC/.config"
|
||
|
|
elif [ -s "$HERE/device.config" ]; then
|
||
|
|
cp "$HERE/device.config" "$SRC/.config"
|
||
|
|
else
|
||
|
|
echo "!! no .config: connect adb or place device.config next to this script" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
cp "$ART/vmlinux.symvers" "$SRC/Module.symvers" # real CRCs for MODVERSIONS
|
||
|
|
|
||
|
|
# ---- 5. prepare + build ----------------------------------------------------
|
||
|
|
# Native aarch64 clang (Debian) — kCFI type-IDs are ABI-stable across clang
|
||
|
|
# versions, so this interoperates with the device's clang-18 GKI kernel.
|
||
|
|
export ARCH=arm64 LLVM=1
|
||
|
|
JOBS="${JOBS:-$(nproc)}"
|
||
|
|
echo "[*] olddefconfig + modules_prepare (-j$JOBS) ..."
|
||
|
|
make -C "$SRC" -j"$JOBS" olddefconfig >/dev/null
|
||
|
|
make -C "$SRC" -j"$JOBS" modules_prepare
|
||
|
|
|
||
|
|
echo "[*] building module ..."
|
||
|
|
make -C "$SRC" -j"$JOBS" M="$HERE" modules
|
||
|
|
|
||
|
|
echo
|
||
|
|
echo "[✓] built: $HERE/cellguard.ko"
|
||
|
|
modinfo "$HERE/cellguard.ko" | grep -E 'vermagic|name'
|
||
|
|
echo
|
||
|
|
echo "Load it via the KernelSU module path (service.sh does this on boot):"
|
||
|
|
echo " adb push $HERE/cellguard.ko /data/local/tmp/cellguard.ko"
|
||
|
|
echo " adb shell su -c 'cp /data/local/tmp/cellguard.ko \\"
|
||
|
|
echo " /data/adb/modules/cellguard/common/kmod/cellguard.ko && \\"
|
||
|
|
echo " insmod /data/adb/modules/cellguard/common/kmod/cellguard.ko'"
|