From fa9adcf3b5efb0f11a1ff185a59494fdd3b12025 Mon Sep 17 00:00:00 2001 From: ThePedroo Date: Sun, 22 Jun 2025 18:33:10 -0300 Subject: [PATCH] fix: `FORCE_DENYLIST_UNMOUNT` not forcing umount This commit fixes the issue where because the mount namespace switch happened only before the Zygisk modules execution, they wouldn't have the opportunity to set "FORCE_DENYLIST_UNMOUNT" flag. Now, with this commit, which added another check to know if that flag was set by a Zygisk module, and if so, switched to mount namespace, adjusts the behavior to the expected one. --- loader/src/injector/hook.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/loader/src/injector/hook.cpp b/loader/src/injector/hook.cpp index 7b3b868..ccdc688 100644 --- a/loader/src/injector/hook.cpp +++ b/loader/src/injector/hook.cpp @@ -753,21 +753,40 @@ void ZygiskContext::app_specialize_pre() { } /* INFO: Modules only have two "start off" points from Zygisk, preSpecialize and - postSpecialize. While preSpecialie in fact runs with Zygote (not superuser) - privileges, in postSpecialize it will now be with lower permission, in - the app's sandbox and therefore can move to a clean mount namespace after - executing the modules preSpecialize. - */ - if ((info_flags & PROCESS_ON_DENYLIST) == PROCESS_ON_DENYLIST) { - flags[DO_REVERT_UNMOUNT] = true; + postSpecialize. In preSpecialize, the process still has privileged + permissions, and therefore can execute mount/umount/setns functions. + If we update the mount namespace AFTER executing them, any mounts made + will be lost, and the process will not have access to them anymore. - update_mnt_ns(Clean, false); + In postSpecialize, while still could have its mounts modified with the + assistance of a Zygisk companion, it will already have the mount + namespace switched by then, so there won't be issues. + + Knowing this, we update the mns before execution, so that they can still + make changes to mounts in DenyListed processes without being reverted. + */ + bool in_denylist = (info_flags & PROCESS_ON_DENYLIST) == PROCESS_ON_DENYLIST; + if (in_denylist) { + flags[DO_REVERT_UNMOUNT] = true; + + update_mnt_ns(Clean, false); } /* INFO: Executed after setns to ensure a module can update the mounts of an application without worrying about it being overwritten by setns. */ run_modules_pre(); + + /* INFO: The modules may request that although the process is NOT in + the DenyList, it has its mount namespace switched to the clean + one. + + So to ensure this behavior happens, we must also check after the + modules are loaded and executed, so that the modules can have + the chance to request it. + */ + if (!in_denylist && flags[DO_REVERT_UNMOUNT]) + update_mnt_ns(Clean, false); } }