Force-allow the ADB shell at boot (fix module-flash permission denied) + v3.3.0#62
Conversation
…nied The offline installer now plants a Magisk service.d script (00-bsrgui-adbgrant.sh) that runs as root at every boot and sets a permanent "allow" Superuser policy for the shell uid (2000). This fixes the "permission denied" seen when flashing ReZygisk/LSPosed over ADB: Magisk prompts for su, and if the prompt isn't tapped in time it auto-DENIES and caches that deny across reboots, permanently locking out ADB module installs. The shell can't set this policy itself (it needs the very su it's being denied), so the grant is planted offline via debugfs during stage_databin and executed by magiskd at late_start. Scoped to the shell uid only -- apps still prompt as normal. Verified live on Android 13: a fresh install grants the shell from first boot with no manager and no tap, and a missed prompt can no longer lock it out. - magisk_system: _service_d_grant_commands + _grant_script_tempfile, wired into stage_databin (verified + rolled back with the DATABIN) and removed on unstage; creates /data/adb/service.d on a fresh instance. - adb_handler: _ensure_su_policy demoted to a silent re-affirm; the flash message no longer tells the user to tap Grant. - Version -> 3.3.0.
There was a problem hiding this comment.
Code Review
This pull request introduces an offline Magisk service.d script (00-bsrgui-adbgrant.sh) to automatically grant root permissions to the ADB shell (UID 2000) at boot, preventing auto-denial issues during module flashing. This includes staging, unstaging, and verification logic in magisk_system.py, corresponding updates in adb_handler.py, and new unit tests. One high-severity issue was identified where staging could fail on fresh instances because the parent /adb directory does not exist and debugfs's mkdir is not recursive; a code suggestion was provided to resolve this.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| svc_exists = "Inode:" in _es._stat_path(dev, _SERVICE_D, env) | ||
| script = (_clean_dir_commands(dev, _DATABIN, env) | ||
| + _write_commands(tools) + _databin_extra_commands(extras) | ||
| + _service_d_grant_commands(grant_script, svc_exists)) |
There was a problem hiding this comment.
On a fresh or newly cloned BlueStacks instance, the /data/adb directory (which maps to /adb in the ext4 filesystem of Data.vhdx) does not exist by default. If /adb is missing, both mkdir /adb/magisk (in _write_commands) and mkdir /adb/service.d (in _service_d_grant_commands) will fail because debugfs's mkdir is not recursive (it does not behave like mkdir -p).
To prevent staging failures on fresh instances, we should check if /adb exists and create it first if it is missing.
adb_exists = "Inode:" in _es._stat_path(dev, "/adb", env)
adb_cmds = []
if not adb_exists:
adb_cmds = ["mkdir /adb", "sif /adb mode 040700",
"sif /adb uid 0", "sif /adb gid 0",
"ea_set /adb security.selinux %s" % _SELINUX_CTX]
svc_exists = adb_exists and "Inode:" in _es._stat_path(dev, _SERVICE_D, env)
script = (adb_cmds
+ _clean_dir_commands(dev, _DATABIN, env)
+ _write_commands(tools) + _databin_extra_commands(extras)
+ _service_d_grant_commands(grant_script, svc_exists))
What
Fixes the "permission denied" failure when flashing modules (ReZygisk / LSPosed) over ADB, and cuts v3.3.0.
Why it was happening
Magisk prompts for
suon the first ADB module flash. If the prompt isn't tapped in time, magiskd auto-denies and caches that deny in thepoliciestable — and the deny persists across cold boots (confirmed live). The previous online pre-grant couldn't help: it wrote the allow-policy throughsu, which is exactly what was being denied (chicken-and-egg).The fix
The offline installer now plants a Magisk
service.dscript (00-bsrgui-adbgrant.sh) that runs as root at every boot and sets a permanent allow policy for the shell uid (2000). The shell can't set this itself; magiskd'sservice.dcan. Scoped to the shell uid — apps still prompt normally.magisk_system:_service_d_grant_commands+_grant_script_tempfile, wired intostage_databin(verified + rolled back with the DATABIN), removed on unstage, and creates/data/adb/service.don a fresh instance.adb_handler:_ensure_su_policyis now a silent belt-and-suspenders re-affirm; the flash message no longer tells the user to tap Grant.Verified live (Android 13)
A fresh install grants the shell from first boot — no manager, no tap, ReZygisk flashes over ADB with no prompt, and a missed prompt can no longer lock ADB module installs out.
179 tests pass (+3).