Skip to content

Commit e02e46d

Browse files
committedMay 19, 2020
Detect volume down key combo for safe mode
It is possible that a module is breaking the device so bad that zygote cannot even be started. In this case, system_server cannot start and detect the safe mode key combo, set the persist property, and reboot. Also on old Android versions, the system directly goes to safe mode after detecting a key combo without rebooting, defeating the purpose of Magisk's safe mode protection if we only check for the persist property. Directly adding key combo check natively in magiskd allows us to enter Magisk safe mode before the system is even aware of it.
1 parent 3c04dab commit e02e46d

File tree

4 files changed

+96
-48
lines changed

4 files changed

+96
-48
lines changed
 

‎native/jni/core/bootstages.cpp‎

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
#include <sys/mount.h>
22
#include <sys/wait.h>
3-
#include <stdlib.h>
4-
#include <stdio.h>
5-
#include <unistd.h>
6-
#include <fcntl.h>
7-
#include <string.h>
8-
#include <dirent.h>
3+
#include <sys/sysmacros.h>
4+
#include <linux/input.h>
95
#include <libgen.h>
106
#include <vector>
117
#include <string>
@@ -220,6 +216,53 @@ static void collect_logs(bool reset) {
220216
});
221217
}
222218

219+
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
220+
221+
static bool check_key_combo() {
222+
uint8_t bitmask[(KEY_MAX + 1) / 8];
223+
vector<int> events;
224+
constexpr char name[] = "/dev/.ev";
225+
226+
// First collect candidate events that accepts volume down
227+
for (int minor = 64; minor < 96; ++minor) {
228+
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
229+
continue;
230+
int fd = open(name, O_RDONLY | O_CLOEXEC);
231+
unlink(name);
232+
if (fd < 0)
233+
continue;
234+
memset(bitmask, 0, sizeof(bitmask));
235+
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
236+
if (test_bit(KEY_VOLUMEDOWN, bitmask))
237+
events.push_back(fd);
238+
else
239+
close(fd);
240+
}
241+
if (events.empty())
242+
return false;
243+
244+
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
245+
246+
// Check if volume down key is held continuously for more than 3 seconds
247+
for (int i = 0; i < 300; ++i) {
248+
bool pressed = false;
249+
for (const int &fd : events) {
250+
memset(bitmask, 0, sizeof(bitmask));
251+
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
252+
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
253+
pressed = true;
254+
break;
255+
}
256+
}
257+
if (!pressed)
258+
return false;
259+
// Check every 10ms
260+
usleep(10000);
261+
}
262+
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
263+
return true;
264+
}
265+
223266
/****************
224267
* Entry points *
225268
****************/
@@ -260,7 +303,7 @@ void post_fs_data(int client) {
260303
goto unblock_init;
261304
}
262305

263-
if (getprop("persist.sys.safemode", true) == "1") {
306+
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
264307
safe_mode = true;
265308
// Disable all modules and magiskhide so next boot will be clean
266309
foreach_modules("disable");

‎native/jni/init/getinfo.cpp‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,8 @@ static bool check_key_combo() {
4848
constexpr const char *name = "/event";
4949

5050
for (int minor = 64; minor < 96; ++minor) {
51-
if (mknod(name, S_IFCHR | 0444, makedev(13, minor))) {
52-
PLOGE("mknod");
51+
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
5352
continue;
54-
}
5553
int fd = open(name, O_RDONLY | O_CLOEXEC);
5654
unlink(name);
5755
if (fd < 0)
@@ -60,17 +58,15 @@ static bool check_key_combo() {
6058
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
6159
if (test_bit(KEY_VOLUMEUP, bitmask))
6260
events.push_back(fd);
61+
else
62+
close(fd);
6363
}
64-
6564
if (events.empty())
6665
return false;
6766

68-
run_finally fin([&]() -> void {
69-
for (const int &fd : events)
70-
close(fd);
71-
});
67+
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
7268

73-
// Return true if volume key up is hold for more than 3 seconds
69+
// Return true if volume up key is held for more than 3 seconds
7470
int count = 0;
7571
for (int i = 0; i < 500; ++i) {
7672
for (const int &fd : events) {

‎native/jni/utils/xwrap.cpp‎

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -91,23 +91,23 @@ ssize_t xxread(int fd, void *buf, size_t count) {
9191

9292
int xpipe2(int pipefd[2], int flags) {
9393
int ret = pipe2(pipefd, flags);
94-
if (ret == -1) {
94+
if (ret < 0) {
9595
PLOGE("pipe2");
9696
}
9797
return ret;
9898
}
9999

100100
int xsetns(int fd, int nstype) {
101101
int ret = setns(fd, nstype);
102-
if (ret == -1) {
102+
if (ret < 0) {
103103
PLOGE("setns");
104104
}
105105
return ret;
106106
}
107107

108108
int xunshare(int flags) {
109109
int ret = unshare(flags);
110-
if (ret == -1) {
110+
if (ret < 0) {
111111
PLOGE("unshare");
112112
}
113113
return ret;
@@ -147,39 +147,39 @@ struct dirent *xreaddir(DIR *dirp) {
147147

148148
pid_t xsetsid() {
149149
pid_t pid = setsid();
150-
if (pid == -1) {
150+
if (pid < 0) {
151151
PLOGE("setsid");
152152
}
153153
return pid;
154154
}
155155

156156
int xsocket(int domain, int type, int protocol) {
157157
int fd = socket(domain, type, protocol);
158-
if (fd == -1) {
158+
if (fd < 0) {
159159
PLOGE("socket");
160160
}
161161
return fd;
162162
}
163163

164164
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
165165
int ret = bind(sockfd, addr, addrlen);
166-
if (ret == -1) {
166+
if (ret < 0) {
167167
PLOGE("bind");
168168
}
169169
return ret;
170170
}
171171

172172
int xlisten(int sockfd, int backlog) {
173173
int ret = listen(sockfd, backlog);
174-
if (ret == -1) {
174+
if (ret < 0) {
175175
PLOGE("listen");
176176
}
177177
return ret;
178178
}
179179

180180
static int accept4_compat(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
181181
int fd = accept(sockfd, addr, addrlen);
182-
if (fd == -1) {
182+
if (fd < 0) {
183183
PLOGE("accept");
184184
} else {
185185
if (flags & SOCK_CLOEXEC)
@@ -194,7 +194,7 @@ static int accept4_compat(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
194194

195195
int xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
196196
int fd = accept4(sockfd, addr, addrlen, flags);
197-
if (fd == -1) {
197+
if (fd < 0) {
198198
if (errno == ENOSYS)
199199
return accept4_compat(sockfd, addr, addrlen, flags);
200200
PLOGE("accept4");
@@ -228,15 +228,15 @@ void *xrealloc(void *ptr, size_t size) {
228228

229229
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) {
230230
int sent = sendmsg(sockfd, msg, flags);
231-
if (sent == -1) {
231+
if (sent < 0) {
232232
PLOGE("sendmsg");
233233
}
234234
return sent;
235235
}
236236

237237
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
238238
int rec = recvmsg(sockfd, msg, flags);
239-
if (rec == -1) {
239+
if (rec < 0) {
240240
PLOGE("recvmsg");
241241
}
242242
return rec;
@@ -253,55 +253,55 @@ int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
253253

254254
int xstat(const char *pathname, struct stat *buf) {
255255
int ret = stat(pathname, buf);
256-
if (ret == -1) {
256+
if (ret < 0) {
257257
PLOGE("stat %s", pathname);
258258
}
259259
return ret;
260260
}
261261

262262
int xlstat(const char *pathname, struct stat *buf) {
263263
int ret = lstat(pathname, buf);
264-
if (ret == -1) {
264+
if (ret < 0) {
265265
PLOGE("lstat %s", pathname);
266266
}
267267
return ret;
268268
}
269269

270270
int xfstat(int fd, struct stat *buf) {
271271
int ret = fstat(fd, buf);
272-
if (ret == -1) {
272+
if (ret < 0) {
273273
PLOGE("fstat %d", fd);
274274
}
275275
return ret;
276276
}
277277

278278
int xdup(int fd) {
279279
int ret = dup(fd);
280-
if (ret == -1) {
280+
if (ret < 0) {
281281
PLOGE("dup");
282282
}
283283
return ret;
284284
}
285285

286286
int xdup2(int oldfd, int newfd) {
287287
int ret = dup2(oldfd, newfd);
288-
if (ret == -1) {
288+
if (ret < 0) {
289289
PLOGE("dup2");
290290
}
291291
return ret;
292292
}
293293

294294
int xdup3(int oldfd, int newfd, int flags) {
295295
int ret = dup3(oldfd, newfd, flags);
296-
if (ret == -1) {
296+
if (ret < 0) {
297297
PLOGE("dup3");
298298
}
299299
return ret;
300300
}
301301

302302
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) {
303303
ssize_t ret = readlink(pathname, buf, bufsiz);
304-
if (ret == -1) {
304+
if (ret < 0) {
305305
PLOGE("readlink %s", pathname);
306306
} else {
307307
buf[ret] = '\0';
@@ -315,7 +315,7 @@ ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
315315
#if defined(__i386__) || defined(__x86_64__)
316316
memset(buf, 0, bufsiz);
317317
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
318-
if (ret == -1) {
318+
if (ret < 0) {
319319
PLOGE("readlinkat %s", pathname);
320320
}
321321
return ret;
@@ -332,23 +332,23 @@ ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
332332

333333
int xsymlink(const char *target, const char *linkpath) {
334334
int ret = symlink(target, linkpath);
335-
if (ret == -1) {
335+
if (ret < 0) {
336336
PLOGE("symlink %s->%s", target, linkpath);
337337
}
338338
return ret;
339339
}
340340

341341
int xsymlinkat(const char *target, int newdirfd, const char *linkpath) {
342342
int ret = symlinkat(target, newdirfd, linkpath);
343-
if (ret == -1) {
343+
if (ret < 0) {
344344
PLOGE("symlinkat %s->%s", target, linkpath);
345345
}
346346
return ret;
347347
}
348348

349349
int xlinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) {
350350
int ret = linkat(olddirfd, oldpath, newdirfd, newpath, flags);
351-
if (ret == -1) {
351+
if (ret < 0) {
352352
PLOGE("linkat %s->%s", oldpath, newpath);
353353
}
354354
return ret;
@@ -358,55 +358,55 @@ int xmount(const char *source, const char *target,
358358
const char *filesystemtype, unsigned long mountflags,
359359
const void *data) {
360360
int ret = mount(source, target, filesystemtype, mountflags, data);
361-
if (ret == -1) {
361+
if (ret < 0) {
362362
PLOGE("mount %s->%s", source, target);
363363
}
364364
return ret;
365365
}
366366

367367
int xumount(const char *target) {
368368
int ret = umount(target);
369-
if (ret == -1) {
369+
if (ret < 0) {
370370
PLOGE("umount %s", target);
371371
}
372372
return ret;
373373
}
374374

375375
int xumount2(const char *target, int flags) {
376376
int ret = umount2(target, flags);
377-
if (ret == -1) {
377+
if (ret < 0) {
378378
PLOGE("umount2 %s", target);
379379
}
380380
return ret;
381381
}
382382

383383
int xrename(const char *oldpath, const char *newpath) {
384384
int ret = rename(oldpath, newpath);
385-
if (ret == -1) {
385+
if (ret < 0) {
386386
PLOGE("rename %s->%s", oldpath, newpath);
387387
}
388388
return ret;
389389
}
390390

391391
int xmkdir(const char *pathname, mode_t mode) {
392392
int ret = mkdir(pathname, mode);
393-
if (ret == -1 && errno != EEXIST) {
393+
if (ret < 0 && errno != EEXIST) {
394394
PLOGE("mkdir %s %u", pathname, mode);
395395
}
396396
return ret;
397397
}
398398

399399
int xmkdirs(const char *pathname, mode_t mode) {
400400
int ret = mkdirs(pathname, mode);
401-
if (ret == -1) {
401+
if (ret < 0) {
402402
PLOGE("mkdirs %s", pathname);
403403
}
404404
return ret;
405405
}
406406

407407
int xmkdirat(int dirfd, const char *pathname, mode_t mode) {
408408
int ret = mkdirat(dirfd, pathname, mode);
409-
if (ret == -1 && errno != EEXIST) {
409+
if (ret < 0 && errno != EEXIST) {
410410
PLOGE("mkdirat %s %u", pathname, mode);
411411
}
412412
return ret;
@@ -431,23 +431,23 @@ ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
431431

432432
pid_t xfork() {
433433
int ret = fork();
434-
if (ret == -1) {
434+
if (ret < 0) {
435435
PLOGE("fork");
436436
}
437437
return ret;
438438
}
439439

440440
int xpoll(struct pollfd *fds, nfds_t nfds, int timeout) {
441441
int ret = poll(fds, nfds, timeout);
442-
if (ret == -1) {
442+
if (ret < 0) {
443443
PLOGE("poll");
444444
}
445445
return ret;
446446
}
447447

448448
int xinotify_init1(int flags) {
449449
int ret = inotify_init1(flags);
450-
if (ret == -1) {
450+
if (ret < 0) {
451451
PLOGE("inotify_init1");
452452
}
453453
return ret;
@@ -463,3 +463,11 @@ char *xrealpath(const char *path, char *resolved_path) {
463463
}
464464
return ret;
465465
}
466+
467+
int xmknod(const char *pathname, mode_t mode, dev_t dev) {
468+
int ret = mknod(pathname, mode, dev);
469+
if (ret < 0) {
470+
PLOGE("mknod");
471+
}
472+
return ret;
473+
}

‎native/jni/utils/xwrap.hpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,5 @@ pid_t xfork();
5959
int xpoll(struct pollfd *fds, nfds_t nfds, int timeout);
6060
int xinotify_init1(int flags);
6161
char *xrealpath(const char *path, char *resolved_path);
62+
int xmknod(const char *pathname, mode_t mode, dev_t dev);
6263

0 commit comments

Comments
 (0)
Please sign in to comment.