xref: /aosp_15_r20/external/selinux/mcstrans/src/mcstransd.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /* Copyright (c) 2006 Trusted Computer Solutions, Inc. */
2 #include <errno.h>
3 #include <poll.h>
4 #include <signal.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <syslog.h>
10 #include <unistd.h>
11 #include <selinux/selinux.h>
12 #include <sys/capability.h>
13 #include <sys/resource.h>
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/uio.h>
18 #include <sys/un.h>
19 
20 #include "mcscolor.h"
21 #include "mcstrans.h"
22 
23 #ifdef UNUSED
24 #elif defined(__GNUC__)
25 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
26 #elif defined(__LCLINT__)
27 # define UNUSED(x) /*@unused@*/ x
28 #else
29 # define UNUSED(x) x
30 #endif
31 
32 #define SETRANS_UNIX_SOCKET "/var/run/setrans/.setrans-unix"
33 
34 #define SETRANS_INIT			1
35 #define RAW_TO_TRANS_CONTEXT		2
36 #define TRANS_TO_RAW_CONTEXT		3
37 #define RAW_CONTEXT_TO_COLOR		4
38 #define MAX_DATA_BUF			4096
39 #define MAX_DESCRIPTORS			8192
40 
41 #ifdef DEBUG
42 //#define log_debug(fmt, ...) syslog(LOG_DEBUG, fmt, __VA_ARGS__)
43 #define log_debug(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
44 #else
45 #define log_debug(fmt, ...) do {} while (0)
46 #endif
47 
48 #define SETRANSD_PATHNAME "/sbin/mcstransd"
49 
50 /* name of program (for error messages) */
51 #define SETRANSD_PROGNAME "mcstransd"
52 
53 static int sockfd = -1;	/* socket we are listening on */
54 
55 static volatile int restart_daemon = 0;
56 static void cleanup_exit(int ret) __attribute__ ((noreturn));
57 static void
cleanup_exit(int ret)58 cleanup_exit(int ret)
59 {
60 	finish_context_colors();
61 	finish_context_translations();
62 	if (sockfd >=0)
63 		(void)unlink(SETRANS_UNIX_SOCKET);
64 
65 	log_debug("%s\n", "cleanup_exit");
66 
67 	exit(ret);
68 }
69 
70 static void clean_exit(void);
clean_exit(void)71 static  __attribute__((noreturn)) void clean_exit(void)
72 {
73 	log_debug("%s\n", "clean_exit");
74 	cleanup_exit(0);
75 }
76 
77 static int
send_response(int fd,uint32_t function,char * data,int32_t ret_val)78 send_response(int fd, uint32_t function, char *data, int32_t ret_val)
79 {
80 	struct iovec resp_hdr[3];
81 	uint32_t data_size;
82 	struct iovec resp_data;
83 	ssize_t count;
84 
85 	if (!data)
86 		data = (char *)"";
87 
88 	data_size = strlen(data) + 1;
89 
90 	resp_hdr[0].iov_base = &function;
91 	resp_hdr[0].iov_len = sizeof(function);
92 	resp_hdr[1].iov_base = &data_size;
93 	resp_hdr[1].iov_len = sizeof(data_size);
94 	resp_hdr[2].iov_base = &ret_val;
95 	resp_hdr[2].iov_len = sizeof(ret_val);
96 
97 	while (((count = writev(fd, resp_hdr, 3)) < 0) && (errno == EINTR));
98 	if (count != (sizeof(function) + sizeof(data_size) + sizeof(ret_val))) {
99 		syslog(LOG_ERR, "Failed to write response header");
100 		return -1;
101 	}
102 
103 	resp_data.iov_base = data;
104 	resp_data.iov_len = data_size;
105 
106 	while (((count = writev(fd, &resp_data, 1)) < 0) && (errno == EINTR));
107 	if (count < 0 || (size_t)count != data_size) {
108 		syslog(LOG_ERR, "Failed to write response data");
109 		return -1;
110 	}
111 
112 	return ret_val;
113 }
114 
115 static int
get_peer_pid(int fd,pid_t * pid)116 get_peer_pid(int fd, pid_t *pid)
117 {
118 	int ret;
119 	socklen_t size = sizeof(struct ucred);
120 	struct ucred peercred;
121 
122 	/* get the context of the requesting process */
123 	ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &size);
124 	if (ret < 0) {
125 		syslog(LOG_ERR, "Failed to get PID of client process");
126 		return -1;
127 	}
128 	*pid = peercred.pid;
129 	return ret;
130 }
131 
132 
133 static int
process_request(int fd,uint32_t function,char * data1,char * UNUSED (data2))134 process_request(int fd, uint32_t function, char *data1, char *UNUSED(data2))
135 {
136 	int32_t result;
137 	char *out = NULL;
138 	int ret;
139 
140 	switch (function) {
141 	case SETRANS_INIT:
142 		result = 0;
143 		ret = send_response(fd, function, NULL, result);
144 		break;
145 	case RAW_TO_TRANS_CONTEXT:
146 		result = trans_context(data1, &out);
147 		ret = send_response(fd, function, out, result);
148 		break;
149 	case TRANS_TO_RAW_CONTEXT:
150 		result = untrans_context(data1, &out);
151 		ret = send_response(fd, function, out, result);
152 		break;
153 	case RAW_CONTEXT_TO_COLOR:
154 		result = raw_color(data1, &out);
155 		ret = send_response(fd, function, out, result);
156 		break;
157 	default:
158 		result = -1;
159 		ret = -1;
160 		break;
161 	}
162 
163 	if (result) {
164 		pid_t pid = 0;
165 		get_peer_pid(fd, &pid);
166 		syslog(LOG_ERR, "Invalid request func=%d from=%u",
167 		       function, pid);
168 	}
169 
170 	free(out);
171 
172 	return ret;
173 }
174 
175 static int
service_request(int fd)176 service_request(int fd)
177 {
178 	struct iovec req_hdr[3];
179 	uint32_t function;
180 	uint32_t data1_size;
181 	uint32_t data2_size;
182 	struct iovec req_data[2];
183 	char *data1;
184 	char *data2;
185 	int ret;
186 	ssize_t count;
187 
188 	req_hdr[0].iov_base = &function;
189 	req_hdr[0].iov_len = sizeof(function);
190 	req_hdr[1].iov_base = &data1_size;
191 	req_hdr[1].iov_len = sizeof(data1_size);
192 	req_hdr[2].iov_base = &data2_size;
193 	req_hdr[2].iov_len = sizeof(data2_size);
194 
195 	while (((count = readv(fd, req_hdr, 3)) < 0) && (errno == EINTR));
196 	if (count <= 0) {
197 		return 1;
198 	}
199 	if (count != (sizeof(function) + sizeof(data1_size) +
200 	              sizeof(data2_size) )) {
201 		log_debug("Failed to read request header %d != %u\n",(int)count,
202 			(unsigned)(sizeof(function) + sizeof(data1_size) +
203                       sizeof(data2_size) ));
204 		return -1;
205 	}
206 
207 	if (!data1_size || !data2_size || data1_size > MAX_DATA_BUF ||
208 						data2_size > MAX_DATA_BUF ) {
209 		log_debug("Header invalid data1_size=%u data2_size=%u\n",
210 		        data1_size, data2_size);
211 		return -1;
212 	}
213 
214 	data1 = malloc(data1_size);
215 	if (!data1) {
216 		log_debug("Could not allocate %d bytes\n", data1_size);
217 		return -1;
218 	}
219 	data2 = malloc(data2_size);
220 	if (!data2) {
221 		free(data1);
222 		log_debug("Could not allocate %d bytes\n", data2_size);
223 		return -1;
224 	}
225 
226 	req_data[0].iov_base = data1;
227 	req_data[0].iov_len = data1_size;
228 	req_data[1].iov_base = data2;
229 	req_data[1].iov_len = data2_size;
230 
231 	while (((count = readv(fd, req_data, 2)) < 0) && (errno == EINTR));
232 	if (count <= 0 || (size_t)count != (data1_size + data2_size) ||
233 	    data1[data1_size - 1] != '\0' || data2[data2_size - 1] != '\0') {
234 		free(data1);
235 		free(data2);
236 		log_debug("Failed to read request data (%d)\n", (int)count);
237 		return -1;
238 	}
239 
240 	ret = process_request(fd, function, data1, data2);
241 
242 	free(data1);
243 	free(data2);
244 
245 	return ret;
246 }
247 
248 static int
add_pollfd(struct pollfd ** ufds,int * nfds,int connfd)249 add_pollfd(struct pollfd **ufds, int *nfds, int connfd)
250 {
251 	int ii = 0;
252 
253 	/* First see if we can find an already invalidated ufd */
254 	for (ii = 0; ii < *nfds; ii++) {
255 		if ((*ufds)[ii].fd == -1)
256 			break;
257 	}
258 
259 	if (ii == *nfds) {
260 		struct pollfd *tmp = (struct pollfd *)realloc(*ufds,
261 					(*nfds+1)*sizeof(struct pollfd));
262 		if (!tmp) {
263 			syslog(LOG_ERR, "realloc failed for %d fds", *nfds+1);
264 			return -1;
265 		}
266 
267 		*ufds = tmp;
268 		(*nfds)++;
269 	}
270 
271 	(*ufds)[ii].fd = connfd;
272 	(*ufds)[ii].events = POLLIN|POLLPRI;
273 	(*ufds)[ii].revents = 0;
274 
275 	return 0;
276 }
277 
278 static void
adj_pollfds(struct pollfd ** ufds,int * nfds)279 adj_pollfds(struct pollfd **ufds, int *nfds)
280 {
281 	int ii, jj;
282 
283 	jj = 0;
284 	for (ii = 0; ii < *nfds; ii++) {
285 		if ((*ufds)[ii].fd != -1) {
286 			if (jj < ii)
287 				(*ufds)[jj] = (*ufds)[ii];
288 			jj++;
289 		}
290 	}
291 	*nfds = jj;
292 }
293 
294 static int
process_events(struct pollfd ** ufds,int * nfds)295 process_events(struct pollfd **ufds, int *nfds)
296 {
297 	int ii = 0;
298 	int ret = 0;
299 
300 	for (ii = 0; ii < *nfds; ii++) {
301 		short revents = (*ufds)[ii].revents;
302 		int connfd = (*ufds)[ii].fd;
303 
304 		if (revents & (POLLIN | POLLPRI)) {
305 			if (connfd == sockfd) {
306 
307 				/* Probably received a connection */
308 				if ((connfd = accept(sockfd, NULL, NULL)) < 0) {
309 					syslog(LOG_ERR, "accept() failed: %m");
310 					return -1;
311 				}
312 
313 				if (add_pollfd(ufds, nfds, connfd)) {
314 					syslog(LOG_ERR,
315 					  "Failed to add fd (%d) to poll list\n",
316 						connfd);
317 					return -1;
318 				}
319 			} else {
320 				ret = service_request(connfd);
321 				if (ret) {
322 					if (ret < 0) {
323 						syslog(LOG_ERR,
324 							"Servicing of request "
325 							"failed for fd (%d)\n",
326 							connfd);
327 					}
328 					/* Setup pollfd for deletion later. */
329 					(*ufds)[ii].fd = -1;
330 					close(connfd);
331 					connfd = -1;
332 					/* So we don't get bothered later */
333 					revents = revents & ~(POLLHUP);
334 				}
335 			}
336 			revents = revents & ~(POLLIN | POLLPRI);
337 		}
338 		if (revents & POLLHUP) {
339 			log_debug("The connection with fd (%d) hung up\n",
340 				connfd);
341 
342 			/* Set the pollfd up for deletion later. */
343 			(*ufds)[ii].fd = -1;
344 			close(connfd);
345 			connfd = -1;
346 
347 			revents = revents & ~(POLLHUP);
348 		}
349 		if (revents && connfd != -1) {
350 			syslog(LOG_ERR, "Unknown/error events (%x) encountered"
351 					" for fd (%d)\n", revents, connfd);
352 
353 			/* Set the pollfd up for deletion later. */
354 			(*ufds)[ii].fd = -1;
355 			close(connfd);
356 		}
357 
358 		(*ufds)[ii].revents = 0;
359 	}
360 
361 	/* Delete any invalidated ufds */
362 	adj_pollfds(ufds, nfds);
363 
364 	return 0;
365 }
366 
367 static void
368 process_connections(void) __attribute__ ((noreturn));
369 
370 static void
process_connections(void)371 process_connections(void)
372 {
373 	int ret = 0;
374 	int nfds = 1;
375 
376 	struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd));
377 	if (!ufds) {
378 		syslog(LOG_ERR, "Failed to allocate a pollfd");
379 		cleanup_exit(1);
380 	}
381 	ufds[0].fd = sockfd;
382 	ufds[0].events = POLLIN|POLLPRI;
383 	ufds[0].revents = 0;
384 
385 	while (1) {
386 		if (restart_daemon) {
387 			syslog(LOG_NOTICE, "Reload Translations");
388 			finish_context_colors();
389 			finish_context_translations();
390 			if (init_translations()) {
391 				syslog(LOG_ERR, "Failed to initialize label translations");
392 				cleanup_exit(1);
393 			}
394 			if (init_colors()) {
395 				syslog(LOG_ERR, "Failed to initialize color translations");
396 				syslog(LOG_ERR, "No color information will be available");
397 			}
398 			restart_daemon = 0;
399 		}
400 
401 		ret = poll(ufds, nfds, -1);
402 		if (ret < 0) {
403 			if (errno == EINTR) {
404 				continue;
405 			}
406 			syslog(LOG_ERR, "poll() failed: %m");
407 			cleanup_exit(1);
408 		}
409 
410 		ret = process_events(&ufds, &nfds);
411 		if (ret) {
412 			syslog(LOG_ERR, "Error processing events");
413 			cleanup_exit(1);
414 		}
415 	}
416 }
417 
418 static void
419 sigterm_handler(int sig) __attribute__ ((noreturn));
420 
421 static void
sigterm_handler(int UNUSED (sig))422 sigterm_handler(int UNUSED(sig))
423 {
424 	cleanup_exit(0);
425 }
426 
427 static void
sighup_handler(int UNUSED (sig))428 sighup_handler(int UNUSED(sig))
429 {
430 	restart_daemon = 1;
431 }
432 
433 static void
initialize(void)434 initialize(void)
435 {
436 	struct sigaction act;
437 	struct sockaddr_un addr;
438 	struct rlimit rl ;
439 
440 	if (init_translations()) {
441 		syslog(LOG_ERR, "Failed to initialize label translations");
442 		cleanup_exit(1);
443 	}
444 	if (init_colors()) {
445 		syslog(LOG_ERR, "Failed to initialize color translations");
446 		syslog(LOG_ERR, "No color information will be available");
447 	}
448 
449 	/* the socket will be unlinked when the daemon terminates */
450 	act.sa_handler = sigterm_handler;
451 	sigemptyset(&act.sa_mask);
452 	sigaddset(&act.sa_mask, SIGINT);
453 	sigaddset(&act.sa_mask, SIGQUIT);
454 	sigaddset(&act.sa_mask, SIGTERM);
455 	sigaddset(&act.sa_mask, SIGHUP);
456 	act.sa_flags = 0;
457 	sigaction(SIGINT, &act, NULL);
458 	sigaction(SIGQUIT, &act, NULL);
459 	sigaction(SIGTERM, &act, NULL);
460 
461 	/* restart the daemon on SIGHUP */
462 	act.sa_handler = sighup_handler;
463 	sigemptyset(&act.sa_mask);
464 	sigaddset(&act.sa_mask, SIGINT);
465 	sigaddset(&act.sa_mask, SIGQUIT);
466 	sigaddset(&act.sa_mask, SIGTERM);
467 	act.sa_flags = 0;
468 	sigaction(SIGHUP, &act, NULL);
469 
470 	/* ignore SIGPIPE (in case a client terminates after sending request) */
471 	act.sa_handler = SIG_IGN;
472 	sigemptyset(&act.sa_mask);
473 	act.sa_flags = 0;
474 	sigaction(SIGPIPE, &act, NULL);
475 
476 	atexit(clean_exit);
477 
478 	sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
479 	if (sockfd < 0)	{
480 		syslog(LOG_ERR, "socket() failed: %m");
481 		cleanup_exit(1);
482 	}
483 
484 	memset(&addr, 0, sizeof(addr));
485 	addr.sun_family = AF_UNIX;
486 	strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path) - 1);
487 
488 	(void)unlink(SETRANS_UNIX_SOCKET);
489 
490 	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
491 		syslog(LOG_ERR, "bind() failed: %m");
492 		cleanup_exit(1);
493 	}
494 
495 	if (listen(sockfd, SOMAXCONN) < 0) {
496 		syslog(LOG_ERR, "listen() failed: %m");
497 		cleanup_exit(1);
498 	}
499 
500 	if (chmod(SETRANS_UNIX_SOCKET, S_IRWXU | S_IRWXG | S_IRWXO)) {
501 		syslog(LOG_ERR, "chmod() failed: %m");
502 		cleanup_exit(1);
503 	}
504 
505 	/* Raise the rlimit for file descriptors... */
506 	rl.rlim_max = MAX_DESCRIPTORS;
507 	rl.rlim_cur = MAX_DESCRIPTORS;
508 	setrlimit(RLIMIT_NOFILE, &rl);
509 
510 }
511 
dropprivs(void)512 static void dropprivs(void)
513 {
514 	cap_t new_caps;
515 
516 	new_caps = cap_init();
517 	if (cap_set_proc(new_caps)) {
518 		syslog(LOG_ERR, "Error dropping capabilities, aborting: %s\n",
519 			 strerror(errno));
520 		cleanup_exit(-1);
521 	}
522 	cap_free(new_caps);
523 }
524 
usage(char * program)525 static void usage(char *program)
526 {
527 	printf("%s [-f] [-h] \n", program);
528 }
529 
530 int
main(int argc,char * argv[])531 main(int argc, char *argv[])
532 {
533 	int opt;
534 	int do_fork = 1;
535 	while ((opt = getopt(argc, argv, "hf")) > 0) {
536 		switch (opt) {
537 		case 'f':
538 			do_fork = 0;
539 			break;
540 		case 'h':
541 			usage(argv[0]);
542 			exit(0);
543 			break;
544 		case '?':
545 			usage(argv[0]);
546 			exit(-1);
547 		}
548 	}
549 
550 #ifndef DEBUG
551 	/* Make sure we are root */
552 	if (getuid() != 0) {
553 		syslog(LOG_ERR, "You must be root to run this program.\n");
554 		return 4;
555 	}
556 #endif
557 
558 	openlog(SETRANSD_PROGNAME, 0, LOG_DAEMON);
559 	syslog(LOG_NOTICE, "%s starting", argv[0]);
560 
561 	initialize();
562 
563 #ifndef DEBUG
564 	dropprivs();
565 
566 	/* run in the background as a daemon */
567 	if (do_fork && daemon(0, 0)) {
568 		syslog(LOG_ERR, "daemon() failed: %m");
569 		cleanup_exit(1);
570 	}
571 #endif
572 
573 	syslog(LOG_NOTICE, "%s initialized", argv[0]);
574 	process_connections();
575 
576 	/* we should never get here */
577 	return 1;
578 }
579 
580