Improve builtin selinux implementation

This commit is contained in:
topjohnwu 2019-03-14 06:34:22 -04:00
parent b7e2e972c7
commit da0a72e8b0
5 changed files with 142 additions and 78 deletions

View File

@ -27,15 +27,17 @@ static int is_excl(const char *name) {
return 0; 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); 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) { int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
if (fd_getpath(dirfd, path, size)) ssize_t len = fd_path(dirfd, path, size);
return 1; if (len < 0)
snprintf(path, size, "%s/%s", path, name); return -1;
path[len] = '/';
strlcpy(&path[len + 1], name, size - len - 1);
return 0; return 0;
} }
@ -85,7 +87,7 @@ void rm_rf(const char *path) {
if (lstat(path, &st) < 0) if (lstat(path, &st) < 0)
return; return;
if (S_ISDIR(st.st_mode)) { 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); frm_rf(fd);
close(fd); close(fd);
} }
@ -211,7 +213,7 @@ void clone_dir(int src, int dest) {
case DT_REG: case DT_REG:
destfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC); destfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC);
srcfd = xopenat(src, entry->d_name, O_RDONLY | 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); fsetattr(destfd, &a);
close(destfd); close(destfd);
close(srcfd); close(srcfd);
@ -263,16 +265,21 @@ int getattr(const char *path, struct file_attr *a) {
return 0; return 0;
} }
int getattrat(int dirfd, const char *pathname, struct file_attr *a) { int getattrat(int dirfd, const char *name, struct file_attr *a) {
char path[PATH_MAX]; char path[4096];
fd_getpathat(dirfd, pathname, path, sizeof(path)); fd_pathat(dirfd, name, path, sizeof(path));
return getattr(path, a); return getattr(path, a);
} }
int fgetattr(int fd, struct file_attr *a) { int fgetattr(int fd, struct file_attr *a) {
char path[PATH_MAX]; if (xfstat(fd, &a->st) < 0)
fd_getpath(fd, path, sizeof(path)); return -1;
return getattr(path, a); 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) { int setattr(const char *path, struct file_attr *a) {
@ -280,21 +287,25 @@ int setattr(const char *path, struct file_attr *a) {
return -1; return -1;
if (chown(path, a->st.st_uid, a->st.st_gid) < 0) if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
return -1; return -1;
if (strlen(a->con) && lsetfilecon(path, a->con) < 0) if (a->con[0] && lsetfilecon(path, a->con) < 0)
return -1; return -1;
return 0; return 0;
} }
int setattrat(int dirfd, const char *pathname, struct file_attr *a) { int setattrat(int dirfd, const char *name, struct file_attr *a) {
char path[PATH_MAX]; char path[4096];
fd_getpathat(dirfd, pathname, path, sizeof(path)); fd_pathat(dirfd, name, path, sizeof(path));
return setattr(path, a); return setattr(path, a);
} }
int fsetattr(int fd, struct file_attr *a) { int fsetattr(int fd, struct file_attr *a) {
char path[PATH_MAX]; if (fchmod(fd, a->st.st_mode & 0777) < 0)
fd_getpath(fd, path, sizeof(path)); return -1;
return setattr(path, a); 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) { 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); 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) { void write_zero(int fd, size_t size) {
char buf[4096] = {0}; char buf[4096] = {0};
size_t len; size_t len;

View File

@ -8,8 +8,12 @@ extern void (*freecon)(char * con);
extern int (*setcon)(const char *con); extern int (*setcon)(const char *con);
extern int (*getfilecon)(const char *path, char **con); extern int (*getfilecon)(const char *path, char **con);
extern int (*lgetfilecon)(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 (*setfilecon)(const char *path, const char *con);
extern int (*lsetfilecon)(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 selinux_builtin_impl();
void dload_selinux(); void dload_selinux();

View File

@ -51,6 +51,7 @@ int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg); void *(*start_routine) (void *), void *arg);
int xstat(const char *pathname, struct stat *buf); int xstat(const char *pathname, struct stat *buf);
int xlstat(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 xdup2(int oldfd, int newfd);
int xdup3(int oldfd, int newfd, int flags); int xdup3(int oldfd, int newfd, int flags);
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz); ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz);
@ -103,8 +104,8 @@ struct file_attr {
char con[128]; char con[128];
}; };
int fd_getpath(int fd, char *path, size_t size); ssize_t fd_path(int fd, char *path, size_t size);
int fd_getpathat(int dirfd, const char *name, 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); int mkdirs(const char *pathname, mode_t mode);
void post_order_walk(int dirfd, void (*fn)(int, struct dirent *)); void post_order_walk(int dirfd, void (*fn)(int, struct dirent *));
void rm_rf(const char *path); 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 link_dir(int src, int dest);
void clone_dir(int src, int dest); void clone_dir(int src, int dest);
int getattr(const char *path, struct file_attr *a); 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 fgetattr(int fd, struct file_attr *a);
int setattr(const char *path, 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); int fsetattr(int fd, struct file_attr *a);
void fclone_attr(int sourcefd, int targetfd); void fclone_attr(int sourcefd, int targetfd);
void clone_attr(const char *source, const char *target); void clone_attr(const char *source, const char *target);
void mmap_ro(const char *filename, void **buf, size_t *size); void mmap_ro(const char *filename, void **buf, size_t *size);
void fd_full_read(int fd, 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(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); void write_zero(int fd, size_t size);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -25,6 +25,13 @@ static int stub(const char *, char **ctx) {
return 0; return 0;
} }
static int stub(int, const char *) { return 0; }
static int stub(int, char **ctx) {
*ctx = strdup("");
return 0;
}
// Builtin implementation // Builtin implementation
static void __freecon(char *s) { static void __freecon(char *s) {
@ -44,7 +51,10 @@ static int __setcon(const char *ctx) {
static int __getfilecon(const char *path, char **ctx) { static int __getfilecon(const char *path, char **ctx) {
char buf[1024]; char buf[1024];
int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
if (rc > 0) if (rc < 0) {
errno = -rc;
return -1;
}
*ctx = strdup(buf); *ctx = strdup(buf);
return rc; return rc;
} }
@ -52,17 +62,50 @@ static int __getfilecon(const char *path, char **ctx) {
static int __lgetfilecon(const char *path, char **ctx) { static int __lgetfilecon(const char *path, char **ctx) {
char buf[1024]; char buf[1024];
int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
if (rc > 0) 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); *ctx = strdup(buf);
return rc; return rc;
} }
static int __setfilecon(const char *path, const char *ctx) { 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) { 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 // Function pointers
@ -71,15 +114,32 @@ void (*freecon)(char *) = __freecon;
int (*setcon)(const char *) = stub; int (*setcon)(const char *) = stub;
int (*getfilecon)(const char *, char **) = stub; int (*getfilecon)(const char *, char **) = stub;
int (*lgetfilecon)(const char *, char **) = stub; int (*lgetfilecon)(const char *, char **) = stub;
int (*fgetfilecon)(int, char **) = stub;
int (*setfilecon)(const char *, const char *) = stub; int (*setfilecon)(const char *, const char *) = stub;
int (*lsetfilecon)(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() { void selinux_builtin_impl() {
setcon = __setcon; setcon = __setcon;
getfilecon = __getfilecon; getfilecon = __getfilecon;
lgetfilecon = __lgetfilecon; lgetfilecon = __lgetfilecon;
fgetfilecon = __fgetfilecon;
setfilecon = __setfilecon; setfilecon = __setfilecon;
lsetfilecon = __lsetfilecon; lsetfilecon = __lsetfilecon;
fsetfilecon = __fsetfilecon;
} }
void dload_selinux() { void dload_selinux() {
@ -95,33 +155,32 @@ void dload_selinux() {
static void restore_syscon(int dirfd) { static void restore_syscon(int dirfd) {
struct dirent *entry; struct dirent *entry;
DIR *dir; DIR *dir;
char *con;
char path[PATH_MAX], *con; fgetfilecon(dirfd, &con);
fd_getpath(dirfd, path, sizeof(path));
size_t len = strlen(path);
getfilecon(path, &con);
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0) if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
lsetfilecon(path, SYSTEM_CON); fsetfilecon(dirfd, SYSTEM_CON);
freecon(con); freecon(con);
dir = xfdopendir(dirfd); dir = xfdopendir(dirfd);
while ((entry = xreaddir(dir))) { while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue; continue;
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
restore_syscon(fd); restore_syscon(fd);
close(fd); } else if (entry->d_type == DT_REG) {
} else { fgetfilecon(fd, &con);
path[len] = '/'; if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
strcpy(path + len + 1, entry->d_name); fsetfilecon(fd, SYSTEM_CON);
lgetfilecon(path, &con); freecon(con);
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0) } else if (entry->d_type == DT_LNK) {
lsetfilecon(path, SYSTEM_CON); 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); freecon(con);
path[len] = '\0';
} }
close(fd);
} }
} }
@ -129,28 +188,21 @@ static void restore_magiskcon(int dirfd) {
struct dirent *entry; struct dirent *entry;
DIR *dir; DIR *dir;
char path[PATH_MAX]; fsetfilecon(dirfd, MAGISK_CON);
fchown(dirfd, 0, 0);
fd_getpath(dirfd, path, sizeof(path));
size_t len = strlen(path);
lsetfilecon(path, MAGISK_CON);
lchown(path, 0, 0);
dir = xfdopendir(dirfd); dir = xfdopendir(dirfd);
while ((entry = xreaddir(dir))) { while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue; continue;
if (entry->d_type == DT_DIR) {
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_magiskcon(fd); restore_magiskcon(fd);
close(fd); } else if (entry->d_type) {
} else { fsetfilecon(fd, MAGISK_CON);
path[len] = '/'; fchown(fd, 0, 0);
strcpy(path + len + 1, entry->d_name);
lsetfilecon(path, MAGISK_CON);
lchown(path, 0, 0);
path[len] = '\0';
} }
close(fd);
} }
} }

View File

@ -262,6 +262,14 @@ int xlstat(const char *pathname, struct stat *buf) {
return ret; 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 xdup2(int oldfd, int newfd) {
int ret = dup2(oldfd, newfd); int ret = dup2(oldfd, newfd);
if (ret == -1) { if (ret == -1) {