Coverage Report

Created: 2026-06-05 06:42

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