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