diff --git a/native/jni/utils/file.cpp b/native/jni/utils/file.cpp index b23990589..a02cf1515 100644 --- a/native/jni/utils/file.cpp +++ b/native/jni/utils/file.cpp @@ -27,15 +27,17 @@ static int is_excl(const char *name) { return 0; } -int fd_getpath(int fd, char *path, size_t size) { +ssize_t fd_path(int fd, char *path, size_t size) { snprintf(path, size, "/proc/self/fd/%d", fd); - return xreadlink(path, path, size) == -1; + return xreadlink(path, path, size); } -int fd_getpathat(int dirfd, const char *name, char *path, size_t size) { - if (fd_getpath(dirfd, path, size)) - return 1; - snprintf(path, size, "%s/%s", path, name); +int fd_pathat(int dirfd, const char *name, char *path, size_t size) { + ssize_t len = fd_path(dirfd, path, size); + if (len < 0) + return -1; + path[len] = '/'; + strlcpy(&path[len + 1], name, size - len - 1); return 0; } @@ -85,7 +87,7 @@ void rm_rf(const char *path) { if (lstat(path, &st) < 0) return; if (S_ISDIR(st.st_mode)) { - int fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); + int fd = open(path, O_RDONLY | O_CLOEXEC); frm_rf(fd); close(fd); } @@ -211,7 +213,7 @@ void clone_dir(int src, int dest) { case DT_REG: destfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC); srcfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC); - xsendfile(destfd, srcfd, 0, a.st.st_size); + xsendfile(destfd, srcfd, nullptr, a.st.st_size); fsetattr(destfd, &a); close(destfd); close(srcfd); @@ -263,16 +265,21 @@ int getattr(const char *path, struct file_attr *a) { return 0; } -int getattrat(int dirfd, const char *pathname, struct file_attr *a) { - char path[PATH_MAX]; - fd_getpathat(dirfd, pathname, path, sizeof(path)); +int getattrat(int dirfd, const char *name, struct file_attr *a) { + char path[4096]; + fd_pathat(dirfd, name, path, sizeof(path)); return getattr(path, a); } int fgetattr(int fd, struct file_attr *a) { - char path[PATH_MAX]; - fd_getpath(fd, path, sizeof(path)); - return getattr(path, a); + if (xfstat(fd, &a->st) < 0) + return -1; + char *con; + if (fgetfilecon(fd, &con) < 0) + return -1; + strcpy(a->con, con); + freecon(con); + return 0; } int setattr(const char *path, struct file_attr *a) { @@ -280,21 +287,25 @@ int setattr(const char *path, struct file_attr *a) { return -1; if (chown(path, a->st.st_uid, a->st.st_gid) < 0) return -1; - if (strlen(a->con) && lsetfilecon(path, a->con) < 0) + if (a->con[0] && lsetfilecon(path, a->con) < 0) return -1; return 0; } -int setattrat(int dirfd, const char *pathname, struct file_attr *a) { - char path[PATH_MAX]; - fd_getpathat(dirfd, pathname, path, sizeof(path)); +int setattrat(int dirfd, const char *name, struct file_attr *a) { + char path[4096]; + fd_pathat(dirfd, name, path, sizeof(path)); return setattr(path, a); } int fsetattr(int fd, struct file_attr *a) { - char path[PATH_MAX]; - fd_getpath(fd, path, sizeof(path)); - return setattr(path, a); + if (fchmod(fd, a->st.st_mode & 0777) < 0) + return -1; + if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0) + return -1; + if (a->con[0] && fsetfilecon(fd, a->con) < 0) + return -1; + return 0; } void clone_attr(const char *source, const char *target) { @@ -346,17 +357,6 @@ void full_read(const char *filename, void **buf, size_t *size) { close(fd); } -void full_read_at(int dirfd, const char *filename, void **buf, size_t *size) { - int fd = xopenat(dirfd, filename, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - *buf = nullptr; - *size = 0; - return; - } - fd_full_read(fd, buf, size); - close(fd); -} - void write_zero(int fd, size_t size) { char buf[4096] = {0}; size_t len; diff --git a/native/jni/utils/include/selinux.h b/native/jni/utils/include/selinux.h index 11f4bef89..2c29a383a 100644 --- a/native/jni/utils/include/selinux.h +++ b/native/jni/utils/include/selinux.h @@ -4,12 +4,16 @@ extern "C" { #endif -extern void (*freecon)(char * con); -extern int (*setcon)(const char * con); -extern int (*getfilecon)(const char *path, char ** con); -extern int (*lgetfilecon)(const char *path, char ** con); -extern int (*setfilecon)(const char *path, const char * con); -extern int (*lsetfilecon)(const char *path, const char * con); +extern void (*freecon)(char *con); +extern int (*setcon)(const char *con); +extern int (*getfilecon)(const char *path, char **con); +extern int (*lgetfilecon)(const char *path, char **con); +extern int (*fgetfilecon)(int fd, char **con); +extern int (*setfilecon)(const char *path, const char *con); +extern int (*lsetfilecon)(const char *path, const char *con); +extern int (*fsetfilecon)(int fd, const char *con); +void getfilecon_at(int dirfd, const char *name, char **con); +void setfilecon_at(int dirfd, const char *name, const char *con); void selinux_builtin_impl(); void dload_selinux(); diff --git a/native/jni/utils/include/utils.h b/native/jni/utils/include/utils.h index a66a3ec58..534602444 100644 --- a/native/jni/utils/include/utils.h +++ b/native/jni/utils/include/utils.h @@ -51,6 +51,7 @@ int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); int xstat(const char *pathname, struct stat *buf); int xlstat(const char *pathname, struct stat *buf); +int xfstat(int fd, struct stat *buf); int xdup2(int oldfd, int newfd); int xdup3(int oldfd, int newfd, int flags); ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz); @@ -103,8 +104,8 @@ struct file_attr { char con[128]; }; -int fd_getpath(int fd, char *path, size_t size); -int fd_getpathat(int dirfd, const char *name, char *path, size_t size); +ssize_t fd_path(int fd, char *path, size_t size); +int fd_pathat(int dirfd, const char *name, char *path, size_t size); int mkdirs(const char *pathname, mode_t mode); void post_order_walk(int dirfd, void (*fn)(int, struct dirent *)); void rm_rf(const char *path); @@ -115,17 +116,16 @@ void cp_afc(const char *source, const char *destination); void link_dir(int src, int dest); void clone_dir(int src, int dest); int getattr(const char *path, struct file_attr *a); -int getattrat(int dirfd, const char *pathname, struct file_attr *a); +int getattrat(int dirfd, const char *name, struct file_attr *a); int fgetattr(int fd, struct file_attr *a); int setattr(const char *path, struct file_attr *a); -int setattrat(int dirfd, const char *pathname, struct file_attr *a); +int setattrat(int dirfd, const char *name, struct file_attr *a); int fsetattr(int fd, struct file_attr *a); void fclone_attr(int sourcefd, int targetfd); void clone_attr(const char *source, const char *target); void mmap_ro(const char *filename, void **buf, size_t *size); void fd_full_read(int fd, void **buf, size_t *size); void full_read(const char *filename, void **buf, size_t *size); -void full_read_at(int dirfd, const char *filename, void **buf, size_t *size); void write_zero(int fd, size_t size); #ifdef __cplusplus diff --git a/native/jni/utils/selinux.cpp b/native/jni/utils/selinux.cpp index 02aba3d73..3ac5484cc 100644 --- a/native/jni/utils/selinux.cpp +++ b/native/jni/utils/selinux.cpp @@ -25,6 +25,13 @@ static int stub(const char *, char **ctx) { return 0; } +static int stub(int, const char *) { return 0; } + +static int stub(int, char **ctx) { + *ctx = strdup(""); + return 0; +} + // Builtin implementation static void __freecon(char *s) { @@ -44,25 +51,61 @@ static int __setcon(const char *ctx) { static int __getfilecon(const char *path, char **ctx) { char buf[1024]; int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); - if (rc > 0) - *ctx = strdup(buf); + if (rc < 0) { + errno = -rc; + return -1; + } + *ctx = strdup(buf); return rc; } static int __lgetfilecon(const char *path, char **ctx) { char buf[1024]; int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); - if (rc > 0) - *ctx = strdup(buf); + if (rc < 0) { + errno = -rc; + return -1; + } + *ctx = strdup(buf); + return rc; +} + +static int __fgetfilecon(int fd, char **ctx) { + char buf[1024]; + int rc = syscall(__NR_fgetxattr, fd, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); + if (rc < 0) { + errno = -rc; + return -1; + } + *ctx = strdup(buf); return rc; } static int __setfilecon(const char *path, const char *ctx) { - return syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); + int rc = syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); + if (rc) { + errno = -rc; + return -1; + } + return 0; } static int __lsetfilecon(const char *path, const char *ctx) { - return syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); + int rc = syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); + if (rc) { + errno = -rc; + return -1; + } + return 0; +} + +static int __fsetfilecon(int fd, const char *ctx) { + int rc = syscall(__NR_fsetxattr, fd, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); + if (rc) { + errno = -rc; + return -1; + } + return 0; } // Function pointers @@ -71,15 +114,32 @@ void (*freecon)(char *) = __freecon; int (*setcon)(const char *) = stub; int (*getfilecon)(const char *, char **) = stub; int (*lgetfilecon)(const char *, char **) = stub; +int (*fgetfilecon)(int, char **) = stub; int (*setfilecon)(const char *, const char *) = stub; int (*lsetfilecon)(const char *, const char *) = stub; +int (*fsetfilecon)(int, const char *) = stub; + +void getfilecon_at(int dirfd, const char *name, char **con) { + char path[4096]; + fd_pathat(dirfd, name, path, sizeof(path)); + if (lgetfilecon(path, con)) + *con = strdup(""); +} + +void setfilecon_at(int dirfd, const char *name, const char *con) { + char path[4096]; + fd_pathat(dirfd, name, path, sizeof(path)); + lsetfilecon(path, con); +} void selinux_builtin_impl() { setcon = __setcon; getfilecon = __getfilecon; lgetfilecon = __lgetfilecon; + fgetfilecon = __fgetfilecon; setfilecon = __setfilecon; lsetfilecon = __lsetfilecon; + fsetfilecon = __fsetfilecon; } void dload_selinux() { @@ -95,33 +155,32 @@ void dload_selinux() { static void restore_syscon(int dirfd) { struct dirent *entry; DIR *dir; + char *con; - char path[PATH_MAX], *con; - - fd_getpath(dirfd, path, sizeof(path)); - size_t len = strlen(path); - getfilecon(path, &con); + fgetfilecon(dirfd, &con); if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0) - lsetfilecon(path, SYSTEM_CON); + fsetfilecon(dirfd, SYSTEM_CON); freecon(con); dir = xfdopendir(dirfd); while ((entry = xreaddir(dir))) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); if (entry->d_type == DT_DIR) { - int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); restore_syscon(fd); - close(fd); - } else { - path[len] = '/'; - strcpy(path + len + 1, entry->d_name); - lgetfilecon(path, &con); - if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0) - lsetfilecon(path, SYSTEM_CON); + } else if (entry->d_type == DT_REG) { + fgetfilecon(fd, &con); + if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0) + fsetfilecon(fd, SYSTEM_CON); + freecon(con); + } else if (entry->d_type == DT_LNK) { + getfilecon_at(dirfd, entry->d_name, &con); + if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0) + setfilecon_at(dirfd, entry->d_name, con); freecon(con); - path[len] = '\0'; } + close(fd); } } @@ -129,28 +188,21 @@ static void restore_magiskcon(int dirfd) { struct dirent *entry; DIR *dir; - char path[PATH_MAX]; - - fd_getpath(dirfd, path, sizeof(path)); - size_t len = strlen(path); - lsetfilecon(path, MAGISK_CON); - lchown(path, 0, 0); + fsetfilecon(dirfd, MAGISK_CON); + fchown(dirfd, 0, 0); dir = xfdopendir(dirfd); while ((entry = xreaddir(dir))) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); if (entry->d_type == DT_DIR) { - int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); restore_magiskcon(fd); - close(fd); - } else { - path[len] = '/'; - strcpy(path + len + 1, entry->d_name); - lsetfilecon(path, MAGISK_CON); - lchown(path, 0, 0); - path[len] = '\0'; + } else if (entry->d_type) { + fsetfilecon(fd, MAGISK_CON); + fchown(fd, 0, 0); } + close(fd); } } diff --git a/native/jni/utils/xwrap.cpp b/native/jni/utils/xwrap.cpp index 8f2319dcf..de14ff454 100644 --- a/native/jni/utils/xwrap.cpp +++ b/native/jni/utils/xwrap.cpp @@ -262,6 +262,14 @@ int xlstat(const char *pathname, struct stat *buf) { return ret; } +int xfstat(int fd, struct stat *buf) { + int ret = fstat(fd, buf); + if (ret == -1) { + PLOGE("fstat %d", fd); + } + return ret; +} + int xdup2(int oldfd, int newfd) { int ret = dup2(oldfd, newfd); if (ret == -1) {