docs: C24 kcall10 analysis — chained fixup pointer mismatch identified

Sysent table uses arm64e chained fixup pointers but patcher writes raw VAs.
Also missing _munge_wwwwwwww and potential PAC issues with BLR X16.
This commit is contained in:
Lakr
2026-03-04 20:59:27 +08:00
parent 5655fd78d7
commit 254a70d210
+78 -9
View File
@@ -1,5 +1,7 @@
# C24 `patch_kcall10`
## Status: NOT_BOOT (timeout, no panic)
## How the patch works
- Source: `scripts/patchers/kernel_jb_patch_kcall10.py`.
- Locator strategy:
@@ -13,16 +15,83 @@
- `sy_munge32` -> `_munge_wwwwwwww` (if resolved)
- return type + arg metadata.
## Patcher output
```
_nosys found
sysent table at file offset 0x73E078
Shellcode at file offset 0x00AB1720 (VA 0xFFFFFE0007AB5720)
sysent[439] at file offset 0x007409A0 (VA 0xFFFFFE00077449A0)
35 patches emitted (32 shellcode + 3 sysent fields)
Note: _munge_wwwwwwww NOT found — sy_munge32 field not patched
```
## Root cause analysis (in progress)
### Primary suspect: chained fixup pointer format mismatch
The sysent table lives in a DATA segment. On arm64e kernelcaches, DATA segment
pointers use **chained fixup encoding**, not raw virtual addresses:
- **Auth rebase** (bit63=1): `file_offset = bits[31:0]`, plus diversity/key metadata
- **Non-auth rebase** (bit63=0): `VA = (bits[50:43] << 56) | bits[42:0]`
The patcher writes `struct.pack("<Q", cave_va)` — a raw 8-byte VA — to `sysent[439].sy_call`.
This is **not valid chained fixup format**. The kernel's pointer fixup chain will either:
1. Misinterpret the raw VA as a chained pointer and decode it to a wrong address
2. Break the fixup chain, corrupting subsequent sysent entries
3. The pointer simply won't be resolved, leaving a garbage function pointer
This explains the NOT_BOOT (timeout) behavior — no panic because the corrupted
pointer is never dereferenced during early boot (syscall 439 is not called during
init), but the fixup chain corruption may silently break other syscall entries,
preventing the system from booting properly.
### Fix approach (TODO)
1. **Read raw bytes at sysent[0] and sysent[439]** via IDA MCP to confirm the
chained fixup pointer format (auth vs non-auth rebase)
2. **Implement `_encode_chained_ptr()`** that produces the correct encoding:
- For auth rebase: set bit63=1, encode file offset in bits[31:0], set
appropriate key/diversity fields
- For non-auth rebase: encode VA with high8 bits in [50:43] and low43 in [42:0]
3. **Use encoded pointer** when writing `sy_call` and `sy_munge32`
4. **Verify the fixup chain** — sysent entries may be part of a linked chain
where each entry's `next` field points to the next pointer to fix up.
Breaking this chain corrupts all subsequent entries.
### Secondary concerns
- **Missing `_munge_wwwwwwww`**: The symbol wasn't found. Without the correct
munge function, the kernel may not properly marshal syscall arguments from
userspace. This may cause a panic when the syscall is actually invoked.
- **Code cave in __TEXT_EXEC**: The shellcode is placed at 0xAB1720 in __TEXT_EXEC.
Need to verify this region is executable at runtime (KTRR/CTRR may lock it).
- **BLR x16 in shellcode**: The shellcode uses `BLR X16` (raw encoding
`0xD63F0200`). On PAC-enabled kernels, this may need to be `BLRAAZ X16` or
similar authenticated branch to avoid PAC traps.
### Sysent table structure
```
struct sysent {
sy_call_t *sy_call; // +0: function pointer (8 bytes)
munge_t *sy_arg_munge32; // +8: argument munge function (8 bytes)
int32_t sy_return_type; // +16: return type (4 bytes)
int16_t sy_narg; // +20: number of arguments (2 bytes)
uint16_t sy_arg_bytes; // +22: argument byte count (2 bytes)
}; // total: 24 bytes per entry
```
### Key addresses
- sysent table: file 0x73E078, VA 0xFFFFFE0007742078
- sysent[439]: file 0x7409A0, VA 0xFFFFFE00077449A0
- Code cave: file 0xAB1720, VA 0xFFFFFE0007AB5720
- _nosys: found by pattern match
## Expected outcome
- Replace syscall 439 handler with arbitrary 10-arg kernel call trampoline behavior.
## Target
- `sysent[439]` table entry and cave shellcode block.
## IDA MCP evidence
- Pattern `mov w0,#0x4e; ret` appears in multiple tiny stubs (expected in this build).
- One strong candidate family is around `0xfffffe00084b5d3c` (tiny nosys-like stub with many data refs), consistent with table-dispatch use.
- This matches patch design that depends on data-table discovery rather than direct named symbol.
## Risk
- Syscall table rewrite is extremely invasive; wrong table/entry decode can hard panic the kernel.
- Syscall table rewrite is extremely invasive; wrong pointer encoding breaks
the fixup chain and can silently corrupt many syscall handlers.
- BLR without PAC authentication may cause kernel traps.