Skip to content

Name the sepolicy access that is missing, not just that one is - #1065

Closed
JingMatrix wants to merge 1 commit into
masterfrom
fix/sepolicy-probes
Closed

JingMatrix wants to merge 1 commit into
masterfrom
fix/sepolicy-probes

Conversation

@JingMatrix

@JingMatrix JingMatrix commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

isSepolicyLoaded probed one access out of the eighteen statements in sepolicy.rule: whether dex2oat may execute dex2oat_exec, the first line of the file. The manager drew one row from it, SELinux policy: Not loaded, and that was the whole of what a reader could learn — while the access the injection actually hangs on is the last line.

A partly applied policy is an ordinary state rather than a corrupt one: the root solution applies that file, and some apply it a statement at a time and carry on past each one they reject. #1053 and #1056 both report that state — a daemon running, vector-cli status answering, SELinux policy: Not loaded and System framework: Not injected — and #1053 quotes KernelSU: sepol: cmd #4 failed, cmd=1 subcmd=1 and cmd #17 failed from its kernel log as the evidence.

Those two are not ours, which is the argument for this change rather than against it. The bugreport attached to #1053 has the lines the kernel writes immediately before each failure: target type magisk does not exist for #4 and target type nsfs does not exist for #17, in a batch that also reports Type magisk_file already exists and Type unshare_lock_file already exists — Zygisk Next's policy, not Vector's. Vector's own batch is the one just before it, and it was accepted: Type xposed_file already exists, Type xposed_data already exists, no failure. So on that device the file applied, two kernel lines about another module's rules were read as being about ours, and nothing anywhere could settle it — which is what one boolean over eighteen statements costs. I had read them the same way before downloading the attachment.

The access the injection actually hangs on is system_server's service_manager find on default_android_service, the rule #1034 added for the name a late-loaded daemon waits under. Without it the module inside system_server cannot look that name up, and what a reader sees is everything on the daemon side healthy, nothing injected, and the first probe still green. That is the shape of both reports, and it is unfalsifiable today.

So the probe is a list — the rendezvous lookup, the dex2oat wrapper, dex2oat reading xposed_file, system_server reading xposed_data — each spelled as the four arguments of checkSELinuxAccess so that what the log names is what a reader can check. Each also stands for the statements it needs as well as its own: a probe against xposed_file answers false when the type that declares it never landed either. The manager keeps its single row, which is all it can honestly offer, since none of these is separately actionable and what to do about any of them is the same thing; the log is where the answer stops being a single bit, written once per distinct answer so a status refresh does not repeat itself.

Also here: the one access AOSP grants rather than this file, system_server self:process execmem, is named in full where getModulesForSystemServer refuses to inject without it. That refusal ends in an empty module set and a system server that looks injected, and the message was sepolicy execmem denied, which says neither which domain was refused nor what wanted it. #1061 was read under that ambiguity: its reporter added system_server execmem rules on the strength of it.

Left alone: sepolicy.rule itself, which the attachment shows applying cleanly, and applying any policy from the daemon. It runs as root and could, and that is a larger decision than a diagnostic.

#1053 also reports its KernelSU module action opening com.android.shell/.BugreportWarningActivity. That is downstream of the same failure — action.sh launches the host activity on purpose and depends on the redirection hook inside system_server — and #1005 already carries the fix for the case where the manager is installed as an ordinary package, which that reporter had done.

This does not fix either issue, and should not close them. #1053's attachment points at a report we already have. Vector injected on its last captured boot — Got system server binder via serial on attempt 1, Injected Vector framework into system_server — and the same logs show two daemons alive at once: pid 6181 still looping on activity after a system_server death while 14401 ran VectorDaemon.main, with 6181 the one that completed sendToBridge and 14401 the one that last claimed serial. A third generation started at 10:17. That device runs 3114, which is eaffc816 — two commits before 5690481 took the daemon's lock back from R8, so nothing turned the second one away. Everything else that report describes sits downstream of that split, so the thing to ask for is a 3116 retest rather than another diagnosis.

Not tested on a device. The four probes are read off the rule file rather than observed passing on hardware, which is the thing to check before this is merged: a probe denied on a healthy install would turn the status row red for everyone. #1053's kernel log is one data point in favour — xposed_file and xposed_data both exist there.

`isSepolicyLoaded` probed one access of the eighteen statements in
`zygisk/module/sepolicy.rule`: whether `dex2oat` may execute
`dex2oat_exec`. The manager drew one row from it, "SELinux policy: not
loaded", and that was the whole of what a reader could learn — while the
access the first probe happens to name is not the one injection depends
on.

A partly applied policy is an ordinary state rather than a corrupt one.
The root solution applies that file, and some apply it a statement at a
time and carry on past each one they reject: KernelSU writes `sepol: cmd
#N failed` to the kernel log for each, and an LKM loaded after boot may
never reach the stage that applies it at all. The one access the whole
injection hangs on is `system_server`'s `service_manager find` on
`default_android_service` — without it the module inside system_server
cannot look up the name the daemon is waiting under, and the result is a
daemon running, a CLI answering, and `system framework: not injected`
with the first probe still green.

So the probe is a list: the rendezvous lookup, the dex2oat wrapper,
`dex2oat` reading `xposed_file` and `system_server` reading
`xposed_data`. Each stands for the statements it needs as well as its
own, since a probe against `xposed_file` answers false when the `type`
that declares it never landed either. The manager keeps its single row,
which is all it can honestly offer — none of these is separately
actionable by a user — and every denied access is written to the log by
name, with what stops working without it, once per distinct answer so
that a status refresh does not repeat itself.

Also here: the one access AOSP grants rather than this file,
`system_server self:process execmem`, is named in full where
`getModulesForSystemServer` refuses to inject without it. That path ends
in an empty module set and a system server that looks injected, and the
message was "sepolicy execmem denied", which says neither which domain
was refused nor what wanted it.

Refs #1053, #1056
@JingMatrix

Copy link
Copy Markdown
Owner Author

Low quality PR, built by AI.

@JingMatrix JingMatrix closed this Nov 5, 2026
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