diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index 3c44dea0a..e2f8d52f6 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -1,11 +1,7 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include @@ -220,6 +216,53 @@ static void collect_logs(bool reset) { }); } +#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8))) + +static bool check_key_combo() { + uint8_t bitmask[(KEY_MAX + 1) / 8]; + vector 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; +} + /**************** * Entry points * ****************/ @@ -260,7 +303,7 @@ void post_fs_data(int client) { goto unblock_init; } - if (getprop("persist.sys.safemode", true) == "1") { + if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) { safe_mode = true; // Disable all modules and magiskhide so next boot will be clean foreach_modules("disable"); diff --git a/native/jni/init/getinfo.cpp b/native/jni/init/getinfo.cpp index 5d707074a..b4c31c27a 100644 --- a/native/jni/init/getinfo.cpp +++ b/native/jni/init/getinfo.cpp @@ -48,10 +48,8 @@ static bool check_key_combo() { constexpr const char *name = "/event"; for (int minor = 64; minor < 96; ++minor) { - if (mknod(name, S_IFCHR | 0444, makedev(13, minor))) { - PLOGE("mknod"); + if (xmknod(name, S_IFCHR | 0444, makedev(13, minor))) continue; - } int fd = open(name, O_RDONLY | O_CLOEXEC); unlink(name); if (fd < 0) @@ -60,17 +58,15 @@ static bool check_key_combo() { ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask); if (test_bit(KEY_VOLUMEUP, bitmask)) events.push_back(fd); + else + close(fd); } - if (events.empty()) return false; - run_finally fin([&]() -> void { - for (const int &fd : events) - close(fd); - }); + run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); }); - // Return true if volume key up is hold for more than 3 seconds + // Return true if volume up key is held for more than 3 seconds int count = 0; for (int i = 0; i < 500; ++i) { for (const int &fd : events) { diff --git a/native/jni/utils/xwrap.cpp b/native/jni/utils/xwrap.cpp index 3a5d67b2b..70d1c0a78 100644 --- a/native/jni/utils/xwrap.cpp +++ b/native/jni/utils/xwrap.cpp @@ -91,7 +91,7 @@ ssize_t xxread(int fd, void *buf, size_t count) { int xpipe2(int pipefd[2], int flags) { int ret = pipe2(pipefd, flags); - if (ret == -1) { + if (ret < 0) { PLOGE("pipe2"); } return ret; @@ -99,7 +99,7 @@ int xpipe2(int pipefd[2], int flags) { int xsetns(int fd, int nstype) { int ret = setns(fd, nstype); - if (ret == -1) { + if (ret < 0) { PLOGE("setns"); } return ret; @@ -107,7 +107,7 @@ int xsetns(int fd, int nstype) { int xunshare(int flags) { int ret = unshare(flags); - if (ret == -1) { + if (ret < 0) { PLOGE("unshare"); } return ret; @@ -147,7 +147,7 @@ struct dirent *xreaddir(DIR *dirp) { pid_t xsetsid() { pid_t pid = setsid(); - if (pid == -1) { + if (pid < 0) { PLOGE("setsid"); } return pid; @@ -155,7 +155,7 @@ pid_t xsetsid() { int xsocket(int domain, int type, int protocol) { int fd = socket(domain, type, protocol); - if (fd == -1) { + if (fd < 0) { PLOGE("socket"); } return fd; @@ -163,7 +163,7 @@ int xsocket(int domain, int type, int protocol) { int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int ret = bind(sockfd, addr, addrlen); - if (ret == -1) { + if (ret < 0) { PLOGE("bind"); } return ret; @@ -171,7 +171,7 @@ int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int xlisten(int sockfd, int backlog) { int ret = listen(sockfd, backlog); - if (ret == -1) { + if (ret < 0) { PLOGE("listen"); } return ret; @@ -179,7 +179,7 @@ int xlisten(int sockfd, int backlog) { static int accept4_compat(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { int fd = accept(sockfd, addr, addrlen); - if (fd == -1) { + if (fd < 0) { PLOGE("accept"); } else { if (flags & SOCK_CLOEXEC) @@ -194,7 +194,7 @@ static int accept4_compat(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { int fd = accept4(sockfd, addr, addrlen, flags); - if (fd == -1) { + if (fd < 0) { if (errno == ENOSYS) return accept4_compat(sockfd, addr, addrlen, flags); PLOGE("accept4"); @@ -228,7 +228,7 @@ void *xrealloc(void *ptr, size_t size) { ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) { int sent = sendmsg(sockfd, msg, flags); - if (sent == -1) { + if (sent < 0) { PLOGE("sendmsg"); } return sent; @@ -236,7 +236,7 @@ ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) { ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) { int rec = recvmsg(sockfd, msg, flags); - if (rec == -1) { + if (rec < 0) { PLOGE("recvmsg"); } return rec; @@ -253,7 +253,7 @@ int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, int xstat(const char *pathname, struct stat *buf) { int ret = stat(pathname, buf); - if (ret == -1) { + if (ret < 0) { PLOGE("stat %s", pathname); } return ret; @@ -261,7 +261,7 @@ int xstat(const char *pathname, struct stat *buf) { int xlstat(const char *pathname, struct stat *buf) { int ret = lstat(pathname, buf); - if (ret == -1) { + if (ret < 0) { PLOGE("lstat %s", pathname); } return ret; @@ -269,7 +269,7 @@ int xlstat(const char *pathname, struct stat *buf) { int xfstat(int fd, struct stat *buf) { int ret = fstat(fd, buf); - if (ret == -1) { + if (ret < 0) { PLOGE("fstat %d", fd); } return ret; @@ -277,7 +277,7 @@ int xfstat(int fd, struct stat *buf) { int xdup(int fd) { int ret = dup(fd); - if (ret == -1) { + if (ret < 0) { PLOGE("dup"); } return ret; @@ -285,7 +285,7 @@ int xdup(int fd) { int xdup2(int oldfd, int newfd) { int ret = dup2(oldfd, newfd); - if (ret == -1) { + if (ret < 0) { PLOGE("dup2"); } return ret; @@ -293,7 +293,7 @@ int xdup2(int oldfd, int newfd) { int xdup3(int oldfd, int newfd, int flags) { int ret = dup3(oldfd, newfd, flags); - if (ret == -1) { + if (ret < 0) { PLOGE("dup3"); } return ret; @@ -301,7 +301,7 @@ int xdup3(int oldfd, int newfd, int flags) { ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) { ssize_t ret = readlink(pathname, buf, bufsiz); - if (ret == -1) { + if (ret < 0) { PLOGE("readlink %s", pathname); } else { buf[ret] = '\0'; @@ -315,7 +315,7 @@ ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { #if defined(__i386__) || defined(__x86_64__) memset(buf, 0, bufsiz); ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz); - if (ret == -1) { + if (ret < 0) { PLOGE("readlinkat %s", pathname); } return ret; @@ -332,7 +332,7 @@ ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { int xsymlink(const char *target, const char *linkpath) { int ret = symlink(target, linkpath); - if (ret == -1) { + if (ret < 0) { PLOGE("symlink %s->%s", target, linkpath); } return ret; @@ -340,7 +340,7 @@ int xsymlink(const char *target, const char *linkpath) { int xsymlinkat(const char *target, int newdirfd, const char *linkpath) { int ret = symlinkat(target, newdirfd, linkpath); - if (ret == -1) { + if (ret < 0) { PLOGE("symlinkat %s->%s", target, linkpath); } return ret; @@ -348,7 +348,7 @@ int xsymlinkat(const char *target, int newdirfd, const char *linkpath) { int xlinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) { int ret = linkat(olddirfd, oldpath, newdirfd, newpath, flags); - if (ret == -1) { + if (ret < 0) { PLOGE("linkat %s->%s", oldpath, newpath); } return ret; @@ -358,7 +358,7 @@ int xmount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) { int ret = mount(source, target, filesystemtype, mountflags, data); - if (ret == -1) { + if (ret < 0) { PLOGE("mount %s->%s", source, target); } return ret; @@ -366,7 +366,7 @@ int xmount(const char *source, const char *target, int xumount(const char *target) { int ret = umount(target); - if (ret == -1) { + if (ret < 0) { PLOGE("umount %s", target); } return ret; @@ -374,7 +374,7 @@ int xumount(const char *target) { int xumount2(const char *target, int flags) { int ret = umount2(target, flags); - if (ret == -1) { + if (ret < 0) { PLOGE("umount2 %s", target); } return ret; @@ -382,7 +382,7 @@ int xumount2(const char *target, int flags) { int xrename(const char *oldpath, const char *newpath) { int ret = rename(oldpath, newpath); - if (ret == -1) { + if (ret < 0) { PLOGE("rename %s->%s", oldpath, newpath); } return ret; @@ -390,7 +390,7 @@ int xrename(const char *oldpath, const char *newpath) { int xmkdir(const char *pathname, mode_t mode) { int ret = mkdir(pathname, mode); - if (ret == -1 && errno != EEXIST) { + if (ret < 0 && errno != EEXIST) { PLOGE("mkdir %s %u", pathname, mode); } return ret; @@ -398,7 +398,7 @@ int xmkdir(const char *pathname, mode_t mode) { int xmkdirs(const char *pathname, mode_t mode) { int ret = mkdirs(pathname, mode); - if (ret == -1) { + if (ret < 0) { PLOGE("mkdirs %s", pathname); } return ret; @@ -406,7 +406,7 @@ int xmkdirs(const char *pathname, mode_t mode) { int xmkdirat(int dirfd, const char *pathname, mode_t mode) { int ret = mkdirat(dirfd, pathname, mode); - if (ret == -1 && errno != EEXIST) { + if (ret < 0 && errno != EEXIST) { PLOGE("mkdirat %s %u", pathname, mode); } return ret; @@ -431,7 +431,7 @@ ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count) { pid_t xfork() { int ret = fork(); - if (ret == -1) { + if (ret < 0) { PLOGE("fork"); } return ret; @@ -439,7 +439,7 @@ pid_t xfork() { int xpoll(struct pollfd *fds, nfds_t nfds, int timeout) { int ret = poll(fds, nfds, timeout); - if (ret == -1) { + if (ret < 0) { PLOGE("poll"); } return ret; @@ -447,7 +447,7 @@ int xpoll(struct pollfd *fds, nfds_t nfds, int timeout) { int xinotify_init1(int flags) { int ret = inotify_init1(flags); - if (ret == -1) { + if (ret < 0) { PLOGE("inotify_init1"); } return ret; @@ -463,3 +463,11 @@ char *xrealpath(const char *path, char *resolved_path) { } return ret; } + +int xmknod(const char *pathname, mode_t mode, dev_t dev) { + int ret = mknod(pathname, mode, dev); + if (ret < 0) { + PLOGE("mknod"); + } + return ret; +} diff --git a/native/jni/utils/xwrap.hpp b/native/jni/utils/xwrap.hpp index 266f4ad4f..d982f0985 100644 --- a/native/jni/utils/xwrap.hpp +++ b/native/jni/utils/xwrap.hpp @@ -59,4 +59,5 @@ pid_t xfork(); int xpoll(struct pollfd *fds, nfds_t nfds, int timeout); int xinotify_init1(int flags); char *xrealpath(const char *path, char *resolved_path); +int xmknod(const char *pathname, mode_t mode, dev_t dev);