Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1832efc
Define one-shot bounded app-owned Shizuku-to-Arena PFD ingress
isomorphisms Oct 14, 2026
cac03d2
Implement bounded stream admission and fail-closed Shizuku producer c…
isomorphisms Oct 14, 2026
f6cb5ca
Define canonical app-private Arena publisher for Shizuku stream ingress
isomorphisms Oct 14, 2026
e58f068
Commit verified ICU stream into canonical appendfat Arena with atomic…
isomorphisms Oct 14, 2026
6330e12
Define private Binder transactions for Shizuku streaming ingress
isomorphisms Oct 14, 2026
8407125
Implement authenticated private Binder write-PFD and zero-exit comple…
isomorphisms Oct 14, 2026
5a076f7
Test cross-process Shizuku ingress framing, failure isolation and rec…
isomorphisms Oct 14, 2026
d4e2678
Verify real appendfat publication and source reopening with refusal c…
isomorphisms Oct 14, 2026
d9771d7
Drive real canonical Arena ingress and durable readback acceptance
isomorphisms Oct 14, 2026
0e9cca6
Reuse pinned Shizuku ICU runner for direct binary PFD streaming
isomorphisms Oct 14, 2026
a01f901
Expose ICU binary stream through existing Binder-named Shizuku provider
isomorphisms Oct 14, 2026
384bb86
Require real Shizuku shell/root authorization before binary stream
isomorphisms Oct 14, 2026
7f55ad3
Add Shizuku ICU binary-stdout worker for scoped Binder write PFD
isomorphisms Oct 14, 2026
5b6de06
Bind producer URI to app-owned navigation via Binder BEGIN reply
isomorphisms Oct 14, 2026
440f4c1
Transfer app-authorized URL with private ingress PFD, not worker-supp…
isomorphisms Oct 14, 2026
c7aead8
Define broker-side ICU runner streaming directly into private Binder …
isomorphisms Oct 14, 2026
b28baad
Stream pinned ICU worker stdout into app-owned Binder PFD and report …
isomorphisms Oct 14, 2026
364786a
Exercise pinned ICU binary stdout and Shizuku denial without file-bas…
isomorphisms Oct 14, 2026
5680d92
Make injection refusal fixture inert, not executable by the test shell
isomorphisms Oct 14, 2026
cfa89be
Test app-scoped Shizuku PFD ingress, canonical appendfat and Android …
isomorphisms Oct 14, 2026
13973b6
Record private one-shot Shizuku ingress, security and incomplete devi…
isomorphisms Oct 14, 2026
02b5e25
Explicitly include standard boolean literals in native ingress
isomorphisms Oct 14, 2026
43515c9
Validate URL and pinned ICU identity before any Shizuku authority probe
isomorphisms Oct 14, 2026
d6904a7
Reconcile private ingress with v2 admission and repair host acceptance
isomorphisms Oct 19, 2026
801dba2
Validate paired ICU captures before private Arena v2 publication
isomorphisms Oct 24, 2026
735d8e9
Retain current ICU captures without admitting unsupported Google HTML
isomorphisms Oct 25, 2026
b2f4cbc
Require the selected HTTP version in retained ICU host adapters
isomorphisms Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions .github/workflows/ib-c67-shizuku-ingress.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
name: IB C67 Shizuku-to-private-Arena ingress
on:
pull_request:
paths:
- 'native/android/ib_shizuku_arena_ingress.*'
- 'native/android/ib_shizuku_arena_publish.*'
- 'native/android/ib_shizuku_ingress_binder.*'
- 'native/android/ib_shizuku_ingress_runner.*'
- 'lib/android_shizuku_icu_provider.grease'
- 'lib/android_binder_icu.grease'
- 'bin/ib_android_icu_stdout.grease'
- 'bin/ib_android_icu_frame.grease'
- 'tests/test_shizuku*'
- 'examples/autogenerated/google-capture/**'
- '.github/workflows/ib-c67-shizuku-ingress.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
fast-host:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- id: ick
uses: isomorphisms/ai-ci/ick-host@015cc7901ae0b3ad262b476f24e129b53c56db95
- name: Cross-process binary PFD stream and refusal cases
env:
ICK: ${{ steps.ick.outputs.compiler }}
run: |
set -euo pipefail
mkdir -p build/shizuku-ingress/fast
"$ICK" -fno-link-libatomic -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror -pthread \
native/android/ib_reader_pfd.c \
native/android/ib_shizuku_arena_ingress.c \
tests/test_shizuku_arena_ingress_host.c \
-o build/shizuku-ingress/fast/test-ingress
build/shizuku-ingress/fast/test-ingress | tee build/shizuku-ingress/fast/receipt.txt
grep -F 'PASS: cross-process anonymous FD delivery' build/shizuku-ingress/fast/receipt.txt
sha256sum build/shizuku-ingress/fast/test-ingress > build/shizuku-ingress/fast/sha256.txt
- name: Pinned ICU stdout and Shizuku denial controls
run: |
set -euo pipefail
sh -n lib/android_shizuku_icu_provider.grease
sh -n lib/android_binder_icu.grease
sh -n bin/ib_android_icu_stdout.grease
sh -n bin/ib_android_icu_frame.grease
sh tests/test_shizuku_icu_stream.sh | tee build/shizuku-ingress/fast/icu-stream-receipt.txt
grep -F 'PASS: pinned ICU binary stdout' build/shizuku-ingress/fast/icu-stream-receipt.txt
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ib-shizuku-ingress-fast
path: build/shizuku-ingress/fast/
if-no-files-found: error

pinned-canonical-and-arm:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Checkout pinned canonical appendfat
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
repository: isomorphisms/sd-card-append-fat
ref: 05a0cb7246c5a9f46abfbe92925812e7b607f454
path: .deps/appendfat
persist-credentials: false
- id: ick
uses: isomorphisms/ai-ci/ick-host@015cc7901ae0b3ad262b476f24e129b53c56db95
- name: Actual canonical Arena publication and reopen
env:
ICK: ${{ steps.ick.outputs.compiler }}
run: |
set -euo pipefail
test "$(git -C .deps/appendfat rev-parse HEAD)" = 05a0cb7246c5a9f46abfbe92925812e7b607f454
test -x "$ICK"
mkdir -p build/shizuku-ingress/canonical
"$ICK" -fno-link-libatomic -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror \
.deps/appendfat/lib/appendfat_arena.c .deps/appendfat/tools/appendfat_arena.c \
-o build/shizuku-ingress/canonical/appendfat_arena
"$ICK" -fno-link-libatomic -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror \
-fPIE -c .deps/appendfat/lib/appendfat_arena.c \
-o build/shizuku-ingress/canonical/appendfat_arena.o
"$ICK" -fno-link-libatomic -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror -pthread -I.deps/appendfat/lib \
native/android/ib_reader_pfd.c native/android/ib_arena_source_owner.c \
native/android/ib_shizuku_arena_ingress.c native/android/ib_shizuku_arena_publish.c \
tests/test_shizuku_ingress_canonical.c \
build/shizuku-ingress/canonical/appendfat_arena.o \
-o build/shizuku-ingress/canonical/test-ingress
env IB_APPEND_ARENA="$GITHUB_WORKSPACE/build/shizuku-ingress/canonical/appendfat_arena" \
IB_INGRESS_CANONICAL_TEST="$GITHUB_WORKSPACE/build/shizuku-ingress/canonical/test-ingress" \
sh tests/test_shizuku_ingress_canonical.sh | tee build/shizuku-ingress/canonical/receipt.txt
grep -F 'PASS: real pinned appendfat Arena stream commit' build/shizuku-ingress/canonical/receipt.txt
"$ICK" -fno-link-libatomic -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror -pthread -I.deps/appendfat/lib \
native/android/ib_reader_pfd.c native/android/ib_arena_source_owner.c \
native/android/ib_shizuku_arena_ingress.c native/android/ib_shizuku_arena_publish.c \
tests/test_shizuku_frame_canonical.c \
build/shizuku-ingress/canonical/appendfat_arena.o \
-o build/shizuku-ingress/canonical/test-frame
env IB_APPEND_ARENA="$GITHUB_WORKSPACE/build/shizuku-ingress/canonical/appendfat_arena" \
IB_INGRESS_CANONICAL_TEST="$GITHUB_WORKSPACE/build/shizuku-ingress/canonical/test-frame" \
sh tests/test_shizuku_ingress_canonical.sh > build/shizuku-ingress/canonical/frame-receipt.txt
cat build/shizuku-ingress/canonical/frame-receipt.txt
grep -F 'PASS: paired ICU frame through private ingress' build/shizuku-ingress/canonical/frame-receipt.txt
sha256sum build/shizuku-ingress/canonical/test-ingress \
build/shizuku-ingress/canonical/test-frame \
build/shizuku-ingress/canonical/appendfat_arena \
build/shizuku-ingress/canonical/appendfat_arena.o \
> build/shizuku-ingress/canonical/sha256.txt
- name: Cross-compile Binder/PFD ingress and canonical publisher adapter
run: |
set -eu
ndk_version=27.3.13750724
yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;$ndk_version" >/dev/null
toolchain="$ANDROID_HOME/ndk/$ndk_version/toolchains/llvm/prebuilt/linux-x86_64/bin"
for entry in 'armeabi-v7a armv7a-linux-androideabi29 ARM' 'arm64-v8a aarch64-linux-android29 AArch64'; do
set -- $entry
abi=$1; target=$2; machine=$3
mkdir -p "build/shizuku-ingress/$abi"
"$toolchain/$target-clang" -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror \
-fPIC -shared -pthread native/android/ib_reader_pfd.c \
native/android/ib_arena_pfd_provider.c \
native/android/ib_shizuku_arena_ingress.c \
native/android/ib_shizuku_ingress_binder.c \
native/android/ib_shizuku_ingress_runner.c -lbinder_ndk \
-o "build/shizuku-ingress/$abi/libib_shizuku_ingress.so"
"$toolchain/$target-clang" -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror \
-fPIC -I.deps/appendfat/lib -c native/android/ib_shizuku_arena_publish.c \
-o "build/shizuku-ingress/$abi/ib_arena_publisher.o"
"$toolchain/llvm-readelf" -h "build/shizuku-ingress/$abi/libib_shizuku_ingress.so" > "build/shizuku-ingress/$abi/elf.txt"
grep -F "Machine:" "build/shizuku-ingress/$abi/elf.txt" | grep -F "$machine"
sha256sum "build/shizuku-ingress/$abi/libib_shizuku_ingress.so" \
"build/shizuku-ingress/$abi/ib_arena_publisher.o" > "build/shizuku-ingress/$abi/sha256.txt"
printf 'abi\t%s\nbinder_ndk\tCOMPILED\ncanonical_appendfat_android_link\tNOT_RUN\nshizuku_runtime\tNOT_RUN\nphysical_C67\tNOT_RUN\n' "$abi" \
> "build/shizuku-ingress/$abi/receipt.tsv"
done
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ib-shizuku-ingress-canonical-abi
path: |
build/shizuku-ingress/canonical/
build/shizuku-ingress/armeabi-v7a/
build/shizuku-ingress/arm64-v8a/
if-no-files-found: error
15 changes: 15 additions & 0 deletions bin/ib_android_icu_frame.grease
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env grease
# Private Binder worker: send ICU's paired capture to the app's WRITE PFD.
# The app validates framing/metadata, commits the body, and reopens it. This
# worker has no app-private Arena path or publication authority.
set -eu
if test "$#" -ne 1; then
printf 'usage: ib_android_icu_frame.grease HTTP_URL\n' >&2
exit 2
fi
script_directory=$(dirname "$0")
repository_root=$(CDPATH='' cd -- "$script_directory/.." && pwd)
. "$repository_root/lib/android_shizuku_host.grease"
. "$repository_root/lib/android_shizuku_icu_provider.grease"
. "$repository_root/lib/android_binder_icu.grease"
ib_binder_icu_frame "$1"
18 changes: 18 additions & 0 deletions bin/ib_android_icu_stdout.grease
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env grease
# Run only from an authorized, pinned private Binder broker holding the
# WRITE-end PFD as stdout. No Arena path or app UID filesystem access.
set -eu
if test "$#" -ne 1; then
printf 'usage: ib_android_icu_stdout.grease HTTP_URL\n' >&2
exit 2
fi
script_directory=$(dirname "$0")
repository_root=$(CDPATH='' cd -- "$script_directory/.." && pwd)
. "$repository_root/lib/android_shizuku_host.grease"
. "$repository_root/lib/android_shizuku_icu_provider.grease"
. "$repository_root/lib/android_binder_icu.grease"

# Writes literal ICU response bytes to stdout. The caller must close its PFD
# and send the real exit status to private Binder FINISH; failed or truncated
# stdout cannot become a committed source.
ib_binder_icu_stream "$1"
129 changes: 129 additions & 0 deletions docs/c67-shizuku-arena-ingress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# C67 Shizuku → app-private Arena ingress

**Status:** implemented native stream/commit boundaries, host tests and ABI build;
**not a usable phone URL flow**. Stacked on IB #153 → #152 → #112.

## Reconciliation with admitted v2 source owner

The paired ICU metadata/body capture from the v2 source branch and the
body-only stdout ingress remain distinct capabilities. Reconciliation retains
the metadata-aware three-argument `ib_shizuku_icu_get`; the stdout helper does
not overwrite it. The canonical ingress publisher still emits v1 with
`navigation_admitted=NO`. Tests independently reopen its retained bytes with
the canonical store and require the newer v2 HTML source owner to refuse
those receipts. They do not weaken the source owner or claim that this
body-only publisher can feed an admitted page.

The host object is compiled with `-fPIE` for its PIE test executable. Stream
tests count actual invocations separately from lines in the remote command.
The inherited shell CI boundary remains compatibility debt; local stream
execution uses Grease implementation `5651cf97a1b5042f24f14112a7ade9a1518eb0bc`
with inherited-shell compatibility enabled. Leak checking is disabled only
for that sanitized runtime in the disposable container, whose process
namespace prevents LeakSanitizer inspection.

The next product dependency is observed HTTP metadata over the authorized
private ingress, followed by Android app-handle lifecycle and the checked
Idriç reader. None is established by compiling the Binder adapter.

## One owner per operation

The *browser/Idriç host* owns the requested URL, request identity and
navigation generation. An approved Shizuku broker (UID 2000 if the actual
Binder caller is shell; otherwise an explicitly granted app UID) has only
a one-shot **write descriptor**. It never opens app-private storage or
receives a pathname for the Arena.

app-owned browser event (URL, request ID, navigation generation)
↓ explicit approved Binder caller UID
private ShizukuArenaIngress.v1 Binder object
↙ transaction 2: BEGIN(request_id, generation)
app returns approved URL + one WRITE ParcelFileDescriptor
↓
approved broker process / pinned Grease runner
↓ verified Shizuku authority (rish), checked ICU DEX + native SO
↓ exactly binary ICU stdout → inherited PFD; no body-as-string
app-owned reader thread drains a bounded anonymous pipe concurrently
↓ broker closes its WRITE descriptor
transaction 3: FINISH(request_id, generation, actual ICU exit)
↓ app confirms EOF, <= 4 MiB, successful zero exit, current generation
↓ app-owned canonical sd-card-append-fat append + commit pointer
↓ independent committed-range readback and exact byte comparison
↓ atomic private ib-icu-arena-v1 receipt publication
existing IB source-owner verifies receipt, bytes and SHA-256
↓ later source-linked Idriç prepaint and native reader (NOT WIRED)

### Native owners

- \`ib_shizuku_arena_ingress.{h,c}\`: single-use stream lifecycle, exact
Binder caller UID/ID/generation admission, bounded concurrent draining,
35-second deadline, 4 MiB body cap, cancellation and fail-closed FINISH.
- \`ib_shizuku_ingress_binder.{h,c}\`: separate private Binder interface.
BEGIN transmits the *app-authorized* URL and a PFD, never a storage name.
FINISH accepts only process exit 0 before calling the publisher.
- \`ib_shizuku_ingress_runner.{h,c}\`: broker side, obtains the write PFD,
launches a separately qualified Grease executable/worker using
\`posix_spawn\` with that FD mapped onto stdout, watches exit/death,
closes PFD, reports actual exit status. The launcher and script must be
pinned by Cat Food; the local ownership checks alone do not attest them.
- \`lib/android_shizuku_icu_provider.grease\`: existing checked ICU
command reused for both ordinary capture and new stdout streaming.
\`bin/ib_android_icu_stdout.grease\` is its narrow binary output entry.
- \`ib_shizuku_arena_publish.{h,c}\`: app-owned persistence callback using
the **actual** \`appendfat_arena\` C API, not an alternate store. The
source root/receipts/locks must already exist with 0700 ownership.
Each request ID gets a unique lock. Existing appendfat owns the .used
commit-pointer and lock protocol. After append it independently
reopens/verifies every byte, then fsyncs a temporary receipt and
atomically links it at \`receipts/REQUEST_ID.tsv\`. Failed writes do not
publish a valid receipt; committed but unreferenced tails remain
inaccessible to reader navigation.

The v1 receipt retains \`UNOBSERVED\` for HTTP status, resolved URL and MIME
and \`navigation_admitted=NO\` until ICU #35 metadata is integrated. It is
**only** proof of retained source bytes, not evidence that a URL was rendered.

## Security properties

- Shell UID 2000 and a Termux/app bridge UID differ. Access is bound to
the *actual* Binder caller UID that the app approved for one navigation;
there is no wildcard permission and no authority derived from page data.
- The source directory is 0700 and belongs to the receiving Android app
process. No world-readable \`/data/local/tmp\` response and no reliance
on cross-UID ordinary-file access. Path names from the producer never
identify source files in the app.
- On nonzero ICU exit, source too large or empty, stale generation, denied
Shizuku, broker death, timeout, duplicate ID, full Arena, write/readback
failure, malformed receipt, or path substitution: do not make a new
current source available. The prior committed receipt remains valid.
- Broker's actual ICU command still requires Cat Food-pinned SHA-256 of
both Android ICU DEX and native transport. It does not silently use
WebView, \`HttpURLConnection\`, curl or a reader-owned network client.
- Binder service is never registered globally; the native Android host
must distribute its object privately and reject unknown/unapproved
clients. Merely compiling a Binder class is not physical authorization.

## Verification limits

The fast source tests use two Linux processes and SCM_RIGHTS transfer to
exercise the actual reader thread and one-shot source admission. They
test refused UID, request identity, epoch, unsafe URL, worker exit 29,
empty/oversized/late output, duplicate calls and retained recovery.

The pinned-storage tests use the real \`sd-card-append-fat\` C implementation
compiled by the checked ICK compiler; append, pointer publication, complete
source receipt, duplicate prevention, corruption and independent PFD reopen
are exercised. The Android CI compiles the native Binder/runner library for
ARM32 and ARM64 and the canonical publisher *adapter object*. Linking
the canonical appendfat code for Android still needs the qualified target
compiler/runtime; the object alone is not a complete Android app.

**Not yet done:** delivering private Binder handles between real MIRO C67
UIDs; app-side Android lifecycle creating/arming ingress; Cat Food packaging
and pinned launcher deployment; real Shizuku+rish execution of ICU HTTPS
and its response metadata; full native Android publisher linkage;
Idriç prepaint projection and live reader navigation; physical device
receipts. Do not advertise a URL-capable APK from this PR.

Tracking: IB #151, #142, #141, #97; PR #112, #129, #147, #152, #153,
and ICU PR #35.
Loading
Loading