Skip to content

Latest commit

 

History

History
66 lines (51 loc) · 5.89 KB

File metadata and controls

66 lines (51 loc) · 5.89 KB

Kernel Check evidence record

Status: reviewed

The Kernel Check detector asks whether the running kernel looks like a custom or community kernel rather than the vendor's build, and whether kernel-facing views agree. These are heuristics about the build; they do not prove root.

Signals

Kernel identity consistency

  • Observable signal: the kernel release and version from the uname syscall, uname, /proc/version, /proc/sys/kernel/osrelease and System.getProperty.
  • Producing subsystem: the kernel's UTS namespace and procfs.
  • Mechanism: a module that hooks one identity path leaves the others disagreeing.
  • References: kernel/common Documentation/filesystems/proc.rst (/proc/version and /proc/sys/kernel); system/core rootdir/init.rc (hostname localhost, so uname output starts "Linux localhost").
  • Applicability: every release.
  • Visibility limits: none for these world-readable views.
  • Result states: consistent, mismatch.
  • Interpretation: a mismatch between identity sources is evidence of rewriting.

Community kernel markers

  • Observable signal: emoji, CJK and other scripts, Telegram handles, @ mentions, known community identifiers and non-release major versions in the kernel identity.
  • Producing subsystem: the kernel build's version string.
  • Mechanism: community kernels usually brand their version strings.
  • References: Discovery only: the marker catalog comes from observed community kernel strings.
  • Applicability: every release.
  • Visibility limits: a custom kernel can use a vendor-looking string.
  • Result states: detected, clean.
  • Interpretation: markers are heuristics and stay below direct evidence.

Boot command line and kernel pointers

  • Observable signal: critical options in /proc/cmdline and whether kernel pointers are exposed.
  • Producing subsystem: the bootloader's command line and the kernel's kptr_restrict setting.
  • Mechanism: permissive or debug options and exposed pointers are unusual on user builds.
  • References: kernel/common Documentation/filesystems/proc.rst (/proc/cmdline and /proc/kallsyms).
  • Applicability: /proc/cmdline is readable only where SELinux allows it.
  • Visibility limits: unreadable sources are reported as partial.
  • Result states: detected, clean, unavailable.
  • Interpretation: a permissive command line is danger; pointer exposure is a warning.

Storage path filter bypass

  • Observable signal: whether /sdcard/Android/data can be listed through a path with ignorable Unicode codepoints.
  • Producing subsystem: MediaProvider's FUSE path handling for shared storage.
  • Mechanism: an unpatched path filter treats a path with an ignorable codepoint as a different, unprotected directory.
  • References: Discovery only: the report labels this CVE-2024-43093 after the Android security bulletin; the MediaProvider fix itself was not reviewed.
  • Applicability: devices before the fix.
  • Visibility limits: storage permissions and scoped storage change what the probe can list.
  • Result states: unpatched, partially patched, patched, inconclusive.
  • Interpretation: a working bypass is a patch-level finding, not a kernel finding.

ARM64 CPU identity

  • Observable signal: MIDR_EL1 read through the kernel's EL0 MRS emulation on each logical CPU, against the identity the kernel cached for that CPU in its sysfs midr_el1 node or its /proc/cpuinfo block.
  • Producing subsystem: the kernel's per-CPU cpuinfo_arm64 record and its MRS emulation.
  • Mechanism: a read pinned to a CPU, and confirmed by getcpu() to have run there, exposes a cached identity that was rewritten. Pinning alone is not enough: moving the app to another cpuset or pausing a CPU moves the thread, and a read taken on another core of a heterogeneous SoC would disagree for that reason alone, so such reads are discarded and a value counts only when three confirmed reads agree.
  • References: kernel/common Documentation/arch/arm64/cpu-feature-registers.rst (MIDR_EL1 holds the value of the CPU it is fetched on, racy without affinity) and arch/arm64/kernel/cpufeature.c on android13-5.15 and android15-6.6 (the emulated value is read_cpuid_id()); kernel.org v6.12 arch/arm64/kernel/cpuinfo.c (sysfs midr_el1 and /proc/cpuinfo both print cpu_data[cpu].reg_midr, stored when the CPU comes online); kernel.org v5.10 and v6.12 arch/arm64/kernel/entry-common.c (the emulation runs with interrupts enabled); kernel.org v5.10 to v6.12 kernel/cgroup/cpuset.c (cpuset_attach() resets the affinity of moved tasks; 6.6 and 6.12 keep a requested mask only where it intersects the new cpuset, 6.1 does not) and kernel/sched/core.c (select_fallback_rq() moves pinned tasks off inactive CPUs); kernel.org v6.1 kernel/sys.c (getcpu() reports the CPU it runs on); kernel.org v6.12 and v6.15 arch/arm64/include/asm/el2_setup.h and arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h (what a KVM guest reads as MIDR_EL1); system/core libprocessgroup task_profiles.cpp and task_profiles.json (app threads join the top-app, foreground and background cpusets); bionic libc/SYSCALLS.TXT (bionic calls getcpu, so app seccomp allows it); the Arm Architecture Reference Manual defines the register but was not consulted here.
  • Applicability: arm64 only; other ABIs report it as unavailable.
  • Visibility limits: kernels without the register exposure cannot be compared, and CPUs outside the app's cpuset are not visited. KVM gives a guest the MIDR_EL1 of the physical CPU its vCPU is running on unless the VMM sets the guest's implementation ID registers, which Linux 6.15 allows and 6.12 does not, so a guest on a heterogeneous host can disagree with its own cached identity without any rewriting.
  • Result states: consistent, mismatch, partial, unavailable.
  • Interpretation: a confirmed mismatch is danger. CPUs whose reads could not be confirmed on the pinned CPU, or changed between reads, are not compared and leave the result partial.

Known gaps

  • The storage path filter bypass is a MediaProvider patch check that lives in the kernel detector; see docs/architecture/follow-ups.md.