Use SO_PEERSEC to get client secontext

This commit is contained in:
topjohnwu 2021-10-19 23:46:38 -07:00
parent fe41df87bb
commit 8d0dc37ec0
7 changed files with 47 additions and 43 deletions

View File

@ -130,26 +130,7 @@ static void poll_ctrl_handler(pollfd *pfd) {
} }
} }
static bool verify_client(pid_t pid) { static void handle_request_async(int client, int code, const sock_cred &cred) {
// Verify caller is the same as server
char path[32];
sprintf(path, "/proc/%d/exe", pid);
struct stat st;
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
}
static bool check_zygote(pid_t pid) {
char buf[32];
sprintf(buf, "/proc/%d/attr/current", pid);
if (auto fp = open_file(buf, "r")) {
fscanf(fp.get(), "%s", buf);
return buf == "u:r:zygote:s0"sv;
} else {
return false;
}
}
static void handle_request_async(int client, int code, ucred cred) {
switch (code) { switch (code) {
case DENYLIST: case DENYLIST:
denylist_handler(client, &cred); denylist_handler(client, &cred);
@ -206,19 +187,29 @@ static void handle_request_sync(int client, int code) {
} }
} }
static bool is_client(pid_t pid) {
// Verify caller is the same as server
char path[32];
sprintf(path, "/proc/%d/exe", pid);
struct stat st;
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
}
static void handle_request(pollfd *pfd) { static void handle_request(pollfd *pfd) {
int client = xaccept4(pfd->fd, nullptr, nullptr, SOCK_CLOEXEC); int client = xaccept4(pfd->fd, nullptr, nullptr, SOCK_CLOEXEC);
// Verify client credentials // Verify client credentials
ucred cred; sock_cred cred;
get_client_cred(client, &cred); bool is_root;
bool is_zygote;
bool is_root = cred.uid == UID_ROOT;
bool is_client = verify_client(cred.pid);
bool is_zygote = !is_client && check_zygote(cred.pid);
int code; int code;
if (!is_root && !is_zygote && !is_client) if (!get_client_cred(client, &cred))
goto done;
is_root = cred.uid == UID_ROOT;
is_zygote = cred.context == "u:r:zygote:s0";
if (!is_root && !is_zygote && !is_client(cred.pid))
goto done; goto done;
code = read_int(client); code = read_int(client);

View File

@ -20,9 +20,17 @@ socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) {
return socket_len(sun); return socket_len(sun);
} }
void get_client_cred(int fd, ucred *cred) { bool get_client_cred(int fd, sock_cred *cred) {
socklen_t len = sizeof(*cred); socklen_t len = sizeof(ucred);
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &len); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &len) != 0)
return false;
char buf[4096];
len = sizeof(buf);
if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &len) != 0)
return false;
buf[len] = '\0';
cred->context = buf;
return true;
} }
static int send_fds(int sockfd, void *cmsgbuf, size_t bufsz, const int *fds, int cnt) { static int send_fds(int sockfd, void *cmsgbuf, size_t bufsz, const int *fds, int cnt) {

View File

@ -63,9 +63,9 @@ void android_logging();
void post_fs_data(int client); void post_fs_data(int client);
void late_start(int client); void late_start(int client);
void boot_complete(int client); void boot_complete(int client);
void denylist_handler(int client, ucred *cred); void denylist_handler(int client, const sock_cred *cred);
void su_daemon_handler(int client, ucred *credential); void su_daemon_handler(int client, const sock_cred *cred);
void zygisk_handler(int client, ucred *cred); void zygisk_handler(int client, const sock_cred *cred);
std::vector<int> zygisk_module_fds(bool is_64_bit); std::vector<int> zygisk_module_fds(bool is_64_bit);
// Denylist // Denylist

View File

@ -3,10 +3,15 @@
#include <sys/un.h> #include <sys/un.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <string_view> #include <string_view>
#include <string>
#include <vector> #include <vector>
struct sock_cred : public ucred {
std::string context;
};
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name); socklen_t setup_sockaddr(sockaddr_un *sun, const char *name);
void get_client_cred(int fd, ucred *cred); bool get_client_cred(int fd, sock_cred *cred);
std::vector<int> recv_fds(int sockfd); std::vector<int> recv_fds(int sockfd);
int recv_fd(int sockfd); int recv_fd(int sockfd);
int send_fds(int sockfd, const int *fds, int cnt); int send_fds(int sockfd, const int *fds, int cnt);

View File

@ -158,13 +158,13 @@ static void set_identity(unsigned uid) {
} }
} }
void su_daemon_handler(int client, struct ucred *credential) { void su_daemon_handler(int client, const sock_cred *cred) {
LOGD("su: request from pid=[%d], client=[%d]\n", credential->pid, client); LOGD("su: request from pid=[%d], client=[%d]\n", cred->pid, client);
su_context ctx = { su_context ctx = {
.info = get_su_info(credential->uid), .info = get_su_info(cred->uid),
.req = su_request(), .req = su_request(),
.pid = credential->pid .pid = cred->pid
}; };
// Read su_request // Read su_request

View File

@ -25,7 +25,7 @@ Actions:
exit(1); exit(1);
} }
void denylist_handler(int client, ucred *cred) { void denylist_handler(int client, const sock_cred *cred) {
if (client < 0) { if (client < 0) {
revert_unmount(); revert_unmount();
return; return;

View File

@ -243,7 +243,7 @@ int remote_request_unmount() {
// The following code runs in magiskd // The following code runs in magiskd
static void setup_files(int client, ucred *cred) { static void setup_files(int client, const sock_cred *cred) {
LOGD("zygisk: setup files for pid=[%d]\n", cred->pid); LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);
char buf[256]; char buf[256];
@ -265,7 +265,7 @@ static void setup_files(int client, ucred *cred) {
int cached_manager_app_id = -1; int cached_manager_app_id = -1;
static time_t last_modified = 0; static time_t last_modified = 0;
static void get_process_info(int client, ucred *cred) { static void get_process_info(int client, const sock_cred *cred) {
AppInfo info{}; AppInfo info{};
int uid = read_int(client); int uid = read_int(client);
string process = read_string(client); string process = read_string(client);
@ -315,7 +315,7 @@ static void get_process_info(int client, ucred *cred) {
} }
} }
static void do_unmount(int client, ucred *cred) { static void do_unmount(int client, const sock_cred *cred) {
if (denylist_enabled) { if (denylist_enabled) {
LOGD("zygisk: cleanup mount namespace for pid=[%d]\n", cred->pid); LOGD("zygisk: cleanup mount namespace for pid=[%d]\n", cred->pid);
revert_daemon(cred->pid, client); revert_daemon(cred->pid, client);
@ -334,7 +334,7 @@ static void send_log_pipe(int fd) {
} }
} }
void zygisk_handler(int client, ucred *cred) { void zygisk_handler(int client, const sock_cred *cred) {
int code = read_int(client); int code = read_int(client);
switch (code) { switch (code) {
case ZYGISK_SETUP: case ZYGISK_SETUP: