DEV Community

PaΓ§oca
PaΓ§oca

Posted on

Running Native glibc (Debian) Binaries on Android 15 Without PRoot

πŸ”§ TL;DR: Android 15 broke PRoot with stricter seccomp filters. After ~10 hours of debugging, I found a working solution using patchelf + LD_PRELOAD= to run native Linux (Debian/glibc) binaries directly on Termux!

🎯 What will you achieve? (Click to expand)

By following this guide, you will be able to:

  • βœ… Run GCC, Python, Bun, Git and 300+ more Debian packages natively
  • βœ… Compile code directly on your Android phone
  • βœ… Use Linux development tools without cloud dependencies
  • βœ… Get a true Linux experience on mobile


The Problem

Android 15 significantly tightened its seccomp security filters. Running any Debian/glibc binary via proot-distro now fails with:

Bad system call (SIGSYS)
set_robust_list: Function not implemented
Enter fullscreen mode Exit fullscreen mode

⚠️ Important: This isn't a configuration issue. The kernel literally blocks the syscalls that PRoot needs to emulate a Linux environment.

Every guide said "just use PRoot" β†’ so I spent ~10 hours finding what actually works.

πŸ€” Why should you care about this? (Click to expand)

If you want to run Linux development tools on your Android device without relying on cloud services or complex setups, this guide is for you!

This solution works because we bypass PRoot entirely and run binaries natively using patchelf to modify the ELF binary's interpreter path.


Understanding Seccomp

πŸ”’ What is Seccomp? (Click to learn)

Seccomp (Secure Computing Mode) is a Linux kernel security feature that:

  • Filters system calls (syscalls) a process can make
  • Restricts access to sensitive kernel operations
  • Prevents exploitation by limiting what programs can do

Think of it like a firewall for programs - it decides which "doors" a program can use.

πŸ“– Learn more about seccomp (Red Hat Documentation)


The Solution β€” Three Tiers

I developed a three-tier approach depending on your needs:

πŸ“‹ Click to see all solution tiers
Tier Method Root Required Native Level Best For
1 LD_PRELOAD= + direct binary ❌ No ⭐⭐⭐⭐⭐ Simple binaries
2 su -c wrapper with env vars βœ… Yes ⭐⭐⭐⭐ Complex binaries
3 Smart APT wrapper βœ… Yes ⭐⭐⭐ Package management

Tier 1 β€” Most Native (No Root)

# After patchelf on binary:
LD_PRELOAD= /path/to/glibc-binary "$@"
Enter fullscreen mode Exit fullscreen mode
  • True native execution
  • The ELF binary loads glibc directly
  • LD_PRELOAD= prevents Termux from injecting its Bionic lib

Tier 2 β€” Production Stable (Root Required)

su -c "LD_PRELOAD= LD_LIBRARY_PATH=\$GLIBC/lib/aarch64-linux-gnu:\$GLIBC/usr/lib/aarch64-linux-gnu \
       \$GLIBC/usr/bin/binary \"\\\$@\""
Enter fullscreen mode Exit fullscreen mode
  • More compatible for complex binaries
  • Handles deep transitive dependencies

Tier 3 β€” "Just Works" (Smart APT)

Transparent apt install that tries Termux repos first, falls back to Debian, and auto-patches new binaries.


Root Cause β€” Why PRoot Fails

πŸ› The Three Problems (Click to expand)

Problem 1: Seccomp Blocking

Android 15 seccomp blocks set_robust_list called by glibc at startup β†’ SIGSYS
Enter fullscreen mode Exit fullscreen mode

πŸ“– What is set_robust_list?

Problem 2: Termux LD_PRELOAD Conflict

Termux injects libtermux-exec-ld-preload.so into every process. This Bionic library looks for libc.so β†’ which doesn't exist in glibc β†’ crash.

Problem 3: Root-Created Symlink Permissions

Symlinks created by apt inside chroot (running as root) inherit security attributes that make them inaccessible to the Termux user UID.


Device Information

πŸ“± My Device Setup (Click to see details)

πŸ’‘ Samsung Variants Explained:

  • Exynos (Europe/Asia): Uses Samsung's own processor β€” our device!
  • Snapdragon (USA/LATAM/China): Uses Qualcomm processor β€” different kernel/firmware
Spec Value
Device Samsung Galaxy S10e (SM-G970F)
Variant Exynos 9820 (International - EMEA)
Processor Exynos 9820 - 8nm Octa-core
Architecture ARM64 (AArch64)
Android 15
ROM ExtremeROM Nexus by ExtremeXT
Root KernelSU
Terminal Termux (F-Droid)


Prerequisites

βœ… Requirements Checklist (Click to expand)

Before we begin, make sure you have:

Why F-Droid?

  • More permissive update cycle
  • Full access to proot-distro
  • Better compatibility with custom ROMs

πŸ“– Learn more about F-Droid


Installation Guide

Step 1: Install Debian rootfs

# Install required packages
pkg install proot-distro rsync -y

# Install Debian
proot-distro install debian

# Define paths
ROOTFS="$PREFIX/var/lib/proot-distro/installed-rootfs/debian"
GLIBC="$HOME/glibc-root"

# Install base packages
proot-distro login debian -- bash -c "
  apt-get update &&
  apt-get install -y gcc g++ make python3 bun curl unzip zip ca-certificates
"
Enter fullscreen mode Exit fullscreen mode

πŸ“– What is proot-distro? | What is rsync?


Step 2: Extract rootfs to native location

mkdir -p "$GLIBC"
rsync -a "$ROOTFS/" "$GLIBC/"
Enter fullscreen mode Exit fullscreen mode

⚠️ Critical: Fix Symlinks (Click to expand)

Root-created symlinks inherit security context that blocks Termux UID access. This fix is mandatory!

#!/usr/bin/env python3
"""Fix symlinks for Termux UID compatibility"""
import os, subprocess

rootfs = os.path.expanduser("~/glibc-root")

for dirpath, dirs, files in os.walk(rootfs):
    for name in files:
        path = os.path.join(dirpath, name)
        if os.path.islink(path):
            target = None
            try:
                target = os.readlink(path)
            except:
                result = subprocess.run(
                    ["su", "-c", f"readlink {path}"],
                    capture_output=True, text=True
                )
                target = result.stdout.strip()

            if target:
                try:
                    os.unlink(path)
                except:
                    subprocess.run(["su", "-c", f"rm -f {path}"], capture_output=True)
                os.symlink(target, path)

print("βœ“ Symlinks repaired.")
Enter fullscreen mode Exit fullscreen mode


Step 3: Fix the dynamic linker

GLIBC="$HOME/glibc-root"
LOADER="$GLIBC/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"

mkdir -p "$GLIBC/lib64"
ln -sf "$LOADER" "$GLIBC/lib64/ld-linux-aarch64.so.1"
ln -sf "$LOADER" "$GLIBC/lib/ld-linux-aarch64.so.1"
Enter fullscreen mode Exit fullscreen mode

πŸ“– Learn about ld-linux.so


Step 4: Mass patchelf β€” make all binaries self-contained

GLIBC="$HOME/glibc-root"
LOADER="$GLIBC/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"
RPATH="$GLIBC/lib/aarch64-linux-gnu:$GLIBC/usr/lib/aarch64-linux-gnu"
OUT="$PREFIX/bin"

for bin in "$GLIBC/usr/bin/"* "$GLIBC/bin/"*; do
    [[ -f "$bin" && -x "$bin" ]] || continue
    name=$(basename "$bin")-glibc
    cp "$bin" "$OUT/$name"
    patchelf --set-interpreter "$LOADER" \
             --set-rpath "$RPATH" \
             "$OUT/$name" 2>/dev/null || rm -f "$OUT/$name"
done

echo "βœ“ Patched $(ls $OUT/*-glibc 2>/dev/null | wc -l) binaries"
Enter fullscreen mode Exit fullscreen mode

πŸ“– What is patchelf?


Step 5: Fix ownership

su -c "chown -R $(id -u):$(id -g) $HOME/glibc-root"
su -c "find $HOME/glibc-root -type d -exec chmod 755 {} \;"
Enter fullscreen mode Exit fullscreen mode

Step 6: Create the Smart APT wrapper

cat > ~/apt-debian << 'SCRIPT'
#!/data/data/com.termux/files/usr/bin/bash
# apt-debian v3 β€” installs from Debian and auto-patchelfs

GLIBC="$HOME/glibc-root"
LOADER="$GLIBC/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"
RPATH="$GLIBC/lib/aarch64-linux-gnu:$GLIBC/usr/lib/aarch64-linux-gnu"

case "$1" in
  install)
    shift
    BEFORE=$(find "$GLIBC/usr/bin" "$GLIBC/bin" -maxdepth 1 -type f -executable 2>/dev/null | sort)
    su -c "cp /system/etc/resolv.conf $GLIBC/etc/resolv.conf 2>/dev/null || \
           echo 'nameserver 8.8.8.8' > $GLIBC/etc/resolv.conf"
    su -c "chroot $GLIBC /usr/bin/apt-get install -y $*"
    AFTER=$(find "$GLIBC/usr/bin" "$GLIBC/bin" -maxdepth 1 -type f -executable 2>/dev/null | sort)
    NEW=$(comm -13 <(echo "$BEFORE") <(echo "$AFTER"))

    for bin in $NEW; do
      name="$(basename $bin)-glibc"
      cp "$bin" "$PREFIX/bin/$name"
      patchelf --set-interpreter "$LOADER" --set-rpath "$RPATH" "$PREFIX/bin/$name" 2>/dev/null
      chmod +x "$PREFIX/bin/$name"
      echo "βœ“ $name available"
    done
    ;;
  update)
    su -c "chroot $GLIBC /usr/bin/apt-get update"
    ;;
  *)
    echo "Usage: apt-debian {install|update} [packages]"
    ;;
esac
SCRIPT

chmod +x ~/apt-debian
mv ~/apt-debian "$PREFIX/bin/apt-debian"
Enter fullscreen mode Exit fullscreen mode

Step 7: Add to PATH

echo 'export PATH="$HOME/.glibc-bin:$PATH"' >> ~/.bashrc
echo 'export GLIBC_ROOT="$HOME/glibc-root"' >> ~/.bashrc
source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

Testing

πŸ§ͺ Verify Installation (Click to expand)
Test Command Expected Output
LD_PRELOAD= gcc-glibc --version gcc (Debian 14.2.0-6) 14.2.0
bun --version 1.x.x
apt-debian install htop && htop Interactive process manager

Quick Tests

# Test GCC
LD_PRELOAD= gcc-glibc --version

# Test Bun
bun --version

# Test APT wrapper
apt-debian install htop && htop
Enter fullscreen mode Exit fullscreen mode


Known Limitations

⚠️ Important Notes (Click to expand)
  1. Requires Root β€” The su -c fallback needs KernelSU/Magisk root. Tier 1 works rootless but may fail on complex binaries.

  2. LD_PRELOAD= Must Be Cleared β€” Termux injects libtermux-exec-ld-preload.so which crashes glibc. Always run with LD_PRELOAD= if not using wrappers.

  3. Symlink Repair Is Mandatory β€” apt creates symlinks as root; they inherit security context that blocks Termux UID access.


Available Binaries

πŸ“¦ What Works Out of the Box (Click to expand)
Binary Package Official Site
βœ… GCC 14 gcc-glibc gcc.gnu.org
βœ… Python 3.13 python3.13-glibc python.org
βœ… Bun bun bun.sh
βœ… Git git-glibc git-scm.com
βœ… htop htop-glibc htop.dev

300+ Debian aarch64 packages available via apt-debian install!


Understanding ELF and Dynamic Linker

πŸ“š Technical Background (Click to learn)

What is ELF?

ELF (Executable and Linkable Format) is the standard binary format for executables on Linux systems. It tells the OS:

  • How to load the program into memory
  • Where to find the code and data
  • What libraries are needed
  • How to execute the program

πŸ“– Learn more about ELF

What is the Dynamic Linker?

The dynamic linker (ld-linux.so) is the first thing that executes when you run any Linux program. It:

  1. Loads the program into memory
  2. Finds required libraries
  3. Resolves symbols
  4. Prepares the program to run

πŸ“– Dynamic linker documentation


Samsung Firmware Flashing Reference

πŸ“± If You Need to Flash Firmware (Click to expand)

Tool Comparison

Tool Platform Link
Odin Windows PC only Wikipedia
Heimdall Linux/macOS GitHub / Official
Eros Android (No PC!) GitHub / XDA

Galaxy S10e (SM-G970F) Resources

πŸ“– XDA Forum - Galaxy S10e ROMs, Kernels & Recoveries


Summary

Component Technology Reference
Terminal Termux GitHub
ROM ExtremeROM Nexus Android 15
Root KernelSU Exynos 9820
Distribution Debian glibc
Compatibility Layer patchelf ELF modification
Execution Method LD_PRELOAD= bypass Native execution
Device Samsung Galaxy S10e (SM-G970F) - Exynos 9820 ARM64/AArch64

Resources & References

πŸ“± Device & Hardware

Topic Link
Samsung Galaxy S10e (SM-G970F) - Exynos GSMArena
Exynos 9820 Processor Wikipedia
AArch64/ARM64 Architecture Wikipedia
XDA Forum - Galaxy S10e XDA Forums

πŸ”§ Development Tools

Tool Official Site
Termux termux.dev / F-Droid
patchelf GitHub
proot-distro GitHub
F-Droid f-droid.org
Bun bun.sh
GCC gcc.gnu.org
Python python.org
Git git-scm.com
htop htop.dev

πŸ“š Linux Concepts

Topic Link
ELF Format Wikipedia
Seccomp Red Hat Docs
Dynamic Linker man7.org
rsync rsync.samba.org

πŸ” Root & ROM

Project Link
KernelSU kernelsu.org
Magisk topjohnwu.github.io/Magisk
ExtremeROM Nexus GitHub

πŸ”§ Firmware Tools

Tool Link
Odin Wikipedia
Heimdall GitHub
Eros GitHub

Credits

❀️ Special Thanks (Click to expand)

This article was made possible with the help of several amazing tools and communities:

AI Assistants

Tool Role Link
Gemini (Google AI) Used in terminal for debugging gemini.google.com
Claude (Anthropic) Solved complex technical challenges claude.ai
MiniMax Agent Formatted and corrected the article agent.minimax.io

ROM & Root Stack

Project Description Link
ExtremeROM Nexus Custom ROM by ExtremeXT GitHub
KernelSU Root solution kernelsu.org

Termux

Tool Description Link
Termux The amazing terminal emulator that makes all of this possible termux.dev / GitHub


πŸ”§ Developed entirely on Termux β€” Samsung Galaxy S10e (SM-G970F) Β· Exynos 9820 Β· Android 15 Β· ExtremeXT Β· KernelSU


If this article helped you, give it a πŸ’š and share with others!

Questions? Feel free to ask in the comments!

Top comments (0)