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