Files
CellGuard/common/kmod/build-stock-gki.sh

127 lines
5.9 KiB
Bash
Raw Normal View History

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