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