if (access("/system/bin/init", F_OK) == 0) { // On 2SI devices, the 2nd stage init file is always a dynamic executable. dump_preload("/dev/preload.so", 0644); setenv("LD_PRELOAD", "/dev/preload.so", 1); }
// Hijack the "load" and "enforce" node in selinuxfs to manipulate // the actual sepolicy being loaded into the kernel auto hijack = [&] { LOGD("Hijack [" SELINUX_LOAD "]\n"); close(xopen(MOCK_LOAD, O_CREAT | O_RDONLY, 0600)); xmount(MOCK_LOAD, SELINUX_LOAD, nullptr, MS_BIND, nullptr); LOGD("Hijack [" SELINUX_ENFORCE "]\n"); mkfifo(MOCK_ENFORCE, 0644); xmount(MOCK_ENFORCE, SELINUX_ENFORCE, nullptr, MS_BIND, nullptr); };
string dt_compat; if (access(SELINUX_ENFORCE, F_OK) != 0) { // selinuxfs not mounted yet. Hijack the dt fstab nodes first // and let the original init mount selinuxfs for us. // This only happens on Android 8.0 - 9.0 // 省略...... } else { hijack(); }
// Read all custom rules into memory string rules; if (auto dir = xopen_dir("/data/" PREINITMIRR)) { for (dirent *entry; (entry = xreaddir(dir.get()));) { auto name = "/data/" PREINITMIRR "/"s + entry->d_name; auto rule_file = name + "/sepolicy.rule"; if (xaccess(rule_file.data(), R_OK) == 0 && access((name + "/disable").data(), F_OK) != 0 && access((name + "/remove").data(), F_OK) != 0) { LOGD("Load custom sepolicy patch: [%s]\n", rule_file.data()); full_read(rule_file.data(), rules); rules += '\n'; } } } // Create a new process waiting for init operations if (xfork()) { // In parent, return and continue boot process returntrue; }
// 省略......
// This open will block until init calls security_getenforce int fd = xopen(MOCK_ENFORCE, O_WRONLY);
// Cleanup the hijacks umount2("/init", MNT_DETACH); xumount2(SELINUX_LOAD, MNT_DETACH); xumount2(SELINUX_ENFORCE, MNT_DETACH);
// Load and patch policy auto sepol = unique_ptr<sepolicy>(sepolicy::from_file(MOCK_LOAD)); sepol->magisk_rules(); sepol->load_rules(rules);
// Load patched policy into kernel sepol->to_file(SELINUX_LOAD);
// Write to the enforce node ONLY after sepolicy is loaded. We need to make sure // the actual init process is blocked until sepolicy is loaded, or else // restorecon will fail and re-exec won't change context, causing boot failure. // We (ab)use the fact that init reads the enforce node, and because // it has been replaced with our FIFO file, init will block until we // write something into the pipe, effectively hijacking its control flow.