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