16cd6a6acSopenharmony_ci#include <sys/syscall.h> 26cd6a6acSopenharmony_ci#include <unistd.h> 36cd6a6acSopenharmony_ci#include <fcntl.h> 46cd6a6acSopenharmony_ci#include <pthread.h> 56cd6a6acSopenharmony_ci#include <string.h> 66cd6a6acSopenharmony_ci#include <stdlib.h> 76cd6a6acSopenharmony_ci#include <stdio.h> 86cd6a6acSopenharmony_ci#include <errno.h> 96cd6a6acSopenharmony_ci#include "selinux_internal.h" 106cd6a6acSopenharmony_ci#include "policy.h" 116cd6a6acSopenharmony_ci 126cd6a6acSopenharmony_ci#define UNSET (char *) -1 136cd6a6acSopenharmony_ci 146cd6a6acSopenharmony_cistatic __thread char *prev_current = UNSET; 156cd6a6acSopenharmony_cistatic __thread char * prev_exec = UNSET; 166cd6a6acSopenharmony_cistatic __thread char * prev_fscreate = UNSET; 176cd6a6acSopenharmony_cistatic __thread char * prev_keycreate = UNSET; 186cd6a6acSopenharmony_cistatic __thread char * prev_sockcreate = UNSET; 196cd6a6acSopenharmony_ci 206cd6a6acSopenharmony_cistatic pthread_once_t once = PTHREAD_ONCE_INIT; 216cd6a6acSopenharmony_cistatic pthread_key_t destructor_key; 226cd6a6acSopenharmony_cistatic int destructor_key_initialized = 0; 236cd6a6acSopenharmony_cistatic __thread char destructor_initialized; 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci/* Bionic and glibc >= 2.30 declare gettid() system call wrapper in unistd.h and 266cd6a6acSopenharmony_ci * has a definition for it */ 276cd6a6acSopenharmony_ci#ifdef __BIONIC__ 286cd6a6acSopenharmony_ci #define HAVE_GETTID 1 296cd6a6acSopenharmony_ci#elif !defined(__GLIBC_PREREQ) 306cd6a6acSopenharmony_ci #define HAVE_GETTID 0 316cd6a6acSopenharmony_ci#elif !__GLIBC_PREREQ(2,30) 326cd6a6acSopenharmony_ci #define HAVE_GETTID 0 336cd6a6acSopenharmony_ci#else 346cd6a6acSopenharmony_ci #define HAVE_GETTID 1 356cd6a6acSopenharmony_ci#endif 366cd6a6acSopenharmony_ci 376cd6a6acSopenharmony_cistatic pid_t selinux_gettid(void) 386cd6a6acSopenharmony_ci{ 396cd6a6acSopenharmony_ci#if HAVE_GETTID 406cd6a6acSopenharmony_ci return gettid(); 416cd6a6acSopenharmony_ci#else 426cd6a6acSopenharmony_ci return syscall(__NR_gettid); 436cd6a6acSopenharmony_ci#endif 446cd6a6acSopenharmony_ci} 456cd6a6acSopenharmony_ci 466cd6a6acSopenharmony_cistatic void procattr_thread_destructor(void __attribute__((unused)) *unused) 476cd6a6acSopenharmony_ci{ 486cd6a6acSopenharmony_ci if (prev_current != UNSET) 496cd6a6acSopenharmony_ci free(prev_current); 506cd6a6acSopenharmony_ci if (prev_exec != UNSET) 516cd6a6acSopenharmony_ci free(prev_exec); 526cd6a6acSopenharmony_ci if (prev_fscreate != UNSET) 536cd6a6acSopenharmony_ci free(prev_fscreate); 546cd6a6acSopenharmony_ci if (prev_keycreate != UNSET) 556cd6a6acSopenharmony_ci free(prev_keycreate); 566cd6a6acSopenharmony_ci if (prev_sockcreate != UNSET) 576cd6a6acSopenharmony_ci free(prev_sockcreate); 586cd6a6acSopenharmony_ci} 596cd6a6acSopenharmony_ci 606cd6a6acSopenharmony_civoid __attribute__((destructor)) procattr_destructor(void); 616cd6a6acSopenharmony_ci 626cd6a6acSopenharmony_civoid __attribute__((destructor)) procattr_destructor(void) 636cd6a6acSopenharmony_ci{ 646cd6a6acSopenharmony_ci if (destructor_key_initialized) 656cd6a6acSopenharmony_ci __selinux_key_delete(destructor_key); 666cd6a6acSopenharmony_ci} 676cd6a6acSopenharmony_ci 686cd6a6acSopenharmony_cistatic inline void init_thread_destructor(void) 696cd6a6acSopenharmony_ci{ 706cd6a6acSopenharmony_ci if (destructor_initialized == 0) { 716cd6a6acSopenharmony_ci __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size); 726cd6a6acSopenharmony_ci destructor_initialized = 1; 736cd6a6acSopenharmony_ci } 746cd6a6acSopenharmony_ci} 756cd6a6acSopenharmony_ci 766cd6a6acSopenharmony_cistatic void init_procattr(void) 776cd6a6acSopenharmony_ci{ 786cd6a6acSopenharmony_ci if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) { 796cd6a6acSopenharmony_ci destructor_key_initialized = 1; 806cd6a6acSopenharmony_ci } 816cd6a6acSopenharmony_ci} 826cd6a6acSopenharmony_ci 836cd6a6acSopenharmony_cistatic int openattr(pid_t pid, const char *attr, int flags) 846cd6a6acSopenharmony_ci{ 856cd6a6acSopenharmony_ci int fd, rc; 866cd6a6acSopenharmony_ci char *path; 876cd6a6acSopenharmony_ci pid_t tid; 886cd6a6acSopenharmony_ci 896cd6a6acSopenharmony_ci if (pid > 0) { 906cd6a6acSopenharmony_ci rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr); 916cd6a6acSopenharmony_ci } else if (pid == 0) { 926cd6a6acSopenharmony_ci rc = asprintf(&path, "/proc/thread-self/attr/%s", attr); 936cd6a6acSopenharmony_ci if (rc < 0) 946cd6a6acSopenharmony_ci return -1; 956cd6a6acSopenharmony_ci fd = open(path, flags | O_CLOEXEC); 966cd6a6acSopenharmony_ci if (fd >= 0 || errno != ENOENT) 976cd6a6acSopenharmony_ci goto out; 986cd6a6acSopenharmony_ci free(path); 996cd6a6acSopenharmony_ci tid = selinux_gettid(); 1006cd6a6acSopenharmony_ci rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr); 1016cd6a6acSopenharmony_ci } else { 1026cd6a6acSopenharmony_ci errno = EINVAL; 1036cd6a6acSopenharmony_ci return -1; 1046cd6a6acSopenharmony_ci } 1056cd6a6acSopenharmony_ci if (rc < 0) 1066cd6a6acSopenharmony_ci return -1; 1076cd6a6acSopenharmony_ci 1086cd6a6acSopenharmony_ci fd = open(path, flags | O_CLOEXEC); 1096cd6a6acSopenharmony_ciout: 1106cd6a6acSopenharmony_ci free(path); 1116cd6a6acSopenharmony_ci return fd; 1126cd6a6acSopenharmony_ci} 1136cd6a6acSopenharmony_ci 1146cd6a6acSopenharmony_cistatic int getprocattrcon_raw(char ** context, 1156cd6a6acSopenharmony_ci pid_t pid, const char *attr) 1166cd6a6acSopenharmony_ci{ 1176cd6a6acSopenharmony_ci char *buf; 1186cd6a6acSopenharmony_ci size_t size; 1196cd6a6acSopenharmony_ci int fd; 1206cd6a6acSopenharmony_ci ssize_t ret; 1216cd6a6acSopenharmony_ci int errno_hold; 1226cd6a6acSopenharmony_ci char * prev_context; 1236cd6a6acSopenharmony_ci 1246cd6a6acSopenharmony_ci __selinux_once(once, init_procattr); 1256cd6a6acSopenharmony_ci init_thread_destructor(); 1266cd6a6acSopenharmony_ci 1276cd6a6acSopenharmony_ci switch (attr[0]) { 1286cd6a6acSopenharmony_ci case 'c': 1296cd6a6acSopenharmony_ci prev_context = NULL; 1306cd6a6acSopenharmony_ci break; 1316cd6a6acSopenharmony_ci case 'e': 1326cd6a6acSopenharmony_ci prev_context = prev_exec; 1336cd6a6acSopenharmony_ci break; 1346cd6a6acSopenharmony_ci case 'f': 1356cd6a6acSopenharmony_ci prev_context = prev_fscreate; 1366cd6a6acSopenharmony_ci break; 1376cd6a6acSopenharmony_ci case 'k': 1386cd6a6acSopenharmony_ci prev_context = prev_keycreate; 1396cd6a6acSopenharmony_ci break; 1406cd6a6acSopenharmony_ci case 's': 1416cd6a6acSopenharmony_ci prev_context = prev_sockcreate; 1426cd6a6acSopenharmony_ci break; 1436cd6a6acSopenharmony_ci case 'p': 1446cd6a6acSopenharmony_ci prev_context = NULL; 1456cd6a6acSopenharmony_ci break; 1466cd6a6acSopenharmony_ci default: 1476cd6a6acSopenharmony_ci errno = ENOENT; 1486cd6a6acSopenharmony_ci return -1; 1496cd6a6acSopenharmony_ci } 1506cd6a6acSopenharmony_ci 1516cd6a6acSopenharmony_ci if (prev_context && prev_context != UNSET) { 1526cd6a6acSopenharmony_ci *context = strdup(prev_context); 1536cd6a6acSopenharmony_ci if (!(*context)) { 1546cd6a6acSopenharmony_ci return -1; 1556cd6a6acSopenharmony_ci } 1566cd6a6acSopenharmony_ci return 0; 1576cd6a6acSopenharmony_ci } 1586cd6a6acSopenharmony_ci 1596cd6a6acSopenharmony_ci fd = openattr(pid, attr, O_RDONLY | O_CLOEXEC); 1606cd6a6acSopenharmony_ci if (fd < 0) 1616cd6a6acSopenharmony_ci return -1; 1626cd6a6acSopenharmony_ci 1636cd6a6acSopenharmony_ci size = selinux_page_size; 1646cd6a6acSopenharmony_ci buf = malloc(size); 1656cd6a6acSopenharmony_ci if (!buf) { 1666cd6a6acSopenharmony_ci ret = -1; 1676cd6a6acSopenharmony_ci goto out; 1686cd6a6acSopenharmony_ci } 1696cd6a6acSopenharmony_ci memset(buf, 0, size); 1706cd6a6acSopenharmony_ci 1716cd6a6acSopenharmony_ci do { 1726cd6a6acSopenharmony_ci ret = read(fd, buf, size - 1); 1736cd6a6acSopenharmony_ci } while (ret < 0 && errno == EINTR); 1746cd6a6acSopenharmony_ci if (ret < 0) 1756cd6a6acSopenharmony_ci goto out2; 1766cd6a6acSopenharmony_ci 1776cd6a6acSopenharmony_ci if (ret == 0) { 1786cd6a6acSopenharmony_ci *context = NULL; 1796cd6a6acSopenharmony_ci goto out2; 1806cd6a6acSopenharmony_ci } 1816cd6a6acSopenharmony_ci 1826cd6a6acSopenharmony_ci *context = strdup(buf); 1836cd6a6acSopenharmony_ci if (!(*context)) { 1846cd6a6acSopenharmony_ci ret = -1; 1856cd6a6acSopenharmony_ci goto out2; 1866cd6a6acSopenharmony_ci } 1876cd6a6acSopenharmony_ci ret = 0; 1886cd6a6acSopenharmony_ci out2: 1896cd6a6acSopenharmony_ci free(buf); 1906cd6a6acSopenharmony_ci out: 1916cd6a6acSopenharmony_ci errno_hold = errno; 1926cd6a6acSopenharmony_ci close(fd); 1936cd6a6acSopenharmony_ci errno = errno_hold; 1946cd6a6acSopenharmony_ci return ret; 1956cd6a6acSopenharmony_ci} 1966cd6a6acSopenharmony_ci 1976cd6a6acSopenharmony_cistatic int getprocattrcon(char ** context, 1986cd6a6acSopenharmony_ci pid_t pid, const char *attr) 1996cd6a6acSopenharmony_ci{ 2006cd6a6acSopenharmony_ci int ret; 2016cd6a6acSopenharmony_ci char * rcontext; 2026cd6a6acSopenharmony_ci 2036cd6a6acSopenharmony_ci ret = getprocattrcon_raw(&rcontext, pid, attr); 2046cd6a6acSopenharmony_ci 2056cd6a6acSopenharmony_ci if (!ret) { 2066cd6a6acSopenharmony_ci ret = selinux_raw_to_trans_context(rcontext, context); 2076cd6a6acSopenharmony_ci freecon(rcontext); 2086cd6a6acSopenharmony_ci } 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci return ret; 2116cd6a6acSopenharmony_ci} 2126cd6a6acSopenharmony_ci 2136cd6a6acSopenharmony_cistatic int setprocattrcon_raw(const char * context, 2146cd6a6acSopenharmony_ci pid_t pid, const char *attr) 2156cd6a6acSopenharmony_ci{ 2166cd6a6acSopenharmony_ci int fd; 2176cd6a6acSopenharmony_ci ssize_t ret; 2186cd6a6acSopenharmony_ci int errno_hold; 2196cd6a6acSopenharmony_ci char **prev_context, *context2 = NULL; 2206cd6a6acSopenharmony_ci 2216cd6a6acSopenharmony_ci __selinux_once(once, init_procattr); 2226cd6a6acSopenharmony_ci init_thread_destructor(); 2236cd6a6acSopenharmony_ci 2246cd6a6acSopenharmony_ci switch (attr[0]) { 2256cd6a6acSopenharmony_ci case 'c': 2266cd6a6acSopenharmony_ci prev_context = &prev_current; 2276cd6a6acSopenharmony_ci break; 2286cd6a6acSopenharmony_ci case 'e': 2296cd6a6acSopenharmony_ci prev_context = &prev_exec; 2306cd6a6acSopenharmony_ci break; 2316cd6a6acSopenharmony_ci case 'f': 2326cd6a6acSopenharmony_ci prev_context = &prev_fscreate; 2336cd6a6acSopenharmony_ci break; 2346cd6a6acSopenharmony_ci case 'k': 2356cd6a6acSopenharmony_ci prev_context = &prev_keycreate; 2366cd6a6acSopenharmony_ci break; 2376cd6a6acSopenharmony_ci case 's': 2386cd6a6acSopenharmony_ci prev_context = &prev_sockcreate; 2396cd6a6acSopenharmony_ci break; 2406cd6a6acSopenharmony_ci default: 2416cd6a6acSopenharmony_ci errno = ENOENT; 2426cd6a6acSopenharmony_ci return -1; 2436cd6a6acSopenharmony_ci } 2446cd6a6acSopenharmony_ci 2456cd6a6acSopenharmony_ci if (!context && !*prev_context) 2466cd6a6acSopenharmony_ci return 0; 2476cd6a6acSopenharmony_ci if (context && *prev_context && *prev_context != UNSET 2486cd6a6acSopenharmony_ci && !strcmp(context, *prev_context)) 2496cd6a6acSopenharmony_ci return 0; 2506cd6a6acSopenharmony_ci 2516cd6a6acSopenharmony_ci fd = openattr(pid, attr, O_RDWR | O_CLOEXEC); 2526cd6a6acSopenharmony_ci if (fd < 0) 2536cd6a6acSopenharmony_ci return -1; 2546cd6a6acSopenharmony_ci if (context) { 2556cd6a6acSopenharmony_ci ret = -1; 2566cd6a6acSopenharmony_ci context2 = strdup(context); 2576cd6a6acSopenharmony_ci if (!context2) 2586cd6a6acSopenharmony_ci goto out; 2596cd6a6acSopenharmony_ci do { 2606cd6a6acSopenharmony_ci ret = write(fd, context2, strlen(context2) + 1); 2616cd6a6acSopenharmony_ci } while (ret < 0 && errno == EINTR); 2626cd6a6acSopenharmony_ci } else { 2636cd6a6acSopenharmony_ci do { 2646cd6a6acSopenharmony_ci ret = write(fd, NULL, 0); /* clear */ 2656cd6a6acSopenharmony_ci } while (ret < 0 && errno == EINTR); 2666cd6a6acSopenharmony_ci } 2676cd6a6acSopenharmony_ciout: 2686cd6a6acSopenharmony_ci errno_hold = errno; 2696cd6a6acSopenharmony_ci close(fd); 2706cd6a6acSopenharmony_ci errno = errno_hold; 2716cd6a6acSopenharmony_ci if (ret < 0) { 2726cd6a6acSopenharmony_ci free(context2); 2736cd6a6acSopenharmony_ci return -1; 2746cd6a6acSopenharmony_ci } else { 2756cd6a6acSopenharmony_ci if (*prev_context != UNSET) 2766cd6a6acSopenharmony_ci free(*prev_context); 2776cd6a6acSopenharmony_ci *prev_context = context2; 2786cd6a6acSopenharmony_ci return 0; 2796cd6a6acSopenharmony_ci } 2806cd6a6acSopenharmony_ci} 2816cd6a6acSopenharmony_ci 2826cd6a6acSopenharmony_cistatic int setprocattrcon(const char * context, 2836cd6a6acSopenharmony_ci pid_t pid, const char *attr) 2846cd6a6acSopenharmony_ci{ 2856cd6a6acSopenharmony_ci int ret; 2866cd6a6acSopenharmony_ci char * rcontext; 2876cd6a6acSopenharmony_ci 2886cd6a6acSopenharmony_ci if (selinux_trans_to_raw_context(context, &rcontext)) 2896cd6a6acSopenharmony_ci return -1; 2906cd6a6acSopenharmony_ci 2916cd6a6acSopenharmony_ci ret = setprocattrcon_raw(rcontext, pid, attr); 2926cd6a6acSopenharmony_ci 2936cd6a6acSopenharmony_ci freecon(rcontext); 2946cd6a6acSopenharmony_ci 2956cd6a6acSopenharmony_ci return ret; 2966cd6a6acSopenharmony_ci} 2976cd6a6acSopenharmony_ci 2986cd6a6acSopenharmony_ci#define getselfattr_def(fn, attr) \ 2996cd6a6acSopenharmony_ci int get##fn##_raw(char **c) \ 3006cd6a6acSopenharmony_ci { \ 3016cd6a6acSopenharmony_ci return getprocattrcon_raw(c, 0, #attr); \ 3026cd6a6acSopenharmony_ci } \ 3036cd6a6acSopenharmony_ci int get##fn(char **c) \ 3046cd6a6acSopenharmony_ci { \ 3056cd6a6acSopenharmony_ci return getprocattrcon(c, 0, #attr); \ 3066cd6a6acSopenharmony_ci } 3076cd6a6acSopenharmony_ci 3086cd6a6acSopenharmony_ci#define setselfattr_def(fn, attr) \ 3096cd6a6acSopenharmony_ci int set##fn##_raw(const char * c) \ 3106cd6a6acSopenharmony_ci { \ 3116cd6a6acSopenharmony_ci return setprocattrcon_raw(c, 0, #attr); \ 3126cd6a6acSopenharmony_ci } \ 3136cd6a6acSopenharmony_ci int set##fn(const char * c) \ 3146cd6a6acSopenharmony_ci { \ 3156cd6a6acSopenharmony_ci return setprocattrcon(c, 0, #attr); \ 3166cd6a6acSopenharmony_ci } 3176cd6a6acSopenharmony_ci 3186cd6a6acSopenharmony_ci#define all_selfattr_def(fn, attr) \ 3196cd6a6acSopenharmony_ci getselfattr_def(fn, attr) \ 3206cd6a6acSopenharmony_ci setselfattr_def(fn, attr) 3216cd6a6acSopenharmony_ci 3226cd6a6acSopenharmony_ci#define getpidattr_def(fn, attr) \ 3236cd6a6acSopenharmony_ci int get##fn##_raw(pid_t pid, char **c) \ 3246cd6a6acSopenharmony_ci { \ 3256cd6a6acSopenharmony_ci if (pid <= 0) { \ 3266cd6a6acSopenharmony_ci errno = EINVAL; \ 3276cd6a6acSopenharmony_ci return -1; \ 3286cd6a6acSopenharmony_ci } else { \ 3296cd6a6acSopenharmony_ci return getprocattrcon_raw(c, pid, #attr); \ 3306cd6a6acSopenharmony_ci } \ 3316cd6a6acSopenharmony_ci } \ 3326cd6a6acSopenharmony_ci int get##fn(pid_t pid, char **c) \ 3336cd6a6acSopenharmony_ci { \ 3346cd6a6acSopenharmony_ci if (pid <= 0) { \ 3356cd6a6acSopenharmony_ci errno = EINVAL; \ 3366cd6a6acSopenharmony_ci return -1; \ 3376cd6a6acSopenharmony_ci } else { \ 3386cd6a6acSopenharmony_ci return getprocattrcon(c, pid, #attr); \ 3396cd6a6acSopenharmony_ci } \ 3406cd6a6acSopenharmony_ci } 3416cd6a6acSopenharmony_ci 3426cd6a6acSopenharmony_ciall_selfattr_def(con, current) 3436cd6a6acSopenharmony_ci getpidattr_def(pidcon, current) 3446cd6a6acSopenharmony_ci getselfattr_def(prevcon, prev) 3456cd6a6acSopenharmony_ci all_selfattr_def(execcon, exec) 3466cd6a6acSopenharmony_ci all_selfattr_def(fscreatecon, fscreate) 3476cd6a6acSopenharmony_ci all_selfattr_def(sockcreatecon, sockcreate) 3486cd6a6acSopenharmony_ci all_selfattr_def(keycreatecon, keycreate) 3496cd6a6acSopenharmony_ci 350