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