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