• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Author: Trusted Computer Solutions, Inc.
2  *
3  * Modified:
4  * Yuichi Nakamura <ynakam@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  */
setransd_open(void)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
send_request(int fd,uint32_t function,const char * data1,const char * data2)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
receive_response(int fd,uint32_t function,char ** outdata,int32_t * ret_val)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 
raw_to_trans_context(const char * raw,char ** transp)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 
trans_to_raw_context(const char * trans,char ** rawp)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 
raw_context_to_color(const char * raw,char ** colors)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 
setrans_thread_destructor(void * unused)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 
setrans_lib_destructor(void)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 
init_thread_destructor(void)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 
init_context_translations(void)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 
selinux_trans_to_raw_context(const char * trans,char ** rawp)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 
hidden_def(selinux_trans_to_raw_context)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 
hidden_def(selinux_raw_to_trans_context)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