/* socket.c - All socket related operations */ #include #include "daemon.h" #include "logging.h" #include "utils.h" #include "magisk.h" char socket_name[] = SOCKET_NAME; /* Setup the address and return socket fd */ int setup_socket(struct sockaddr_un *sun) { int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); memset(sun, 0, sizeof(*sun)); sun->sun_family = AF_LOCAL; sun->sun_path[0] = '\0'; memcpy(sun->sun_path + 1, socket_name, sizeof(SOCKET_NAME)); return fd; } /* * Receive a file descriptor from a Unix socket. * Contributed by @mkasick * * Returns the file descriptor on success, or -1 if a file * descriptor was not actually included in the message * * On error the function terminates by calling exit(-1) */ int recv_fd(int sockfd) { // Need to receive data from the message, otherwise don't care about it. char iovbuf; struct iovec iov = { .iov_base = &iovbuf, .iov_len = 1, }; char cmsgbuf[CMSG_SPACE(sizeof(int))]; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsgbuf, .msg_controllen = sizeof(cmsgbuf), }; xrecvmsg(sockfd, &msg, MSG_WAITALL); // Was a control message actually sent? switch (msg.msg_controllen) { case 0: // No, so the file descriptor was closed and won't be used. return -1; case sizeof(cmsgbuf): // Yes, grab the file descriptor from it. break; default: goto error; } struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { error: LOGE("unable to read fd"); exit(-1); } return *(int *)CMSG_DATA(cmsg); } /* * Send a file descriptor through a Unix socket. * Contributed by @mkasick * * On error the function terminates by calling exit(-1) * * fd may be -1, in which case the dummy data is sent, * but no control message with the FD is sent. */ void send_fd(int sockfd, int fd) { // Need to send some data in the message, this will do. struct iovec iov = { .iov_base = "", .iov_len = 1, }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, }; char cmsgbuf[CMSG_SPACE(sizeof(int))]; if (fd != -1) { // Is the file descriptor actually open? if (fcntl(fd, F_GETFD) == -1) { if (errno != EBADF) { PLOGE("unable to send fd"); } // It's closed, don't send a control message or sendmsg will EBADF. } else { // It's open, send the file descriptor in a control message. msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = fd; } } xsendmsg(sockfd, &msg, 0); } int read_int(int fd) { int val; xxread(fd, &val, sizeof(int)); return val; } void write_int(int fd, int val) { if (fd < 0) return; xwrite(fd, &val, sizeof(int)); } char* read_string(int fd) { int len = read_int(fd); if (len > PATH_MAX || len < 0) { LOGE("invalid string length %d", len); exit(1); } char* val = xmalloc(sizeof(char) * (len + 1)); xxread(fd, val, len); val[len] = '\0'; return val; } void write_string(int fd, const char* val) { if (fd < 0) return; int len = strlen(val); write_int(fd, len); xwrite(fd, val, len); }