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 int mls_enabled = -1;
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 (destructor_key_initialized)
265 __selinux_key_delete(destructor_key);
266 }
267
init_thread_destructor(void)268 static inline void init_thread_destructor(void)
269 {
270 if (destructor_initialized == 0) {
271 __selinux_setspecific(destructor_key, (void *)1);
272 destructor_initialized = 1;
273 }
274 }
275
init_context_translations(void)276 static void init_context_translations(void)
277 {
278 if (__selinux_key_create(&destructor_key, setrans_thread_destructor) == 0)
279 destructor_key_initialized = 1;
280
281 mls_enabled = is_selinux_mls_enabled();
282 }
283
selinux_trans_to_raw_context(const char * trans,char ** rawp)284 int selinux_trans_to_raw_context(const char * trans,
285 char ** rawp)
286 {
287 if (!trans) {
288 *rawp = NULL;
289 return 0;
290 }
291
292 __selinux_once(once, init_context_translations);
293 init_thread_destructor();
294
295 if (!mls_enabled) {
296 *rawp = strdup(trans);
297 goto out;
298 }
299
300 if (prev_t2r_trans && strcmp(prev_t2r_trans, trans) == 0) {
301 *rawp = strdup(prev_t2r_raw);
302 } else {
303 free(prev_t2r_trans);
304 prev_t2r_trans = NULL;
305 free(prev_t2r_raw);
306 prev_t2r_raw = NULL;
307 if (trans_to_raw_context(trans, rawp))
308 *rawp = strdup(trans);
309 if (*rawp) {
310 prev_t2r_trans = strdup(trans);
311 if (!prev_t2r_trans)
312 goto out;
313 prev_t2r_raw = strdup(*rawp);
314 if (!prev_t2r_raw) {
315 free(prev_t2r_trans);
316 prev_t2r_trans = NULL;
317 }
318 }
319 }
320 out:
321 return *rawp ? 0 : -1;
322 }
323
hidden_def(selinux_trans_to_raw_context)324 hidden_def(selinux_trans_to_raw_context)
325
326 int selinux_raw_to_trans_context(const char * raw,
327 char ** transp)
328 {
329 if (!raw) {
330 *transp = NULL;
331 return 0;
332 }
333
334 __selinux_once(once, init_context_translations);
335 init_thread_destructor();
336
337 if (!mls_enabled) {
338 *transp = strdup(raw);
339 goto out;
340 }
341
342 if (prev_r2t_raw && strcmp(prev_r2t_raw, raw) == 0) {
343 *transp = strdup(prev_r2t_trans);
344 } else {
345 free(prev_r2t_raw);
346 prev_r2t_raw = NULL;
347 free(prev_r2t_trans);
348 prev_r2t_trans = NULL;
349 if (raw_to_trans_context(raw, transp))
350 *transp = strdup(raw);
351 if (*transp) {
352 prev_r2t_raw = strdup(raw);
353 if (!prev_r2t_raw)
354 goto out;
355 prev_r2t_trans = strdup(*transp);
356 if (!prev_r2t_trans) {
357 free(prev_r2t_raw);
358 prev_r2t_raw = NULL;
359 }
360 }
361 }
362 out:
363 return *transp ? 0 : -1;
364 }
365
hidden_def(selinux_raw_to_trans_context)366 hidden_def(selinux_raw_to_trans_context)
367
368 int selinux_raw_context_to_color(const char * raw, char **transp)
369 {
370 if (!raw) {
371 *transp = NULL;
372 return -1;
373 }
374
375 __selinux_once(once, init_context_translations);
376 init_thread_destructor();
377
378 if (prev_r2c_raw && strcmp(prev_r2c_raw, raw) == 0) {
379 *transp = strdup(prev_r2c_trans);
380 } else {
381 free(prev_r2c_raw);
382 prev_r2c_raw = NULL;
383 free(prev_r2c_trans);
384 prev_r2c_trans = NULL;
385 if (raw_context_to_color(raw, transp))
386 return -1;
387 if (*transp) {
388 prev_r2c_raw = strdup(raw);
389 if (!prev_r2c_raw)
390 goto out;
391 prev_r2c_trans = strdup(*transp);
392 if (!prev_r2c_trans) {
393 free(prev_r2c_raw);
394 prev_r2c_raw = NULL;
395 }
396 }
397 }
398 out:
399 return *transp ? 0 : -1;
400 }
401
402 hidden_def(selinux_raw_context_to_color)
403 #else /*DISABLE_SETRANS*/
404
405 int selinux_trans_to_raw_context(const char * trans,
406 char ** rawp)
407 {
408 if (!trans) {
409 *rawp = NULL;
410 return 0;
411 }
412
413 *rawp = strdup(trans);
414
415 return *rawp ? 0 : -1;
416 }
417
418 hidden_def(selinux_trans_to_raw_context)
419
420 int selinux_raw_to_trans_context(const char * raw,
421 char ** transp)
422 {
423 if (!raw) {
424 *transp = NULL;
425 return 0;
426 }
427 *transp = strdup(raw);
428
429 return *transp ? 0 : -1;
430 }
431
432 hidden_def(selinux_raw_to_trans_context)
433 #endif /*DISABLE_SETRANS*/
434