Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9452cad
Define checked reader-owned PFD source admission contract
isomorphisms Oct 14, 2026
05134e5
Verify private Binder parcel descriptors before reader source publica…
isomorphisms Oct 14, 2026
ffc84e5
Exercise cross-process reader PFD verification and fail-closed source…
isomorphisms Oct 14, 2026
0dac735
Check native reader PFD admission on host and cross-compile Binder ABI
isomorphisms Oct 14, 2026
e077732
Document private scoped Binder/PFD contract and remaining Idriç Andro…
isomorphisms Oct 14, 2026
9ed23d8
Define UID-scoped native Arena PFD Binder provider contract
isomorphisms Oct 14, 2026
851deca
Implement UID-gated Binder PFD provider for verified Arena sources
isomorphisms Oct 14, 2026
554ef2d
Cross-build private Arena Binder provider with native reader
isomorphisms Oct 14, 2026
7e80861
Refuse Arena file descriptors and shell UID at private Binder provider
isomorphisms Oct 14, 2026
9d156b2
Admit only finite read-only PFD pipes, not backing Arena descriptors
isomorphisms Oct 14, 2026
26b81c8
Refuse path-backed and writable descriptors in reader acceptance
isomorphisms Oct 14, 2026
a8e7dd8
Describe private native provider and accepted read-only pipe boundary
isomorphisms Oct 14, 2026
a1a9963
Expose shared private Binder class for remote proxy association
isomorphisms Oct 14, 2026
b2c5194
Share native Binder service class identity with consumer proxy
isomorphisms Oct 14, 2026
36dd6d1
Associate authenticated private Binder interface class before client …
isomorphisms Oct 14, 2026
44a82b0
Expose checked SHA-256 for Arena source owner validation
isomorphisms Oct 14, 2026
1cfe4eb
Share reader SHA-256 with private Arena source owner
isomorphisms Oct 14, 2026
9cf28c2
Define app-private source owner callback for canonical Arena and PFD
isomorphisms Oct 14, 2026
571d77e
Read canonical private Arena receipt and emit verified finite PFD pipe
isomorphisms Oct 14, 2026
53c93d7
Test receipt-bound app-private Arena to native PFD source publication
isomorphisms Oct 14, 2026
cbdb7c0
Exercise native private PFD handoff with canonical appendfat Arena
isomorphisms Oct 14, 2026
1b896a3
Keep hostile receipt fixture zero-terminated during mutation
isomorphisms Oct 14, 2026
c343649
Test real canonical Arena-to-private PFD callback and cross-build ARM…
isomorphisms Oct 14, 2026
f9fd28a
Define native app host assembly joining private Arena and Binder prov…
isomorphisms Oct 14, 2026
e111e33
Connect native Binder service to canonical source-owner callback
isomorphisms Oct 14, 2026
4108533
Cross-build app-owned Binder+Arena native assembly for both Android ABIs
isomorphisms Oct 14, 2026
7a5d8d5
Use pinned ICK for canonical appendfat Unicode C instead of host cc
isomorphisms Oct 14, 2026
3a56496
Accept numeric suffix in known Arena receipt keys such as sha256
isomorphisms Oct 14, 2026
197bd5d
Document source-owning private binder assembly and real appendfat hos…
isomorphisms Oct 14, 2026
a9702df
Do not let Arena writer locks block the reader Binder dispatch indefi…
isomorphisms Oct 14, 2026
56fec2a
Create Binder class once safely across concurrent IPC calls
isomorphisms Oct 14, 2026
2e4a672
Add fast synthetic host acceptance independent of ICK bootstrap
isomorphisms Oct 14, 2026
1f369df
Run fast host PFD admission tests separately from expensive pinned IC…
isomorphisms Oct 14, 2026
26f215a
Bind source length and SHA ticket to returned private Binder descriptor
isomorphisms Oct 14, 2026
5afbc6b
Return authenticated receipt metadata with PFD callback
isomorphisms Oct 14, 2026
1d9e0ad
Deliver receipt-derived ticket alongside private descriptor
isomorphisms Oct 14, 2026
18b58fb
Return bounded source length and digest inside authenticated PFD reply
isomorphisms Oct 14, 2026
34d3d7e
Authenticate PFD metadata against browser-held ticket before source read
isomorphisms Oct 14, 2026
3cf15c6
Check new Binder callback returns metadata with source descriptor
isomorphisms Oct 14, 2026
2708575
Specify receipt-derived length and SHA in Binder PFD reply
isomorphisms Oct 14, 2026
2324eb7
Bind PFD source-owner admission to complete ICU/Arena v2 receipt and …
isomorphisms Oct 15, 2026
5535805
Test v2 admitted HTML and stale v1 refusal through canonical and synt…
isomorphisms Oct 15, 2026
74a9777
Test v2 admitted HTML and stale v1 refusal through canonical and synt…
isomorphisms Oct 15, 2026
44e3152
Require source-generation match and admitted v2 HTML in PFD source-ow…
isomorphisms Oct 15, 2026
5bf806b
Document v2 HTML admission and generation requirements of private PFD…
isomorphisms Oct 15, 2026
4e7b839
Document generation-bound admitted v2 PFD source and refuse v1 on nat…
isomorphisms Oct 15, 2026
3e769cb
Reconcile stacked PFD draft with observed ICU/Arena v2 source while p…
isomorphisms Oct 15, 2026
f98ad77
Require independent AI-CI v2 Arena verdict before PFD host source tests
isomorphisms Oct 15, 2026
e8116f3
Require independent AI-CI v2 Arena verdict before PFD host source tests
isomorphisms Oct 15, 2026
d9f1895
Run separately pinned AI-CI admitted-source verifier in both PFD host…
isomorphisms Oct 15, 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
144 changes: 144 additions & 0 deletions .github/workflows/ib-c67-reader-pfd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
name: IB checked reader Binder PFD admission

on:
pull_request:
paths:
- 'native/android/ib_reader_pfd.c'
- 'native/android/ib_reader_pfd.h'
- 'native/android/ib_arena_pfd_provider.c'
- 'native/android/ib_arena_pfd_provider.h'
- 'native/android/ib_arena_source_owner.c'
- 'native/android/ib_arena_source_owner.h'
- 'native/android/ib_reader_host_assembly.c'
- 'native/android/ib_reader_host_assembly.h'
- 'tests/test_android_arena_source_owner.c'
- 'tests/test_android_arena_source_owner.sh'
- 'tests/test_android_arena_source_owner_synthetic.sh'
- 'tests/test_android_reader_pfd.c'
- '.github/workflows/ib-c67-reader-pfd.yml'
workflow_dispatch:

permissions:
contents: read

jobs:
pfd-host-fast:
runs-on: ubuntu-24.04
steps:
- name: Checkout candidate source
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Check out pinned independent AI-CI admitted-source verifier
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
repository: isomorphisms/ai-ci
ref: 634626a14834e14b776616440e0a9071708f81b7
path: .deps/ai-ci
persist-credentials: false
- name: Compile native receiver and fake-boundary source owner
run: |
set -eu
test "$(git -C .deps/ai-ci rev-parse HEAD)" = 634626a14834e14b776616440e0a9071708f81b7
sh .deps/ai-ci/ib-source/self-test.sh > build-source-self-test.txt
grep -F 'PASS: independent IB v2 oracle' build-source-self-test.txt
export IB_AICI_SOURCE_VERIFY="$GITHUB_WORKSPACE/.deps/ai-ci/ib-source/verify.sh"
mkdir -p build/c67-pfd/fast
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror -pthread \
native/android/ib_reader_pfd.c native/android/ib_arena_source_owner.c \
tests/test_android_arena_source_owner.c \
-o build/c67-pfd/fast/test-arena-pfd
env IB_TEST_VERIFIED_ARENA_PIPE="$GITHUB_WORKSPACE/build/c67-pfd/fast/test-arena-pfd" \
sh tests/test_android_arena_source_owner_synthetic.sh \
| tee build/c67-pfd/fast/receipt.txt
grep -F 'fixture' build/c67-pfd/fast/receipt.txt | grep -F 'synthetic-pointer-not-canonical-appendfat'
sha256sum build/c67-pfd/fast/test-arena-pfd > build/c67-pfd/fast/sha256.txt

pfd-source-admission:
runs-on: ubuntu-24.04
steps:
- name: Checkout pinned PR source
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Check out pinned independent AI-CI admitted-source verifier
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
repository: isomorphisms/ai-ci
ref: 634626a14834e14b776616440e0a9071708f81b7
path: .deps/ai-ci
persist-credentials: false
- name: Checkout immutable canonical appendfat Arena
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
repository: isomorphisms/sd-card-append-fat
ref: 05a0cb7246c5a9f46abfbe92925812e7b607f454
path: .deps/appendfat
persist-credentials: false
- name: Verify canonical Arena source pin
run: |
test "$(git -C .deps/appendfat rev-parse HEAD)" = 05a0cb7246c5a9f46abfbe92925812e7b607f454
- name: Host C11 two-process descriptor tests
run: |
set -eu
mkdir -p build/c67-pfd/host
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror \
native/android/ib_reader_pfd.c tests/test_android_reader_pfd.c \
-o build/c67-pfd/host/test-reader-pfd
./build/c67-pfd/host/test-reader-pfd | tee build/c67-pfd/host/receipt.txt
grep -F 'NOT_RUN: Android Binder service' build/c67-pfd/host/receipt.txt
sha256sum build/c67-pfd/host/test-reader-pfd \
> build/c67-pfd/host/sha256.txt
- id: ick
uses: isomorphisms/ai-ci/ick-host@015cc7901ae0b3ad262b476f24e129b53c56db95
- name: Read and serve actual canonical Arena bytes as a scoped pipe
env:
ICK: ${{ steps.ick.outputs.compiler }}
run: |
set -eu
test -x "$ICK"
test "$(git -C .deps/ai-ci rev-parse HEAD)" = 634626a14834e14b776616440e0a9071708f81b7
export IB_AICI_SOURCE_VERIFY="$GITHUB_WORKSPACE/.deps/ai-ci/ib-source/verify.sh"
"$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/c67-pfd/host/appendfat_arena
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror \
native/android/ib_arena_slice.c -o build/c67-pfd/host/ib-arena-slice
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -Werror -pthread \
native/android/ib_reader_pfd.c native/android/ib_arena_source_owner.c \
tests/test_android_arena_source_owner.c \
-o build/c67-pfd/host/test-arena-pfd
env IB_APPEND_ARENA="$GITHUB_WORKSPACE/build/c67-pfd/host/appendfat_arena" \
IB_ARENA_SLICE="$GITHUB_WORKSPACE/build/c67-pfd/host/ib-arena-slice" \
IB_TEST_VERIFIED_ARENA_PIPE="$GITHUB_WORKSPACE/build/c67-pfd/host/test-arena-pfd" \
sh tests/test_android_arena_source_owner.sh \
| tee build/c67-pfd/host/arena-source-receipt.txt
grep -F 'checked_arena=actual_appends' build/c67-pfd/host/arena-source-receipt.txt
sha256sum build/c67-pfd/host/test-arena-pfd \
> build/c67-pfd/host/arena-test-sha256.txt
- name: Cross-build real Android libbinder_ndk PFD reader on both ABIs
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/c67-pfd/$abi"
"$toolchain/$target-clang" -std=c11 -O2 -Wall -Wextra \
-Wpedantic -Werror -fPIC -shared native/android/ib_reader_pfd.c \
native/android/ib_arena_pfd_provider.c \
native/android/ib_arena_source_owner.c \
native/android/ib_reader_host_assembly.c \
-pthread -lbinder_ndk -o "build/c67-pfd/$abi/libib_reader_pfd.so"
"$toolchain/llvm-readelf" -h "build/c67-pfd/$abi/libib_reader_pfd.so" \
> "build/c67-pfd/$abi/elf.txt"
grep -F "Machine:" "build/c67-pfd/$abi/elf.txt" | grep -F "$machine"
sha256sum "build/c67-pfd/$abi/libib_reader_pfd.so" \
> "build/c67-pfd/$abi/sha256.txt"
printf 'abi\t%s\nandroid_link\tlibbinder_ndk\nphysical_device\tNOT_RUN\nidric_screen\tNOT_CONNECTED\n' \
"$abi" > "build/c67-pfd/$abi/receipt.tsv"
done
- name: Publish ABI artifacts, not an APK
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ib-c67-reader-pfd-native
path: build/c67-pfd/
if-no-files-found: error
139 changes: 139 additions & 0 deletions docs/c67-reader-pfd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# IB C67: private Binder/PFD reader handoff (bounded receiver)

**Status:** native Binder provider/receiver, verified Arena source-owner callback and app-host assembly, with hosted fixture tests. No phone APK.
This branch is stacked on IB PR #152, which stores checked ICU body bytes in
the existing userspace appendfat Arena. **No URL-capable APK, provider service,
Idriç screen connection, or physical C67 Binder execution is claimed.**

## Required connection

Idriç browser-owned navigation epoch + source identity
→ Shizuku-authorized ICU worker (no Android-reader HTTP)
→ exact captured bytes → checked appendfat Arena source
→ source-owner checks admitted v2 receipt + matching navigation epoch
→ independently reopens and hashes committed bytes
→ private app-scoped Binder provider: OPEN_COMMITTED_SOURCE(request,epoch)
→ one read-only, per-open ParcelFileDescriptor (not Arena file FD)
→ native reader verifies exact stream length + SHA-256 + epoch
→ source-linked extraction / Idriç Prepaint → existing native views

The eventual app-scoped source owner must first consume the **real** committed source using
bin/ib_android_arena_read.grease (which does not emit bytes until its
digest check passes). Materialize the verified bounded source into a
fresh **read-only anonymous pipe** whose descriptor, rather than a path, is transferred. A backing Arena file descriptor, writable descriptor or socket is refused.
Never hand out the appendfat Arena's descriptor or rely on a shared
/data/local/tmp response. Never give the reader a network client.

Private Binder implementation contract, transaction code **1**:

- Request parcel: validated UTF-8 request ID and signed 64-bit navigation
generation. A real provider authorizes Binder calling UID against an
explicit same-signer/allowed-reader identity before opening a source.
Missing/denied authorization returns a nonzero status and no descriptor.
- Reply parcel: int32 status **0**, source byte_count (int32), 64-character
lowercase source SHA-256, then a ParcelFileDescriptor with **only**
the already checked committed source's bytes. Provider closes its write
side after the declared byte count. A matching, admitted v2 receipt is necessary but does not
replace the browser's navigation authorization.
- Browser-held admission ticket: request ID, generation, byte count
(1–4194304) and lowercase SHA-256 copied from the previously checked
immutable source receipt, **never from untrusted page content**. The
ticket must be authenticated at the broker/reader boundary. The client
also rejects any length or SHA difference between its browser-held ticket
and the provider's receipt-derived reply metadata before accepting the FD.
For a
matching ticket, the receiver verifies the entire stream, checks for EOF,
and compares SHA-256 before replacing the last displayed source.
- A newer browser navigation updates the expected generation. Late results,
corrupt/replayed metadata, malformed IDs, extra/short input, over-limit
bodies, reader/provider death and stalled streams are refused. The
existing last-good snapshot remains owned by the reader.

native/android/ib_arena_pfd_provider.{h,c} implement a narrowly UID-gated
**serving** Binder object (the host supplies its verified-source callback).
The object must be handed privately to the checked reader by the app host:
no global Binder service registration is used here. The callback is now implemented in native/android/ib_arena_source_owner.{h,c}:
it opens the app's existing 0700 Arena root, reads an immutable source receipt,
checks canonical .used and locked range, independently rehashes the complete
body, and emits an anonymous read-only pipe from a bounded writer thread.
It never returns the Arena's file descriptor. Host assembly wiring in
native/android/ib_reader_host_assembly.{h,c} binds that callback to the
private Binder provider object. **The app lifecycle has not yet instantiated
this assembly, and no Binder reference has been delivered to the Idriç DEX.**

native/android/ib_reader_pfd.{h,c} implement the **receiving** C11
boundary. On Android API 29+ they use NDK Binder parcel transactions and
AParcel_readParcelFileDescriptor. The consumer does not discover a global
service, request Shizuku permission, decide URLs, parse HTML, or publish
history. It requires an already authorized provider Binder handle supplied
by the host adapter. This is compatible with Android 14/SDK 34 on A1/C67;
older Android API 28 is not yet supported by this native Binder adapter.

This is **not** a second canonical store. The C receiver holds one
replaceable in-memory candidate. The browser-owned committed source and
navigation journal continue to reside in existing IB/Cauldron/Arena.
Raw bytes remain binary until source verification and the existing Idriç
extraction/Prepaint decision. It is not correct to render raw HTML as if it
were already the semantic prepaint projection.

## Source and validation

test_android_reader_pfd.c uses two real Linux processes and transfers an
anonymous pipe descriptor via SCM_RIGHTS. This checks the exact native
consumer's binary fidelity, known SHA-256 vectors, good-source retention,
and fail-closed refusal on corruption, short/extra data, bad IDs,
over-limit tickets and stale navigation generations. **SCM_RIGHTS is a
host stand-in for descriptor ownership, not a claim of tested Android
Binder delivery or tested cross-UID Android authority.**

The second host test constructs a real pinned sd-card-append-fat Arena,
appends an admitted UTF-8 HTML fixture using its canonical append command,
publishes a complete v2 receipt and a legacy v1 refusal fixture, then drives the actual C source owner and reader
verifiers end-to-end. It mutates receipts, source bytes, commit pointer,
generation, root permissions and path identity, requiring refusal and
last-good preservation. This is still Linux-hosted source admission.

The independent Android CI lane cross-compiles actual NDK Binder calls,
source-owner assembly and pipe writer for ARM32 and ARM64 and retains digests. Cross-compilation does
**not** prove the provider exists, the Idriç DEX can call this library,
or that an Android Binder transaction has happened.

## Required next integration

1. Instantiate the newly connected native host assembly in the existing
Android application lifecycle, resolve the real reader UID from trusted
package identity and privately supply its Binder handle to the checked
Idriç DEX. The assembly cannot use root paths owned by Termux or shell:
add the separate authorized Shizuku-worker-to-app-private-Arena ingress
through scoped IPC. Shell UID 2000 cannot read the app's private Arena.
2. Bind the native C receiver to the **existing checked Idriç Material
reader** (#129/#147), with qualified DEX/native FFI and lifecycle.
Do not introduce Java/Kotlin application logic or a replacement UI.
3. The native source owner now requires v2 admission, observed HTTP status,
resolved URL, MIME, charset and a source-generation/epoch match.
IB #152 host tests passed, but real C67 ICU/TLS remains NOT_RUN.
Navigation ordering and link events remain owned by Idriç.
4. Device-check denied/missing Shizuku, private reader UID, real ICU
HTTPS, committed Arena and readback digest, actual Binder PFD
transaction, page presentation, copying text, replacement/restart
recovery and late/out-of-order completions on the physical C67.
Mark each absent test NOT_RUN.

Existing source owners: IB #151, #142, #141, #97; IB PR #112
(Binder-first host), #129/#147 (checked Android reader), #152
(ICU/Arena). ICU PR #35 owns real resolved-URL/redirect metadata.

## ICU #35 / IB #152 v2 admission invariant

Native PFD publication requires exactly 23 receipt fields, schema
`ib-icu-arena-v2`, `source_key=arena:REQUEST_ID`, source_generation
matching the requested epoch, observed HTTP 200, `text/html`, explicit
`utf-8` charset, identity content encoding, ICU UTF-8 validity,
`acquisition_complete=YES`, `reopen_check=MATCH` and
`navigation_admitted=YES`. Reopened canonical Arena body length and SHA-256
must match. v1 UNOBSERVED receipts are always refused by this native source
owner, including when their body digests are correct.

These changes are host candidates until exact-head CI and independent AI-CI
acceptance. The host fixture is not live ICU on C67; physical Shizuku,
cross-UID worker ingress, Binder/Idriç DEX registration and UI remain NOT_RUN.
Loading
Loading