Skip to content

iOS 27: Sileo and the rootless prefix as a full-root step (60-sileo), REV 2 after phone runs - #300

Draft
claudiusthebot wants to merge 6 commits into
mainfrom
s9/sileo-ios27
Draft

claudiusthebot wants to merge 6 commits into
mainfrom
s9/sileo-ios27

Conversation

@claudiusthebot

Copy link
Copy Markdown
Collaborator

Sileo and the Procursus rootless prefix (/var/jb) as a step of the iOS 27 full root (tools/ios27/fullroot/steps.d/60-sileo.sh), with jb_seed/var_sync from the 16.5 line, launchd jobs, a self-test for test roots, and docs/ios27/SILEO.md.

Commits: 6cdb31a (jb_seed owners), 5383a81 (the step), f8d797f (REV 2, after the first boots on a phone).

What ran on a phone (Galaxy S9 "phone 1", iOS 27 full root, 13 Nov 2026), applied to the phone's live root by hand with the same edits:

  • REV 1: seeding, owners, no password, no OpenSSH all fine; but apt-get update hung and the UI froze a few minutes after boot. Cause: apt's methods run as _apt (uid 1001), unknown to iOS's /etc/passwd; the system cfprefsd crashes (CFEqual on NULL) on such a client, restarts every 10 s, and every root CFPreferences client waits for ever (apt, uicache, then SpringBoard's pasteboard call). REV 2 sets APT::Sandbox::User "root" in the prefix. No crash in the boots since.
  • uicache -p cannot register anything on this port (also /Applications/*.app); lsd's boot-time rebuild registers /Applications. REV 2 copies Sileo.app there, drops the LS databases, and prep.sh keeps the copy root-owned with giveMeRoot 4755.
  • With REV 2: apt installs/removes/reinstalls from an on-phone repository; packages kept across reboots; Sileo icon on the home screen, Sileo opens, lists installed packages, refreshes sources (no network on this port: Procursus "offline").

Not yet proven: install from Sileo's own interface; a network source (no Wi-Fi); apps brought by packages (installed but not registered, needs uicache fixed).

Checked offline on a clone of the phone's root: apply, idempotent second run, undo.

Draft: do not merge before an RC root build has run it.

🤖 Generated with Claude Code

…ge has

jb_seed copied /jb to /private/var/jb with each file's owner as the image had it. That is right for an image made
as root. An image made or edited without root (a mount without owners on the builder's machine, which is how a root
that is already on a phone gets one more step) carries the builder's user ID on its files, or 99, which the kernel
shows to every process as that process's own. The copy would then be a prefix whose programs any app could rewrite,
with a giveMeRoot whose set-user-ID bit names nobody.

Everything in the Procursus bootstrap and in Sileo's package is root:wheel except var/mobile, which for_mobile()
sets after the copy. So the copy is now made root:wheel outright; on an image built as root nothing changes.

claim(), new: the few files an iOS 27 root carries for the prefix outside it (this program, var_sync, the five
links in /bin, a test root's self-test script) and the image's /jb are made root's if they are not, before anything
else. A fixed list; a name in /bin only if it is a link into the prefix. On a root built as root it touches nothing.
…root (60-sileo, on by default)

The iOS 27 root had no package manager: tools/ios27/fullroot had no step for it, so a full root had no /var/jb, no
Sileo and nothing in /bin but df and ps. The 16.5 line has had it by default (tools/mk-jb.sh, jb_seed).

steps.d/60-sileo.sh ROOT [undo] puts the prefix on the root the way 16.5 does on a kept volume: the Procursus
bootstrap with Sileo in it as /jb, copied to /private/var/jb by jb_seed at the first boot and left alone afterwards;
var_sync flushing the volume every 5 s (the phone is reset, never shut down); the five names in /bin Sileo runs; two
launchd jobs, as entries of /System/Library/xpc/launchd.plist, which is where iOS's launchd reads its jobs from
(tools/ios27/sileo/jobs.py). Both programs are the 16.5 line's sources built for iOS (build-tools.sh).

The prefix is the plain one (prepare.sh: PREINSTALL= ELLEKIT= tools/mk-jb.sh, both downloads pinned by SHA-256) and
the step stops the build if it is anything else: no OpenSSH, no tweak injection, Procursus as the only repository
(the project's own when SCION_REPO_URL says where it is hosted), no file writable by everybody, every Mach-O plain
arm64, the set-ID programs exactly the bootstrap's seven and Sileo's helper. Two things of the bootstrap as shipped
are changed on the way: mobile's password hash becomes "!" (no account has a password), and usr/sbin/shshd with its
job, which mk-jb.sh takes out of dpkg's database but leaves on the disk, is deleted. mk-jb.sh itself is not touched:
its checksum is the stamp of every 16.5 phone's prefix, and a change there would seed them all again.

undo takes the step off again; launchd.plist comes back identical (checked on a clone of a full root image, with a
second run, check-root.sh's new checks and fsck_hfs). prepare-root-inputs.sh calls prepare.sh; ENABLE_SILEO=0 builds
a root without it.

selftest.sh (SILEO_SELFTEST=1, a test root only): the port has no shell, so a third job says into a file at every
boot what the prefix is: owners, modes, dpkg's database, Sileo registered, a kept file with a line per boot, and with
a repository on the phone an install, run, remove and install again through apt-get.

docs/ios27/SILEO.md: the step, keeping, apps, and what "secure user data" is and is not on this port today (no
encryption at rest, no passcode, no sandbox: Unix owners and modes are what holds), with credits to Procursus, the
Sileo Team and Anan Jaser's kept-volume work on 16.5.

Not yet run on a phone.
…rom /Applications

What phone 1 showed on its first boots with REV 1 (13 Nov 2026):

- Procursus' apt runs its download methods as _apt (uid 1001), a uid iOS's own /etc/passwd does not have. The system
  cfprefsd crashes (CFEqual on NULL) on the first preferences request of a client it cannot name; the method retries,
  launchd restarts cfprefsd every ten seconds, and every root process that reads a preference waits for ever:
  apt-get update hung at its first file, uicache with it, then SpringBoard's pasteboard call and the interface.
  The prefix now gets etc/apt/apt.conf.d/00scion-sandbox (APT::Sandbox::User "root"). No crash since.
- uicache -p answers "Unable to register" for every path (also /Applications/*.app) and uicache -l lists nothing,
  while lsd's own rebuild at boot registers /Applications. The step puts a real copy of Sileo.app there (marked
  .scion-prefix-app), drops the LaunchServices databases so lsd rebuilds them, and prep.sh makes such copies root's
  (giveMeRoot 4755) at every boot. Undo takes the copy off again.

REV 1 -> 2: phones seeded with REV 1 seed again (the old copy is moved aside).
selftest.sh: no awk in the plain bootstrap (grep/cut), Sileo checked by its /Applications copy and giveMeRoot's owner.
docs/ios27/SILEO.md and the README's status table say what ran on the phone and what did not.

Checked on a clone of phone 1's root on the Mac: apply, a second run without change, undo (jobs and copy gone).
…-sync from prep.sh and a diverted uicache)

On this port LaunchServices refuses uicache's registration of every bundle ("Unable to register"), while
lsd's own rebuild registers what is in /Applications (13 Nov 2026, phone 1: that is how Sileo got its icon).
tools/ios27/sileo/scion-apps-sync.sh, installed as /var/jb/usr/libexec/scion-apps-sync, gives every
/var/jb/Applications/X.app a real copy in /Applications (marked .scion-prefix-app, root's, nothing writable
by others, giveMeRoot set-user-ID), makes it again when it differs from the prefix's, removes marked copies
whose package is gone, and when anything changed drops the LaunchServices databases and restarts lsd. iOS's
own applications (no mark) are never touched. prep.sh (every boot, root) runs it and, once, diverts uicache
(dpkg-divert, so a uikittools upgrade keeps it) to a wrapper that runs it first, so an app installed from
Sileo or apt is synced by its package's own uicache trigger. tools/ios27/sileo/prep-apps.py adds both to a
prefix; 60-sileo.sh calls it on the image's /jb.
@claudiusthebot

Copy link
Copy Markdown
Collaborator Author

New: 96c9d91, app icons for package-installed apps.

LaunchServices refuses uicache's registration of any bundle on this port. Instead, scion-apps-sync copies every /var/jb/Applications/X.app into /Applications:

  • the copy is marked, owned by root, and refreshed when it differs from the original;
  • it is removed when its package is gone;
  • after a change, the LaunchServices databases are dropped and lsd is restarted.

It runs from prep.sh at every boot, and from a dpkg-diverted uicache wrapper (the trigger every app package runs).

Phone 1, 13 Nov 2026: com.scion.app.puzzles (installed earlier by apt) got its home-screen icon after one reboot, and launching it execs the app. The app itself then stops with SIGTRAP, an app problem not looked into.

Sileo Confirm, root cause found:

  • Sileo 2.5.1 on iOS 13 and later runs apt-get through posix_spawn into persona 99, uid 0. This kernel has no personas, so the spawn fails with ESRCH and Sileo returns silently.
  • Kernel fix: persona_lax=1, Scion-Project/xnu vgpu3d: 1024 resources per open #21. It is booted on phone 1 but not yet exercised: in the runs so far the install never reached the spawn.
  • Sileo's own refresh over Wi-Fi works (1,273 Procursus packages listed). Queue and Confirm work, and its apt simulate as mobile is clean.
  • After Confirm the .deb download never completes: no file is written and nothing is exec'd. One suspect is the repo showing as "Untitled Repo", i.e. no Release in sileolists. Next step is a Sileo debug build or lldb on the download delegate.
  • Also: Sileo's "status 522" is Evander's code for a non-HTTP response. file: repos can never work in Sileo.

🤖 Generated with Claude Code

…s); firmware's packages get empty sums

mk-jb.sh unpacks Sileo (and ElleKit) by hand and writes only their status entries. dpkg then warns "files list
file for package 'org.coolstar.sileo' missing" at every run and 'dpkg --audit' names it broken; on phone 1
(13 Nov) the audit printed 172 lines: Sileo without a list, and the 165 packages usr/libexec/firmware makes
(firmware, cy+*, gsc.*), whose lists name no file, without sums files.

tools/ios27/sileo/dpkg-info.py DEB ADMINDIR writes info/PKG.{list,md5sums} and the maintainer scripts from the
package itself (checking every file is in the tree); prep.sh gives a list that names no file an empty sums file.
Run here with PREINSTALL=: Sileo 337 paths, 283 files; ElleKit 31 paths, 6 files.
…OS 27 SDK, dpkg audit, Sileo's lists are apt's)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant