Magisk/native/src/core/bootstages.cpp

204 lines
5.2 KiB
C++

#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/sysmacros.h>
#include <linux/input.h>
#include <libgen.h>
#include <set>
#include <string>
#include <consts.hpp>
#include <db.hpp>
#include <base.hpp>
#include <core.hpp>
#include <selinux.hpp>
using namespace std;
bool zygisk_enabled = false;
/*********
* Setup *
*********/
static bool magisk_env() {
char buf[4096];
LOGI("* Initializing Magisk environment\n");
// Directories in /data/adb
chmod(SECURE_DIR, 0700);
xmkdir(DATABIN, 0755);
xmkdir(MODULEROOT, 0755);
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
xmkdir(SECURE_DIR "/service.d", 0755);
restorecon();
if (access(DATABIN "/busybox", X_OK))
return false;
ssprintf(buf, sizeof(buf), "%s/" BBPATH "/busybox", get_magisk_tmp());
mkdir(dirname(buf), 0755);
cp_afc(DATABIN "/busybox", buf);
exec_command_async(buf, "--install", "-s", dirname(buf));
// magisk32 and magiskpolicy are not installed into ramdisk and has to be copied
// from data to magisk tmp
if (access(DATABIN "/magisk32", X_OK) == 0) {
ssprintf(buf, sizeof(buf), "%s/magisk32", get_magisk_tmp());
cp_afc(DATABIN "/magisk32", buf);
}
if (access(DATABIN "/magiskpolicy", X_OK) == 0) {
ssprintf(buf, sizeof(buf), "%s/magiskpolicy", get_magisk_tmp());
cp_afc(DATABIN "/magiskpolicy", buf);
}
return true;
}
void unlock_blocks() {
int fd, dev, OFF = 0;
auto dir = xopen_dir("/dev/block");
if (!dir)
return;
dev = dirfd(dir.get());
for (dirent *entry; (entry = readdir(dir.get()));) {
if (entry->d_type == DT_BLK) {
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
continue;
if (ioctl(fd, BLKROSET, &OFF) < 0)
PLOGE("unlock %s", entry->d_name);
close(fd);
}
}
}
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
static bool check_key_combo() {
uint8_t bitmask[(KEY_MAX + 1) / 8];
vector<int> events;
constexpr char name[] = "/dev/.ev";
// First collect candidate events that accepts volume down
for (int minor = 64; minor < 96; ++minor) {
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
continue;
int fd = open(name, O_RDONLY | O_CLOEXEC);
unlink(name);
if (fd < 0)
continue;
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEDOWN, bitmask))
events.push_back(fd);
else
close(fd);
}
if (events.empty())
return false;
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
// Check if volume down key is held continuously for more than 3 seconds
for (int i = 0; i < 300; ++i) {
bool pressed = false;
for (const int &fd : events) {
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
pressed = true;
break;
}
}
if (!pressed)
return false;
// Check every 10ms
usleep(10000);
}
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
return true;
}
/***********************
* Boot Stage Handlers *
***********************/
static void disable_zygisk() {
char sql[64];
sprintf(sql, "REPLACE INTO settings (key,value) VALUES('%s',%d)",
DB_SETTING_KEYS[ZYGISK_CONFIG], false);
char *err = db_exec(sql);
db_err(err);
}
bool MagiskD::post_fs_data() const {
as_rust().setup_logfile();
LOGI("** post-fs-data mode running\n");
preserve_stub_apk();
prune_su_access();
bool safe_mode = false;
if (access(SECURE_DIR, F_OK) != 0) {
if (SDK_INT < 24) {
xmkdir(SECURE_DIR, 0700);
} else {
LOGE(SECURE_DIR " is not present, abort\n");
return safe_mode;
}
}
if (!magisk_env()) {
LOGE("* Magisk environment incomplete, abort\n");
return safe_mode;
}
if (get_prop("persist.sys.safemode", true) == "1" ||
get_prop("ro.sys.safemode") == "1" || check_key_combo()) {
safe_mode = true;
// Disable all modules and zygisk so next boot will be clean
disable_modules();
disable_zygisk();
return safe_mode;
}
exec_common_scripts("post-fs-data");
db_settings dbs;
get_db_settings(dbs, ZYGISK_CONFIG);
zygisk_enabled = dbs[ZYGISK_CONFIG];
initialize_denylist();
setup_mounts();
handle_modules();
load_modules();
return safe_mode;
}
void MagiskD::late_start() const {
as_rust().setup_logfile();
LOGI("** late_start service mode running\n");
exec_common_scripts("service");
exec_module_scripts("service");
}
void MagiskD::boot_complete() const {
as_rust().setup_logfile();
LOGI("** boot-complete triggered\n");
// At this point it's safe to create the folder
if (access(SECURE_DIR, F_OK) != 0)
xmkdir(SECURE_DIR, 0700);
// Ensure manager exists
check_pkg_refresh();
get_manager(0, nullptr, true);
reset_zygisk(true);
}