Home | History | Annotate | Download | only in src
      1 /* Author: Trusted Computer Solutions, Inc.
      2  *
      3  * Modified:
      4  * Yuichi Nakamura <ynakam (at) hitachisoft.jp>
      5  - Stubs are used when DISABLE_SETRANS is defined,
      6    it is to reduce size for such as embedded devices.
      7 */
      8 
      9 #include <sys/types.h>
     10 #include <sys/socket.h>
     11 #include <sys/un.h>
     12 
     13 #include <errno.h>
     14 #include <stdlib.h>
     15 #include <netdb.h>
     16 #include <fcntl.h>
     17 #include <stdio.h>
     18 #include <string.h>
     19 #include <ctype.h>
     20 #include <unistd.h>
     21 #include <sys/uio.h>
     22 #include "dso.h"
     23 #include "selinux_internal.h"
     24 #include "setrans_internal.h"
     25 
     26 #ifndef DISABLE_SETRANS
     27 static unsigned char has_setrans;
     28 
     29 // Simple cache
     30 static __thread char * prev_t2r_trans = NULL;
     31 static __thread char * prev_t2r_raw = NULL;
     32 static __thread char * prev_r2t_trans = NULL;
     33 static __thread char * prev_r2t_raw = NULL;
     34 static __thread char *prev_r2c_trans = NULL;
     35 static __thread char * prev_r2c_raw = NULL;
     36 
     37 static pthread_once_t once = PTHREAD_ONCE_INIT;
     38 static pthread_key_t destructor_key;
     39 static int destructor_key_initialized = 0;
     40 static __thread char destructor_initialized;
     41 
     42 /*
     43  * setransd_open
     44  *
     45  * This function opens a socket to the setransd.
     46  * Returns:  on success, a file descriptor ( >= 0 ) to the socket
     47  *           on error, a negative value
     48  */
     49 static int setransd_open(void)
     50 {
     51 	struct sockaddr_un addr;
     52 	int fd;
     53 #ifdef SOCK_CLOEXEC
     54 	fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
     55 	if (fd < 0 && errno == EINVAL)
     56 #endif
     57 	{
     58 		fd = socket(PF_UNIX, SOCK_STREAM, 0);
     59 		if (fd >= 0)
     60 			if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
     61 				close(fd);
     62 				return -1;
     63 			}
     64 	}
     65 	if (fd < 0)
     66 		return -1;
     67 
     68 	memset(&addr, 0, sizeof(addr));
     69 	addr.sun_family = AF_UNIX;
     70 	strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path));
     71 	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
     72 		close(fd);
     73 		return -1;
     74 	}
     75 
     76 	return fd;
     77 }
     78 
     79 /* Returns: 0 on success, <0 on failure */
     80 static int
     81 send_request(int fd, uint32_t function, const char *data1, const char *data2)
     82 {
     83 	struct msghdr msgh;
     84 	struct iovec iov[5];
     85 	uint32_t data1_size;
     86 	uint32_t data2_size;
     87 	ssize_t count, expected;
     88 	unsigned int i;
     89 
     90 	if (fd < 0)
     91 		return -1;
     92 
     93 	if (!data1)
     94 		data1 = "";
     95 	if (!data2)
     96 		data2 = "";
     97 
     98 	data1_size = strlen(data1) + 1;
     99 	data2_size = strlen(data2) + 1;
    100 
    101 	iov[0].iov_base = &function;
    102 	iov[0].iov_len = sizeof(function);
    103 	iov[1].iov_base = &data1_size;
    104 	iov[1].iov_len = sizeof(data1_size);
    105 	iov[2].iov_base = &data2_size;
    106 	iov[2].iov_len = sizeof(data2_size);
    107 	iov[3].iov_base = (char *)data1;
    108 	iov[3].iov_len = data1_size;
    109 	iov[4].iov_base = (char *)data2;
    110 	iov[4].iov_len = data2_size;
    111 	memset(&msgh, 0, sizeof(msgh));
    112 	msgh.msg_iov = iov;
    113 	msgh.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
    114 
    115 	expected = 0;
    116 	for (i = 0; i < sizeof(iov) / sizeof(iov[0]); i++)
    117 		expected += iov[i].iov_len;
    118 
    119 	while (((count = sendmsg(fd, &msgh, MSG_NOSIGNAL)) < 0)
    120 	       && (errno == EINTR)) ;
    121 	if (count < 0 || count != expected)
    122 		return -1;
    123 
    124 	return 0;
    125 }
    126 
    127 /* Returns: 0 on success, <0 on failure */
    128 static int
    129 receive_response(int fd, uint32_t function, char **outdata, int32_t * ret_val)
    130 {
    131 	struct iovec resp_hdr[3];
    132 	uint32_t func;
    133 	uint32_t data_size;
    134 	char *data;
    135 	struct iovec resp_data;
    136 	ssize_t count;
    137 
    138 	if (fd < 0)
    139 		return -1;
    140 
    141 	resp_hdr[0].iov_base = &func;
    142 	resp_hdr[0].iov_len = sizeof(func);
    143 	resp_hdr[1].iov_base = &data_size;
    144 	resp_hdr[1].iov_len = sizeof(data_size);
    145 	resp_hdr[2].iov_base = ret_val;
    146 	resp_hdr[2].iov_len = sizeof(*ret_val);
    147 
    148 	while (((count = readv(fd, resp_hdr, 3)) < 0) && (errno == EINTR)) ;
    149 	if (count != (sizeof(func) + sizeof(data_size) + sizeof(*ret_val))) {
    150 		return -1;
    151 	}
    152 
    153 	if (func != function || !data_size || data_size > MAX_DATA_BUF) {
    154 		return -1;
    155 	}
    156 
    157 	data = malloc(data_size);
    158 	if (!data)
    159 		return -1;
    160 	/* coveriety doesn't realize that data will be initialized in readv */
    161 	memset(data, 0, data_size);
    162 
    163 	resp_data.iov_base = data;
    164 	resp_data.iov_len = data_size;
    165 
    166 	while (((count = readv(fd, &resp_data, 1))) < 0 && (errno == EINTR)) ;
    167 	if (count < 0 || (uint32_t) count != data_size ||
    168 	    data[data_size - 1] != '\0') {
    169 		free(data);
    170 		return -1;
    171 	}
    172 	*outdata = data;
    173 	return 0;
    174 }
    175 
    176 static int raw_to_trans_context(const char *raw, char **transp)
    177 {
    178 	int ret;
    179 	int32_t ret_val;
    180 	int fd;
    181 
    182 	*transp = NULL;
    183 
    184 	fd = setransd_open();
    185 	if (fd < 0)
    186 		return fd;
    187 
    188 	ret = send_request(fd, RAW_TO_TRANS_CONTEXT, raw, NULL);
    189 	if (ret)
    190 		goto out;
    191 
    192 	ret = receive_response(fd, RAW_TO_TRANS_CONTEXT, transp, &ret_val);
    193 	if (ret)
    194 		goto out;
    195 
    196 	ret = ret_val;
    197       out:
    198 	close(fd);
    199 	return ret;
    200 }
    201 
    202 static int trans_to_raw_context(const char *trans, char **rawp)
    203 {
    204 	int ret;
    205 	int32_t ret_val;
    206 	int fd;
    207 
    208 	*rawp = NULL;
    209 
    210 	fd = setransd_open();
    211 	if (fd < 0)
    212 		return fd;
    213 	ret = send_request(fd, TRANS_TO_RAW_CONTEXT, trans, NULL);
    214 	if (ret)
    215 		goto out;
    216 
    217 	ret = receive_response(fd, TRANS_TO_RAW_CONTEXT, rawp, &ret_val);
    218 	if (ret)
    219 		goto out;
    220 
    221 	ret = ret_val;
    222       out:
    223 	close(fd);
    224 	return ret;
    225 }
    226 
    227 static int raw_context_to_color(const char *raw, char **colors)
    228 {
    229 	int ret;
    230 	int32_t ret_val;
    231 	int fd;
    232 
    233 	fd = setransd_open();
    234 	if (fd < 0)
    235 		return fd;
    236 
    237 	ret = send_request(fd, RAW_CONTEXT_TO_COLOR, raw, NULL);
    238 	if (ret)
    239 		goto out;
    240 
    241 	ret = receive_response(fd, RAW_CONTEXT_TO_COLOR, colors, &ret_val);
    242 	if (ret)
    243 		goto out;
    244 
    245 	ret = ret_val;
    246 out:
    247 	close(fd);
    248 	return ret;
    249 }
    250 
    251 static void setrans_thread_destructor(void __attribute__((unused)) *unused)
    252 {
    253 	free(prev_t2r_trans);
    254 	free(prev_t2r_raw);
    255 	free(prev_r2t_trans);
    256 	free(prev_r2t_raw);
    257 	free(prev_r2c_trans);
    258 	free(prev_r2c_raw);
    259 }
    260 
    261 void __attribute__((destructor)) setrans_lib_destructor(void);
    262 
    263 void hidden __attribute__((destructor)) setrans_lib_destructor(void)
    264 {
    265 	if (!has_setrans)
    266 		return;
    267 	if (destructor_key_initialized)
    268 		__selinux_key_delete(destructor_key);
    269 }
    270 
    271 static inline void init_thread_destructor(void)
    272 {
    273 	if (!has_setrans)
    274 		return;
    275 	if (destructor_initialized == 0) {
    276 		__selinux_setspecific(destructor_key, (void *)1);
    277 		destructor_initialized = 1;
    278 	}
    279 }
    280 
    281 static void init_context_translations(void)
    282 {
    283 	has_setrans = (access(SETRANS_UNIX_SOCKET, F_OK) == 0);
    284 	if (!has_setrans)
    285 		return;
    286 	if (__selinux_key_create(&destructor_key, setrans_thread_destructor) == 0)
    287 		destructor_key_initialized = 1;
    288 }
    289 
    290 int selinux_trans_to_raw_context(const char * trans,
    291 				 char ** rawp)
    292 {
    293 	if (!trans) {
    294 		*rawp = NULL;
    295 		return 0;
    296 	}
    297 
    298 	__selinux_once(once, init_context_translations);
    299 	init_thread_destructor();
    300 
    301 	if (!has_setrans) {
    302 		*rawp = strdup(trans);
    303 		goto out;
    304 	}
    305 
    306 	if (prev_t2r_trans && strcmp(prev_t2r_trans, trans) == 0) {
    307 		*rawp = strdup(prev_t2r_raw);
    308 	} else {
    309 		free(prev_t2r_trans);
    310 		prev_t2r_trans = NULL;
    311 		free(prev_t2r_raw);
    312 		prev_t2r_raw = NULL;
    313 		if (trans_to_raw_context(trans, rawp))
    314 			*rawp = strdup(trans);
    315 		if (*rawp) {
    316 			prev_t2r_trans = strdup(trans);
    317 			if (!prev_t2r_trans)
    318 				goto out;
    319 			prev_t2r_raw = strdup(*rawp);
    320 			if (!prev_t2r_raw) {
    321 				free(prev_t2r_trans);
    322 				prev_t2r_trans = NULL;
    323 			}
    324 		}
    325 	}
    326       out:
    327 	return *rawp ? 0 : -1;
    328 }
    329 
    330 hidden_def(selinux_trans_to_raw_context)
    331 
    332 int selinux_raw_to_trans_context(const char * raw,
    333 				 char ** transp)
    334 {
    335 	if (!raw) {
    336 		*transp = NULL;
    337 		return 0;
    338 	}
    339 
    340 	__selinux_once(once, init_context_translations);
    341 	init_thread_destructor();
    342 
    343 	if (!has_setrans)  {
    344 		*transp = strdup(raw);
    345 		goto out;
    346 	}
    347 
    348 	if (prev_r2t_raw && strcmp(prev_r2t_raw, raw) == 0) {
    349 		*transp = strdup(prev_r2t_trans);
    350 	} else {
    351 		free(prev_r2t_raw);
    352 		prev_r2t_raw = NULL;
    353 		free(prev_r2t_trans);
    354 		prev_r2t_trans = NULL;
    355 		if (raw_to_trans_context(raw, transp))
    356 			*transp = strdup(raw);
    357 		if (*transp) {
    358 			prev_r2t_raw = strdup(raw);
    359 			if (!prev_r2t_raw)
    360 				goto out;
    361 			prev_r2t_trans = strdup(*transp);
    362 			if (!prev_r2t_trans) {
    363 				free(prev_r2t_raw);
    364 				prev_r2t_raw = NULL;
    365 			}
    366 		}
    367 	}
    368       out:
    369 	return *transp ? 0 : -1;
    370 }
    371 
    372 hidden_def(selinux_raw_to_trans_context)
    373 
    374 int selinux_raw_context_to_color(const char * raw, char **transp)
    375 {
    376 	if (!raw) {
    377 		*transp = NULL;
    378 		return -1;
    379 	}
    380 
    381 	__selinux_once(once, init_context_translations);
    382 	init_thread_destructor();
    383 
    384 	if (!has_setrans) {
    385 		*transp = strdup(raw);
    386 		goto out;
    387 	}
    388 
    389 	if (prev_r2c_raw && strcmp(prev_r2c_raw, raw) == 0) {
    390 		*transp = strdup(prev_r2c_trans);
    391 	} else {
    392 		free(prev_r2c_raw);
    393 		prev_r2c_raw = NULL;
    394 		free(prev_r2c_trans);
    395 		prev_r2c_trans = NULL;
    396 		if (raw_context_to_color(raw, transp))
    397 			return -1;
    398 		if (*transp) {
    399 			prev_r2c_raw = strdup(raw);
    400 			if (!prev_r2c_raw)
    401 				goto out;
    402 			prev_r2c_trans = strdup(*transp);
    403 			if (!prev_r2c_trans) {
    404 				free(prev_r2c_raw);
    405 				prev_r2c_raw = NULL;
    406 			}
    407 		}
    408 	}
    409       out:
    410 	return *transp ? 0 : -1;
    411 }
    412 
    413 hidden_def(selinux_raw_context_to_color)
    414 #else /*DISABLE_SETRANS*/
    415 
    416 int selinux_trans_to_raw_context(const char * trans,
    417 				 char ** rawp)
    418 {
    419 	if (!trans) {
    420 		*rawp = NULL;
    421 		return 0;
    422 	}
    423 
    424 	*rawp = strdup(trans);
    425 
    426 	return *rawp ? 0 : -1;
    427 }
    428 
    429 hidden_def(selinux_trans_to_raw_context)
    430 
    431 int selinux_raw_to_trans_context(const char * raw,
    432 				 char ** transp)
    433 {
    434 	if (!raw) {
    435 		*transp = NULL;
    436 		return 0;
    437 	}
    438 	*transp = strdup(raw);
    439 
    440 	return *transp ? 0 : -1;
    441 }
    442 
    443 hidden_def(selinux_raw_to_trans_context)
    444 #endif /*DISABLE_SETRANS*/
    445