cfw: iBoot: disable skywalk fsw netagents on iOS 18 (if_attach_nx=0x3)

iOS 18.6.2 userland on the 26.1 vphone600 kernel has no working DNS: the
guest gets a correct resolver config (DHCP hands out 192.168.64.1, which
configd propagates to State:/Network/Global/DNS) and the path works (raw
UDP DNS to the gateway succeeds), but getaddrinfo fails EAI_NONAME because
mDNSResponder crash-loops. Every crash is identical: EXC_BREAKPOINT in
os_channel_create_extended, hit from Network.framework flow setup
(nw_channel_create_with_attributes). That is a skywalk userspace-channel
trap: the 26.1 kernel advertises skywalk, Network.framework tries to create
a flowswitch channel for its DNS flow, the channel-create syscall trips a
fatal trap in the 18.6.2 libsystem_kernel, and the resolver daemon dies.
26.x userland handles this path; 18.6.2 does not.

Fix: set boot-arg if_attach_nx=0x3 (SKYWALK_NETWORKING_BSD_ONLY =
IF_ATTACH_NX_NETIF_COMPAT | IF_ATTACH_NX_FLOWSWITCH) on iOS 18 bases. This
keeps the netif + flowswitch nexus (interface/host stack unaffected) but
leaves the FSW_TRANSPORT/IP netagents unset, so Network.framework uses the
BSD-socket path and mDNSResponder never creates the crashing channel. The
kernel boot-args come from the patched iBoot (kern.bootargs matches
IBootPatcher.bootArgs), so the arg is baked into the iBEC/LLB boot-args
patch, not the host NVRAM (which iBoot overrides).

- IBootPatcher gains `extraBootArgs`, inserted before the trailing %s in
  the patched boot-args string (ibec/llb).
- FirmwarePipeline sets extraBootArgs="if_attach_nx=0x3" for iOS 18 bases
  (iosBaseIs18), empty otherwise, on the iBEC and LLB factories.

Gated to iOS 18 bases: 26.x keeps the stock boot-args and is untouched.
Validated at runtime first (setting net.link.generic.system.enable_netagent
=0 makes DNS resolve reliably), then confirmed end-to-end on a fresh
17,3_18.6.2_22G100 jb restore: kern.bootargs shows if_attach_nx=0x3 and
DNS/networking works.

Documented in research/0_binary_patch_comparison.md (iBEC/LLB boot-args row).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q7gbWrtKLu8rFGmpXHmu9t
This commit is contained in:
zqxwce
2026-07-13 15:40:44 +03:00
committed by zqxwce
co-authored by Claude Opus 4.8
parent b90f699583
commit 8781e20c76
3 changed files with 31 additions and 5 deletions
+2 -2
View File
@@ -65,7 +65,7 @@
| --- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------ | :-----: | :-: | :-: |
| 1 | Serial labels (2x) | "Loaded iBEC" in serial log | Y | Y | Y |
| 2 | `image4_validate_property_callback` | Signature bypass | Y | Y | Y |
| 3 | Boot-args redirect | ADRP+ADD -> `serial=3 -v debug=0x2014e %s` | Y | Y | Y |
| 3 | Boot-args redirect | ADRP+ADD -> `serial=3 -v debug=0x2014e %s`; iOS 18 base adds `if_attach_nx=0x3` (skywalk BSD_ONLY: disables fsw netagents so Network.framework uses BSD sockets, fixes mDNSResponder skywalk-channel crash-loop / DNS) | Y | Y | Y |
| 4 | Modern bootx-handoff panic bypass | `IBootPatcher.patchBootxPrecondition` NOPs gate TBZ via structural anchor (no hash/line tied); no-op pre-26.4 | Y | Y | Y |
| 5 | Ramdisk boot-args overwrite | `ramdisk_build.py:patch_ibec_bootargs` rewrites string to `... rd=md0 ... wdt=-1 ...` (ramdisk-send iBEC only) | Y | Y | Y |
@@ -75,7 +75,7 @@
| --- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------ | :-----: | :-: | :-: |
| 1 | Serial labels (2x) | "Loaded LLB" in serial log | Y | Y | Y |
| 2 | `image4_validate_property_callback` | Signature bypass | Y | Y | Y |
| 3 | Boot-args redirect | ADRP+ADD -> `serial=3 -v debug=0x2014e %s` | Y | Y | Y |
| 3 | Boot-args redirect | ADRP+ADD -> `serial=3 -v debug=0x2014e %s`; iOS 18 base adds `if_attach_nx=0x3` (skywalk BSD_ONLY: disables fsw netagents so Network.framework uses BSD sockets, fixes mDNSResponder skywalk-channel crash-loop / DNS) | Y | Y | Y |
| 4 | Rootfs bypass (5 patches) | Allow edited rootfs loading | Y | Y | Y |
| 5 | Panic bypass | NOP `cbnz` after `mov w8,#0x328` check | Y | Y | Y |
@@ -35,6 +35,14 @@ public class IBootPatcher: Patcher {
public let component: String
public let verbose: Bool
/// Extra boot-args token(s) inserted before the trailing `%s` in the
/// patched boot-args (ibec/llb). Used to add `if_attach_nx=0x3` on iOS 18
/// bases (disables the skywalk flowswitch netagents so Network.framework
/// uses the BSD path; the 26.1-kernel skywalk channel-create traps in the
/// 18.x Network.framework and crash-loops mDNSResponder no DNS). Empty
/// by default, so 26.x bases keep the stock boot-args.
public var extraBootArgs: String = ""
let buffer: BinaryBuffer
let mode: Mode
let disasm = ARM64Disassembler()
@@ -305,9 +313,17 @@ public class IBootPatcher: Patcher {
// MARK: - 3. Boot-Args (iBEC / LLB)
/// Effective boot-args string, with any `extraBootArgs` inserted before `%s`.
private var effectiveBootArgs: String {
extraBootArgs.isEmpty
? IBootPatcher.bootArgs
: "serial=3 -v debug=0x2014e \(extraBootArgs) %s"
}
/// Redirect ADRP+ADD x2 to a custom boot-args string.
/// Python: `patch_boot_args()`
func patchBootArgs(newArgs: String = IBootPatcher.bootArgs) {
func patchBootArgs(newArgs: String? = nil) {
let newArgs = newArgs ?? effectiveBootArgs
guard let newArgsData = newArgs.data(using: .ascii) else { return }
guard let fmtOff = findBootArgsFmt() else {
@@ -196,6 +196,12 @@ public final class FirmwarePipeline {
// capturing self). True only for iOS 18 bases; gates the EXC_GUARD patch.
let applyExcGuard = iosBaseIs18
// iOS 18 bases: disable the skywalk flowswitch netagents via boot-arg so
// Network.framework uses the BSD path (the 26.1-kernel skywalk
// channel-create traps in the 18.x Network.framework and crash-loops
// mDNSResponder no DNS). Empty on 26.x bases (stock boot-args).
let extraBootArgs = iosBaseIs18 ? "if_attach_nx=0x3" : ""
// 1. AVPBooter always present, lives in VM root.
// Patched for every non-less variant (regular/dev/jb/exp).
components.append(ComponentDescriptor(
@@ -246,7 +252,9 @@ public final class FirmwarePipeline {
inRestoreDir: true,
searchPatterns: ["Firmware/dfu/iBEC.vresearch101.RELEASE.im4p"],
patcherFactories: [{ data, verbose in
IBootPatcher(data: data, mode: .ibec, verbose: verbose)
let p = IBootPatcher(data: data, mode: .ibec, verbose: verbose)
p.extraBootArgs = extraBootArgs
return p
}]
))
@@ -256,7 +264,9 @@ public final class FirmwarePipeline {
inRestoreDir: true,
searchPatterns: ["Firmware/all_flash/LLB.vresearch101.RELEASE.im4p"],
patcherFactories: [{ data, verbose in
IBootPatcher(data: data, mode: .llb, verbose: verbose)
let p = IBootPatcher(data: data, mode: .llb, verbose: verbose)
p.extraBootArgs = extraBootArgs
return p
}]
))