Home | History | Annotate | Download | only in src
      1 #include <sys/syscall.h>
      2 #include <unistd.h>
      3 #include <fcntl.h>
      4 #include <pthread.h>
      5 #include <string.h>
      6 #include <stdlib.h>
      7 #include <stdio.h>
      8 #include <errno.h>
      9 #include "selinux_internal.h"
     10 #include "policy.h"
     11 
     12 #define UNSET (char *) -1
     13 
     14 static __thread char *prev_current = UNSET;
     15 static __thread char * prev_exec = UNSET;
     16 static __thread char * prev_fscreate = UNSET;
     17 static __thread char * prev_keycreate = UNSET;
     18 static __thread char * prev_sockcreate = UNSET;
     19 
     20 static pthread_once_t once = PTHREAD_ONCE_INIT;
     21 static pthread_key_t destructor_key;
     22 static int destructor_key_initialized = 0;
     23 static __thread char destructor_initialized;
     24 
     25 static pid_t gettid(void)
     26 {
     27 	return syscall(__NR_gettid);
     28 }
     29 
     30 static void procattr_thread_destructor(void __attribute__((unused)) *unused)
     31 {
     32 	if (prev_current != UNSET)
     33 		free(prev_current);
     34 	if (prev_exec != UNSET)
     35 		free(prev_exec);
     36 	if (prev_fscreate != UNSET)
     37 		free(prev_fscreate);
     38 	if (prev_keycreate != UNSET)
     39 		free(prev_keycreate);
     40 	if (prev_sockcreate != UNSET)
     41 		free(prev_sockcreate);
     42 }
     43 
     44 void __attribute__((destructor)) procattr_destructor(void);
     45 
     46 void hidden __attribute__((destructor)) procattr_destructor(void)
     47 {
     48 	if (destructor_key_initialized)
     49 		__selinux_key_delete(destructor_key);
     50 }
     51 
     52 static inline void init_thread_destructor(void)
     53 {
     54 	if (destructor_initialized == 0) {
     55 		__selinux_setspecific(destructor_key, (void *)1);
     56 		destructor_initialized = 1;
     57 	}
     58 }
     59 
     60 static void init_procattr(void)
     61 {
     62 	if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) {
     63 		destructor_key_initialized = 1;
     64 	}
     65 }
     66 
     67 static int openattr(pid_t pid, const char *attr, int flags)
     68 {
     69 	int fd, rc;
     70 	char *path;
     71 	pid_t tid;
     72 
     73 	if (pid > 0)
     74 		rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
     75 	else {
     76 		rc = asprintf(&path, "/proc/thread-self/attr/%s", attr);
     77 		if (rc < 0)
     78 			return -1;
     79 		fd = open(path, flags | O_CLOEXEC);
     80 		if (fd >= 0 || errno != ENOENT)
     81 			goto out;
     82 		free(path);
     83 		tid = gettid();
     84 		rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
     85 	}
     86 	if (rc < 0)
     87 		return -1;
     88 
     89 	fd = open(path, flags | O_CLOEXEC);
     90 out:
     91 	free(path);
     92 	return fd;
     93 }
     94 
     95 static int getprocattrcon_raw(char ** context,
     96 			      pid_t pid, const char *attr)
     97 {
     98 	char *buf;
     99 	size_t size;
    100 	int fd;
    101 	ssize_t ret;
    102 	int errno_hold;
    103 	char * prev_context;
    104 
    105 	__selinux_once(once, init_procattr);
    106 	init_thread_destructor();
    107 
    108 	switch (attr[0]) {
    109 		case 'c':
    110 			prev_context = prev_current;
    111 			break;
    112 		case 'e':
    113 			prev_context = prev_exec;
    114 			break;
    115 		case 'f':
    116 			prev_context = prev_fscreate;
    117 			break;
    118 		case 'k':
    119 			prev_context = prev_keycreate;
    120 			break;
    121 		case 's':
    122 			prev_context = prev_sockcreate;
    123 			break;
    124 		case 'p':
    125 			prev_context = NULL;
    126 			break;
    127 		default:
    128 			errno = ENOENT;
    129 			return -1;
    130 	};
    131 
    132 	if (prev_context && prev_context != UNSET) {
    133 		*context = strdup(prev_context);
    134 		if (!(*context)) {
    135 			return -1;
    136 		}
    137 		return 0;
    138 	}
    139 
    140 	fd = openattr(pid, attr, O_RDONLY);
    141 	if (fd < 0)
    142 		return -1;
    143 
    144 	size = selinux_page_size;
    145 	buf = malloc(size);
    146 	if (!buf) {
    147 		ret = -1;
    148 		goto out;
    149 	}
    150 	memset(buf, 0, size);
    151 
    152 	do {
    153 		ret = read(fd, buf, size - 1);
    154 	} while (ret < 0 && errno == EINTR);
    155 	if (ret < 0)
    156 		goto out2;
    157 
    158 	if (ret == 0) {
    159 		*context = NULL;
    160 		goto out2;
    161 	}
    162 
    163 	*context = strdup(buf);
    164 	if (!(*context)) {
    165 		ret = -1;
    166 		goto out2;
    167 	}
    168 	ret = 0;
    169       out2:
    170 	free(buf);
    171       out:
    172 	errno_hold = errno;
    173 	close(fd);
    174 	errno = errno_hold;
    175 	return ret;
    176 }
    177 
    178 static int getprocattrcon(char ** context,
    179 			  pid_t pid, const char *attr)
    180 {
    181 	int ret;
    182 	char * rcontext;
    183 
    184 	ret = getprocattrcon_raw(&rcontext, pid, attr);
    185 
    186 	if (!ret) {
    187 		ret = selinux_raw_to_trans_context(rcontext, context);
    188 		freecon(rcontext);
    189 	}
    190 
    191 	return ret;
    192 }
    193 
    194 static int setprocattrcon_raw(const char * context,
    195 			      pid_t pid, const char *attr)
    196 {
    197 	int fd;
    198 	ssize_t ret;
    199 	int errno_hold;
    200 	char **prev_context, *context2 = NULL;
    201 
    202 	__selinux_once(once, init_procattr);
    203 	init_thread_destructor();
    204 
    205 	switch (attr[0]) {
    206 		case 'c':
    207 			prev_context = &prev_current;
    208 			break;
    209 		case 'e':
    210 			prev_context = &prev_exec;
    211 			break;
    212 		case 'f':
    213 			prev_context = &prev_fscreate;
    214 			break;
    215 		case 'k':
    216 			prev_context = &prev_keycreate;
    217 			break;
    218 		case 's':
    219 			prev_context = &prev_sockcreate;
    220 			break;
    221 		default:
    222 			errno = ENOENT;
    223 			return -1;
    224 	};
    225 
    226 	if (!context && !*prev_context)
    227 		return 0;
    228 	if (context && *prev_context && *prev_context != UNSET
    229 	    && !strcmp(context, *prev_context))
    230 		return 0;
    231 
    232 	fd = openattr(pid, attr, O_RDWR);
    233 	if (fd < 0)
    234 		return -1;
    235 	if (context) {
    236 		ret = -1;
    237 		context2 = strdup(context);
    238 		if (!context2)
    239 			goto out;
    240 		do {
    241 			ret = write(fd, context2, strlen(context2) + 1);
    242 		} while (ret < 0 && errno == EINTR);
    243 	} else {
    244 		do {
    245 			ret = write(fd, NULL, 0);	/* clear */
    246 		} while (ret < 0 && errno == EINTR);
    247 	}
    248 out:
    249 	errno_hold = errno;
    250 	close(fd);
    251 	errno = errno_hold;
    252 	if (ret < 0) {
    253 		free(context2);
    254 		return -1;
    255 	} else {
    256 		if (*prev_context != UNSET)
    257 			free(*prev_context);
    258 		*prev_context = context2;
    259 		return 0;
    260 	}
    261 }
    262 
    263 static int setprocattrcon(const char * context,
    264 			  pid_t pid, const char *attr)
    265 {
    266 	int ret;
    267 	char * rcontext;
    268 
    269 	if (selinux_trans_to_raw_context(context, &rcontext))
    270 		return -1;
    271 
    272 	ret = setprocattrcon_raw(rcontext, pid, attr);
    273 
    274 	freecon(rcontext);
    275 
    276 	return ret;
    277 }
    278 
    279 #define getselfattr_def(fn, attr) \
    280 	int get##fn##_raw(char **c) \
    281 	{ \
    282 		return getprocattrcon_raw(c, 0, #attr); \
    283 	} \
    284 	int get##fn(char **c) \
    285 	{ \
    286 		return getprocattrcon(c, 0, #attr); \
    287 	}
    288 
    289 #define setselfattr_def(fn, attr) \
    290 	int set##fn##_raw(const char * c) \
    291 	{ \
    292 		return setprocattrcon_raw(c, 0, #attr); \
    293 	} \
    294 	int set##fn(const char * c) \
    295 	{ \
    296 		return setprocattrcon(c, 0, #attr); \
    297 	}
    298 
    299 #define all_selfattr_def(fn, attr) \
    300 	getselfattr_def(fn, attr)	 \
    301 	setselfattr_def(fn, attr)
    302 
    303 #define getpidattr_def(fn, attr) \
    304 	int get##fn##_raw(pid_t pid, char **c)	\
    305 	{ \
    306 		return getprocattrcon_raw(c, pid, #attr); \
    307 	} \
    308 	int get##fn(pid_t pid, char **c)	\
    309 	{ \
    310 		return getprocattrcon(c, pid, #attr); \
    311 	}
    312 
    313 all_selfattr_def(con, current)
    314     getpidattr_def(pidcon, current)
    315     getselfattr_def(prevcon, prev)
    316     all_selfattr_def(execcon, exec)
    317     all_selfattr_def(fscreatecon, fscreate)
    318     all_selfattr_def(sockcreatecon, sockcreate)
    319     all_selfattr_def(keycreatecon, keycreate)
    320 
    321     hidden_def(getcon_raw)
    322     hidden_def(getcon)
    323     hidden_def(getexeccon_raw)
    324     hidden_def(getfilecon_raw)
    325     hidden_def(getfilecon)
    326     hidden_def(getfscreatecon_raw)
    327     hidden_def(getkeycreatecon_raw)
    328     hidden_def(getpeercon_raw)
    329     hidden_def(getpidcon_raw)
    330     hidden_def(getprevcon_raw)
    331     hidden_def(getprevcon)
    332     hidden_def(getsockcreatecon_raw)
    333     hidden_def(setcon_raw)
    334     hidden_def(setexeccon_raw)
    335     hidden_def(setexeccon)
    336     hidden_def(setfilecon_raw)
    337     hidden_def(setfscreatecon_raw)
    338     hidden_def(setkeycreatecon_raw)
    339     hidden_def(setsockcreatecon_raw)
    340