mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-04 07:25:26 +00:00
Use isolated devpts if kernel support
kernel version >= 4.7 or CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
This commit is contained in:
parent
0dad06cdfe
commit
f324252681
@ -249,6 +249,19 @@ static int switch_cgroup(const char *cgroup, int pid) {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Use isolated devpts if kernel support
|
||||||
|
if (access("/dev/pts/ptmx", F_OK) == 0) {
|
||||||
|
auto pts = MAGISKTMP + "/" SHELLPTS;
|
||||||
|
xmkdirs(pts.data(), 0755);
|
||||||
|
xmount("devpts", pts.data(), "devpts",
|
||||||
|
MS_NOSUID | MS_NOEXEC, "newinstance");
|
||||||
|
auto ptmx = pts + "/ptmx";
|
||||||
|
if (access(ptmx.data(), F_OK)) {
|
||||||
|
xumount(pts.data());
|
||||||
|
rmdir(pts.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sockaddr_un sun;
|
sockaddr_un sun;
|
||||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||||
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
|
@ -22,6 +22,7 @@ extern std::string MAGISKTMP;
|
|||||||
#define MODULEMNT INTLROOT "/modules"
|
#define MODULEMNT INTLROOT "/modules"
|
||||||
#define BBPATH INTLROOT "/busybox"
|
#define BBPATH INTLROOT "/busybox"
|
||||||
#define ROOTOVL INTLROOT "/rootdir"
|
#define ROOTOVL INTLROOT "/rootdir"
|
||||||
|
#define SHELLPTS INTLROOT "/pts"
|
||||||
#define ROOTMNT ROOTOVL "/.mount_list"
|
#define ROOTMNT ROOTOVL "/.mount_list"
|
||||||
|
|
||||||
constexpr const char *applet_names[] = { "su", "resetprop", "magiskhide", nullptr };
|
constexpr const char *applet_names[] = { "su", "resetprop", "magiskhide", nullptr };
|
||||||
|
@ -35,6 +35,10 @@ void hide_unmount(int pid) {
|
|||||||
|
|
||||||
// Unmount dummy skeletons and MAGISKTMP
|
// Unmount dummy skeletons and MAGISKTMP
|
||||||
targets.push_back(MAGISKTMP);
|
targets.push_back(MAGISKTMP);
|
||||||
|
auto magiskpts = MAGISKTMP + "/" SHELLPTS;
|
||||||
|
if (access(magiskpts.data(), F_OK) == 0) {
|
||||||
|
targets.push_back(magiskpts);
|
||||||
|
}
|
||||||
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
|
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
|
||||||
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))
|
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))
|
||||||
targets.emplace_back(mentry->mnt_dir);
|
targets.emplace_back(mentry->mnt_dir);
|
||||||
|
@ -105,6 +105,14 @@ error:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_pty_num(int fd) {
|
||||||
|
int pty_num = -1;
|
||||||
|
if (ioctl(fd, TIOCGPTN, &pty_num) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pty_num;
|
||||||
|
}
|
||||||
|
|
||||||
// Stores the previous termios of stdin
|
// Stores the previous termios of stdin
|
||||||
static struct termios old_stdin;
|
static struct termios old_stdin;
|
||||||
static int stdin_is_raw = 0;
|
static int stdin_is_raw = 0;
|
||||||
|
@ -29,10 +29,13 @@
|
|||||||
*/
|
*/
|
||||||
int pts_open(char *slave_name, size_t slave_name_size);
|
int pts_open(char *slave_name, size_t slave_name_size);
|
||||||
|
|
||||||
|
|
||||||
|
int get_pty_num(int fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set_stdin_raw
|
* set_stdin_raw
|
||||||
*
|
*
|
||||||
* Changes stdin to raw unbuffered mode, disables echo,
|
* Changes stdin to raw unbuffered mode, disables echo,
|
||||||
* auto carriage return, etc.
|
* auto carriage return, etc.
|
||||||
*
|
*
|
||||||
* Return Value
|
* Return Value
|
||||||
@ -60,7 +63,7 @@ int restore_stdin(void);
|
|||||||
* watch_sigwinch_async
|
* watch_sigwinch_async
|
||||||
*
|
*
|
||||||
* After calling this function, if the application receives
|
* After calling this function, if the application receives
|
||||||
* SIGWINCH, the terminal window size will be read from
|
* SIGWINCH, the terminal window size will be read from
|
||||||
* "input" and set on "output".
|
* "input" and set on "output".
|
||||||
*
|
*
|
||||||
* NOTE: This function blocks SIGWINCH and spawns a thread.
|
* NOTE: This function blocks SIGWINCH and spawns a thread.
|
||||||
@ -72,7 +75,7 @@ int restore_stdin(void);
|
|||||||
*
|
*
|
||||||
* Return Value
|
* Return Value
|
||||||
* on failure, -1 and errno will be set. In this case, no
|
* on failure, -1 and errno will be set. In this case, no
|
||||||
* thread has been spawned and SIGWINCH will not be
|
* thread has been spawned and SIGWINCH will not be
|
||||||
* blocked.
|
* blocked.
|
||||||
* on success, 0
|
* on success, 0
|
||||||
*/
|
*/
|
||||||
|
@ -156,7 +156,6 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
optind++;
|
optind++;
|
||||||
}
|
}
|
||||||
|
|
||||||
char pts_slave[PATH_MAX];
|
|
||||||
int ptmx, fd;
|
int ptmx, fd;
|
||||||
|
|
||||||
// Connect to client
|
// Connect to client
|
||||||
@ -183,16 +182,6 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
if (isatty(STDOUT_FILENO)) atty |= ATTY_OUT;
|
if (isatty(STDOUT_FILENO)) atty |= ATTY_OUT;
|
||||||
if (isatty(STDERR_FILENO)) atty |= ATTY_ERR;
|
if (isatty(STDERR_FILENO)) atty |= ATTY_ERR;
|
||||||
|
|
||||||
if (atty) {
|
|
||||||
// We need a PTY. Get one.
|
|
||||||
ptmx = pts_open(pts_slave, sizeof(pts_slave));
|
|
||||||
} else {
|
|
||||||
pts_slave[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send pts_slave
|
|
||||||
write_string(fd, pts_slave);
|
|
||||||
|
|
||||||
// Send stdin
|
// Send stdin
|
||||||
send_fd(fd, (atty & ATTY_IN) ? -1 : STDIN_FILENO);
|
send_fd(fd, (atty & ATTY_IN) ? -1 : STDIN_FILENO);
|
||||||
// Send stdout
|
// Send stdout
|
||||||
@ -200,6 +189,14 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
// Send stderr
|
// Send stderr
|
||||||
send_fd(fd, (atty & ATTY_ERR) ? -1 : STDERR_FILENO);
|
send_fd(fd, (atty & ATTY_ERR) ? -1 : STDERR_FILENO);
|
||||||
|
|
||||||
|
if (atty) {
|
||||||
|
// We need a PTY. Get one.
|
||||||
|
write_int(fd, 1);
|
||||||
|
ptmx = recv_fd(fd);
|
||||||
|
} else {
|
||||||
|
write_int(fd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (atty) {
|
if (atty) {
|
||||||
setup_sighandlers(sighandler);
|
setup_sighandlers(sighandler);
|
||||||
watch_sigwinch_async(STDOUT_FILENO, ptmx);
|
watch_sigwinch_async(STDOUT_FILENO, ptmx);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
#include <daemon.hpp>
|
#include <daemon.hpp>
|
||||||
|
#include <magisk.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
#include <db.hpp>
|
#include <db.hpp>
|
||||||
@ -222,23 +223,32 @@ void su_daemon_handler(int client, struct ucred *credential) {
|
|||||||
// Become session leader
|
// Become session leader
|
||||||
xsetsid();
|
xsetsid();
|
||||||
|
|
||||||
// Get pts_slave
|
|
||||||
string pts_slave = read_string(client);
|
|
||||||
|
|
||||||
// The FDs for each of the streams
|
// The FDs for each of the streams
|
||||||
int infd = recv_fd(client);
|
int infd = recv_fd(client);
|
||||||
int outfd = recv_fd(client);
|
int outfd = recv_fd(client);
|
||||||
int errfd = recv_fd(client);
|
int errfd = recv_fd(client);
|
||||||
|
|
||||||
if (!pts_slave.empty()) {
|
// App need a PTY
|
||||||
LOGD("su: pts_slave=[%s]\n", pts_slave.data());
|
if (read_int(client)) {
|
||||||
// Check pts_slave file is owned by daemon_from_uid
|
string pts;
|
||||||
struct stat st;
|
string ptmx;
|
||||||
xstat(pts_slave.data(), &st);
|
auto magiskpts = MAGISKTMP + "/" SHELLPTS;
|
||||||
|
if (access(magiskpts.data(), F_OK)) {
|
||||||
|
pts = "/dev/pts";
|
||||||
|
ptmx = "/dev/ptmx";
|
||||||
|
} else {
|
||||||
|
pts = magiskpts;
|
||||||
|
ptmx = magiskpts + "/ptmx";
|
||||||
|
}
|
||||||
|
int ptmx_fd = xopen(ptmx.data(), O_RDWR);
|
||||||
|
int unlock = 0;
|
||||||
|
ioctl(ptmx_fd, TIOCSPTLCK, &unlock);
|
||||||
|
send_fd(client, ptmx_fd);
|
||||||
|
int pty_num = get_pty_num(ptmx_fd);
|
||||||
|
close(ptmx_fd);
|
||||||
|
|
||||||
// If caller is not root, ensure the owner of pts_slave is the caller
|
string pts_slave = pts + "/" + to_string(pty_num);
|
||||||
if(st.st_uid != ctx.info->uid && ctx.info->uid != 0)
|
LOGD("su: pts_slave=[%s]\n", pts_slave.data());
|
||||||
LOGE("su: Wrong permission of pts_slave\n");
|
|
||||||
|
|
||||||
// Opening the TTY has to occur after the
|
// Opening the TTY has to occur after the
|
||||||
// fork() and setsid() so that it becomes
|
// fork() and setsid() so that it becomes
|
||||||
@ -258,11 +268,6 @@ void su_daemon_handler(int client, struct ucred *credential) {
|
|||||||
xdup2(outfd, STDOUT_FILENO);
|
xdup2(outfd, STDOUT_FILENO);
|
||||||
xdup2(errfd, STDERR_FILENO);
|
xdup2(errfd, STDERR_FILENO);
|
||||||
|
|
||||||
// Unleash all streams from SELinux hell
|
|
||||||
setfilecon("/proc/self/fd/0", "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
|
||||||
setfilecon("/proc/self/fd/1", "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
|
||||||
setfilecon("/proc/self/fd/2", "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
|
||||||
|
|
||||||
close(infd);
|
close(infd);
|
||||||
close(outfd);
|
close(outfd);
|
||||||
close(errfd);
|
close(errfd);
|
||||||
@ -331,5 +336,4 @@ void su_daemon_handler(int client, struct ucred *credential) {
|
|||||||
execvp(ctx.req.shell.data(), (char **) argv);
|
execvp(ctx.req.shell.data(), (char **) argv);
|
||||||
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell.data(), strerror(errno));
|
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell.data(), strerror(errno));
|
||||||
PLOGE("exec");
|
PLOGE("exec");
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
@ -54,4 +54,4 @@ void LOGD(const char *fmt, ...) {}
|
|||||||
#endif
|
#endif
|
||||||
void LOGI(const char *fmt, ...) { LOG_BODY(i) }
|
void LOGI(const char *fmt, ...) { LOG_BODY(i) }
|
||||||
void LOGW(const char *fmt, ...) { LOG_BODY(w) }
|
void LOGW(const char *fmt, ...) { LOG_BODY(w) }
|
||||||
void LOGE(const char *fmt, ...) { LOG_BODY(e); log_cb.ex(1); }
|
void LOGE(const char *fmt, ...) { LOG_BODY(e); log_cb.ex(EXIT_FAILURE); }
|
||||||
|
Loading…
Reference in New Issue
Block a user