Skip to content

KSUN + SUSFS + DroidSpaces — verified booting, containers working

Pre-release
Pre-release

Choose a tag to compare

@Mohithash Mohithash released this 17 Jul 16:41
· 9 commits to peridot-6.1.175 since this release

peridot 6.1.175 + KernelSU-Next v3.3.0 + SUSFS v2.2.0 + DroidSpaces (LXC-style
containers, ravindu644/Droidspaces-OSS).

Built from 88c1263bc9deacb5d6933e2e7839a44336ab0f94 on peridot-6.1.175
verified directly: CI compiled this exact commit, the zip is a real AnyKernel3
package (Image + anykernel.sh), kernel.release =
6.1.175-android14-11-ga3b9c44908dd-ab13320413.

Two earlier builds on this feature bootlooped

Both compiled cleanly and still failed on-device. Neither failure was captured
with diagnostics at the time, so what follows is the strongest evidence
available, not a confirmed root cause:

  • 1st attempt had CONFIG_CGROUP_DEVICE/CONFIG_CGROUP_PIDS enabled, which
    grow enum cgroup_subsys_id and resize struct css_set.subsys[] — measured via
    hand-built genksyms, this shifts the exported-symbol ABI checksum for
    __put_task_struct and everything reachable from task_struct.
  • 2nd attempt had CONFIG_BRIDGE_NETFILTER/CONFIG_NF_TABLES enabled, which
    independently shifted the checksum for 113 of 115 exports in
    kernel/sched/core.c (wake_up_process, sched_setscheduler,
    set_cpus_allowed_ptr, runqueues, ...).

Removing each pair, in turn, was followed by a stable boot. That correlation is
solid — a controlled two-step bisection, not a guess. The exact mechanism is
less certain than it might sound
: on-device evidence from this successful boot
(below) shows this vendor kernel tolerates ~1791 symbol-CRC disagreements as
non-fatal "...but ignore" warnings by default, so a plain "CRC mismatch means
hard module rejection" story doesn't fully hold up. Something about those two
config pairs broke this specific device's boot; a checksum shift is the
measurable fact, not a confirmed causal chain to the failure.

The CONFIG_SYSVIPC KABI relocation (scripts/droidspaces/integrate.sh) was not
the cause of either bootloop — confirmed clean via direct CRC comparison against
the boot-tested base, both times, and again in the raw log below.

Raw on-device verification

Reported via a separate Claude session with adb access to the physical device.
Commands and their literal output, unedited:

Full raw log (uname, dmesg, namespace stress test, live Alpine container)
################################################################################
# Device: Xiaomi peridot (POCO F6, SM8635) — A/B slot _b
# Kernel: Theettam / KernelSU-Next 3.3.0 + SUSFS v2.2.0 + DroidSpaces (SYSVIPC)
# Built:  Fri Jul 17 15:59:37 UTC 2026   (commit 88c1263bc9de, peridot-6.1.175)
################################################################################

===================== CHECK 1 =====================
$ adb shell su -c 'uname -r'
6.1.175-android14-11-ga3b9c44908dd-ab13320413

===================== CHECK 2 =====================
$ adb shell su -c 'dmesg | grep -iE "module verification failed|invalid module format|unknown symbol"'
                              <-- empty: zero hard module-load rejections

$ adb shell su -c 'dmesg | grep -ic "disagrees about version"'
1791                          <-- all "...but ignore" (module loads anyway);
                                  this kernel tolerates CRC drift as non-fatal
                                  on a large number of symbols by default

===================== CHECK 3 =====================
$ adb shell su -c 'dmesg | grep -iE "kernel panic|Oops|BUG:|Call trace|WARNING:"' | head -30
[    1.435480] pmic_glink_debug: disagrees about version of symbol _dev_err, but ignore...
[    1.435524] pmic_glink_debug: disagrees about version of symbol put_device, but ignore...
[    1.438328] qcom_iommu_debug: disagrees about version of symbol _dev_err, but ignore...
[    1.438403] qcom_iommu_debug: disagrees about version of symbol dev_driver_string, but ignore...
[    1.503417] spmi_pmic_arb_debug: disagrees about version of symbol _dev_err, but ignore...
[    1.503433] spmi_pmic_arb_debug: disagrees about version of symbol _dev_info, but ignore...
[    1.503461] spmi_pmic_arb_debug: disagrees about version of symbol put_device, but ignore...
[    1.503612] spmi_pmic_arb_debug 10b14000.qcom,spmi-debug: SPMI PMIC arbiter debug bus disabled by fuse
[    1.507479] qti_battery_debug: disagrees about version of symbol _dev_err, but ignore...
[    1.688899] qcom_cpufreq_hw_debug: disagrees about version of symbol _dev_err, but ignore...
[    1.935618] mtdoops: pares mtd_dt, mem_address =0xa7000000, mem_size =0x400000
[    1.935620] mtdoops: pares mtd_dt, pmsg_size =0x200000,console-size =0x200000
[    1.997878] mtdoops: ready 4, 1389 (no erase)
[    1.997881] mtdoops: Attached to MTD device 0
[    1.997884] block2mtd: mtd0: [/dev/block/by-name/oops] erase_size = 2048KiB [2097152]
[    4.061737] WARNING: Unprivileged eBPF is enabled, data leaks possible via Spectre v2 BHB attacks!
[  901.295275] capability: warning: `wpa_supplicant' uses 32-bit capabilities (legacy support in use)
[ 1050.987097] [GTP-INF][brl_irq_enbale:463] warning: irq depth imbalance!
# no kernel panic, no real Oops, no real BUG: — remaining WARNINGs are stock/benign

===================== CHECK 4 (fork + namespace stress via unshare) =====================
$ adb shell su -c 'unshare -m -i -p -U -r -f /system/bin/sh /data/local/tmp/ctest.sh'
=== inside new namespaces ===
pid_in_ns=1
forked_reaped=300
proc_pids_visible_in_ns=3
sysvipc_in_ns=msg,sem,shm,
uid_in_ns=0
=== done ===

$ adb shell su -c 'ls /proc | grep -c "^[0-9][0-9]*$"'     # host, for contrast
764

===================== CHECK 5 (live Alpine container "hi", PID 22215) =====================
$ adb shell su -c '/data/local/Droidspaces/bin/droidspaces --name=hi run cat /etc/os-release'
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.23.5
PRETTY_NAME="Alpine Linux v3.23"

$ adb shell su -c '/data/local/Droidspaces/bin/droidspaces --name=hi run uname -a'
Linux hi 6.1.175-android14-11-ga3b9c44908dd-ab13320413 #1 SMP PREEMPT Fri Jul 17 15:59:37 UTC 2026 aarch64 GNU/Linux

$ adb shell su -c '/data/local/Droidspaces/bin/droidspaces --name=hi run ps -ef'
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 16:49 ?        00:00:00 /sbin/init
dhcpcd     132     1  0 16:49 ?        00:00:00 dhcpcd: [manager] [ip4] [ip6]
root       135   132  0 16:49 ?        00:00:00 dhcpcd: [privileged proxy]
dhcpcd     136   132  0 16:49 ?        00:00:00 dhcpcd: [network proxy]
dhcpcd     137   132  0 16:49 ?        00:00:00 dhcpcd: [control proxy]
root       168     1  0 16:49 ?        00:00:00 sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups
root       175     1  0 16:49 console  00:00:00 /sbin/getty 38400 console
dhcpcd     176   135  0 16:49 ?        00:00:00 dhcpcd: [BPF ARP] eth0 172.28.36.75
root       201     0  0 16:49 ?        00:00:00 ps -ef

$ adb shell su -c 'cat /proc/22215/root/etc/alpine-release'
3.23.5

$ adb shell su -c 'for p in $(ls /proc | grep -E "^[0-9]+$"); do readlink /proc/$p/ns/pid; done | sort | uniq -c | sort -rn'
    770 pid:[4026531836]      <-- host PID namespace
      8 pid:[4026535174]      <-- container "hi" PID namespace (8 procs)

$ adb shell su -c 'for n in pid mnt net ipc uts user cgroup; do echo "$n host=$(readlink /proc/1/ns/$n) ctnr=$(readlink /proc/22215/ns/$n)"; done'
pid    host=pid:[4026531836]    ctnr=pid:[4026535174]      # ISOLATED
mnt    host=mnt:[4026532614]    ctnr=mnt:[4026535264]      # ISOLATED
net    host=net:[4026531840]    ctnr=net:[4026535175]      # ISOLATED
ipc    host=ipc:[4026531839]    ctnr=ipc:[4026535172]      # ISOLATED (SYSVIPC)
uts    host=uts:[4026531838]    ctnr=uts:[4026535171]      # ISOLATED
user   host=user:[4026531837]   ctnr=user:[4026531837]     # shared (allow_userns=0 by config)
cgroup host=cgroup:[4026531835] ctnr=cgroup:[4026535173]   # ISOLATED

Reading it:

  • No hard module-load rejection (unknown symbol / invalid module format /
    module verification failed) — empty
  • No panic, real Oops, or real BUG since boot
  • 300 fork/exit cycles inside a PID+USER namespace under unshare — the
    task_struct alloc/__put_task_struct path, zero faults
  • Real namespace isolation: pid/mnt/net/ipc/uts/cgroup separated from host (ls /proc shows 3 processes in-namespace vs 764 on host); user namespace is
    shared by DroidSpaces config (allow_userns=0), not a kernel limitation
  • A real Alpine Linux 3.23.5 container running via the DroidSpaces binary, with
    init+dhcpcd+sshd+getty — confirmed by reading the container's actual
    rootfs at /proc/<pid>/root/etc/alpine-release, independent of the tool's own
    reporting

What this does not cover

One device, one boot slot, one test session. Confirms every vendor module that
loads on this hardware loads without a hard rejection — does not cover code
paths only exercised by workloads that weren't run, or other SoC variants.

Known limitations vs the full DroidSpaces feature list

No per-device cgroup allowlisting, no --pids-limit enforcement, no in-container
nftables/bridge-netfilter. Basic container networking (the already-enabled
veth/bridge/NAT path) is unaffected — Alpine's dhcpcd got a lease in the
test above.

Still EXPERIMENTAL. Flash with a backup and fastboot recovery ready.