]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/selinux-util.c
tree-wide: port things over to FORMAT_PROC_FD_PATH()
[thirdparty/systemd.git] / src / shared / selinux-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
cad45ba1 2
66b6d9d5 3#include <errno.h>
ca78ad1d 4#include <fcntl.h>
66b6d9d5 5#include <malloc.h>
11c3a366
TA
6#include <stddef.h>
7#include <string.h>
8#include <sys/stat.h>
9#include <sys/time.h>
ca78ad1d 10#include <sys/types.h>
66b6d9d5 11#include <sys/un.h>
11c3a366 12#include <syslog.h>
a07e9cfb 13
349cc4a5 14#if HAVE_SELINUX
61f3e897 15#include <selinux/avc.h>
66b6d9d5 16#include <selinux/context.h>
cf0fbc49
TA
17#include <selinux/label.h>
18#include <selinux/selinux.h>
66b6d9d5
WC
19#endif
20
b5efdb8a 21#include "alloc-util.h"
2b2fec7d 22#include "errno-util.h"
08c84981 23#include "fd-util.h"
11c3a366
TA
24#include "log.h"
25#include "macro.h"
93cc7779
TA
26#include "path-util.h"
27#include "selinux-util.h"
08c84981 28#include "stdio-util.h"
11c3a366 29#include "time-util.h"
cad45ba1 30
349cc4a5 31#if HAVE_SELINUX
fd421c4a 32DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(context_t, context_free, NULL);
66b6d9d5 33#define _cleanup_context_free_ _cleanup_(context_freep)
0b6018f3 34
61f3e897
CG
35static int mac_selinux_reload(int seqno);
36
6baa7db0 37static int cached_use = -1;
fd5e402f 38static bool initialized = false;
fd5e402f 39static int last_policyload = 0;
66b6d9d5 40static struct selabel_handle *label_hnd = NULL;
c3b8bacd 41static bool have_status_page = false;
66cedb30 42
3cd44590 43#define log_enforcing(...) \
fd5e402f 44 log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
65804d6a
LP
45
46#define log_enforcing_errno(error, ...) \
47 ({ \
fd5e402f 48 bool _enforcing = mac_selinux_enforcing(); \
65804d6a
LP
49 int _level = _enforcing ? LOG_ERR : LOG_WARNING; \
50 int _e = (error); \
51 \
52 int _r = (log_get_max_level() >= LOG_PRI(_level)) \
10d296c1 53 ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
65804d6a
LP
54 : -ERRNO_VALUE(_e); \
55 _enforcing ? _r : 0; \
56 })
66b6d9d5 57#endif
cad45ba1 58
6d395665 59bool mac_selinux_use(void) {
349cc4a5 60#if HAVE_SELINUX
2073bf3f 61 if (_unlikely_(cached_use < 0)) {
6baa7db0 62 cached_use = is_selinux_enabled() > 0;
2073bf3f
CG
63 log_debug("SELinux enabled state cached to: %s", cached_use ? "enabled" : "disabled");
64 }
cad45ba1 65
6baa7db0 66 return cached_use;
66b6d9d5
WC
67#else
68 return false;
69#endif
cad45ba1
LP
70}
71
fd5e402f 72bool mac_selinux_enforcing(void) {
c3b8bacd 73 int r = 0;
fd5e402f 74#if HAVE_SELINUX
c3b8bacd
ZJS
75
76 /* If the SELinux status page has been successfully opened, retrieve the enforcing
77 * status over it to avoid system calls in security_getenforce(). */
78
79 if (have_status_page)
80 r = selinux_status_getenforce();
81 else
82 r = security_getenforce();
83
fd5e402f 84#endif
c3b8bacd 85 return r != 0;
fd5e402f
CG
86}
87
6baa7db0 88void mac_selinux_retest(void) {
349cc4a5 89#if HAVE_SELINUX
6baa7db0 90 cached_use = -1;
66b6d9d5 91#endif
cad45ba1 92}
0b6018f3 93
349cc4a5 94#if HAVE_SELINUX
1885169c
LP
95# if HAVE_MALLINFO2
96# define HAVE_GENERIC_MALLINFO 1
97typedef struct mallinfo2 generic_mallinfo;
98static generic_mallinfo generic_mallinfo_get(void) {
99 return mallinfo2();
100}
101# elif HAVE_MALLINFO
102# define HAVE_GENERIC_MALLINFO 1
103typedef struct mallinfo generic_mallinfo;
104static generic_mallinfo generic_mallinfo_get(void) {
105 /* glibc has deprecated mallinfo(), let's suppress the deprecation warning if mallinfo2() doesn't
106 * exist yet. */
4b6f74f5
ZJS
107DISABLE_WARNING_DEPRECATED_DECLARATIONS
108 return mallinfo();
109REENABLE_WARNING
110}
111# else
1885169c 112# define HAVE_GENERIC_MALLINFO 0
4b6f74f5
ZJS
113# endif
114
fd5e402f
CG
115static int open_label_db(void) {
116 struct selabel_handle *hnd;
66b6d9d5 117 usec_t before_timestamp, after_timestamp;
66b6d9d5 118
1885169c
LP
119# if HAVE_GENERIC_MALLINFO
120 generic_mallinfo before_mallinfo = generic_mallinfo_get();
4b6f74f5 121# endif
66b6d9d5
WC
122 before_timestamp = now(CLOCK_MONOTONIC);
123
fd5e402f
CG
124 hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
125 if (!hnd)
a9ba0e32 126 return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
66b6d9d5 127
65804d6a 128 after_timestamp = now(CLOCK_MONOTONIC);
1885169c
LP
129# if HAVE_GENERIC_MALLINFO
130 generic_mallinfo after_mallinfo = generic_mallinfo_get();
131 size_t l = LESS_BY((size_t) after_mallinfo.uordblks, (size_t) before_mallinfo.uordblks);
132 log_debug("Successfully loaded SELinux database in %s, size on heap is %zuK.",
5291f26d 133 FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0),
4b6f74f5
ZJS
134 DIV_ROUND_UP(l, 1024));
135# else
136 log_debug("Successfully loaded SELinux database in %s.",
5291f26d 137 FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0));
4b6f74f5 138# endif
66b6d9d5 139
fd5e402f
CG
140 /* release memory after measurement */
141 if (label_hnd)
142 selabel_close(label_hnd);
143 label_hnd = TAKE_PTR(hnd);
144
145 return 0;
146}
147#endif
148
149int mac_selinux_init(void) {
150#if HAVE_SELINUX
151 int r;
152
153 if (initialized)
154 return 0;
155
156 if (!mac_selinux_use())
157 return 0;
158
961b341e
ZJS
159 r = selinux_status_open(/* netlink fallback */ 1);
160 if (r < 0) {
161 if (!ERRNO_IS_PRIVILEGE(errno))
162 return log_enforcing_errno(errno, "Failed to open SELinux status page: %m");
163 log_warning_errno(errno, "selinux_status_open() with netlink fallback failed, not checking for policy reloads: %m");
164 } else if (r == 1)
165 log_warning("selinux_status_open() failed to open the status page, using the netlink fallback.");
166 else
167 have_status_page = true;
fd5e402f
CG
168
169 r = open_label_db();
170 if (r < 0) {
171 selinux_status_close();
172 return r;
173 }
174
961b341e
ZJS
175 /* Save the current policyload sequence number, so mac_selinux_maybe_reload() does not trigger on
176 * first call without any actual change. */
fd5e402f
CG
177 last_policyload = selinux_status_policyload();
178
fd5e402f 179 initialized = true;
65804d6a
LP
180#endif
181 return 0;
d682b3a7
LP
182}
183
fd5e402f
CG
184void mac_selinux_maybe_reload(void) {
185#if HAVE_SELINUX
c46c7688 186 int policyload;
fd5e402f 187
1006038c
CG
188 if (!initialized)
189 return;
190
c46c7688
CG
191 /* Do not use selinux_status_updated(3), cause since libselinux 3.2 selinux_check_access(3),
192 * called in core and user instances, does also use it under the hood.
193 * That can cause changes to be consumed by selinux_check_access(3) and not being visible here.
194 * Also do not use selinux callbacks, selinux_set_callback(3), cause they are only automatically
195 * invoked since libselinux 3.2 by selinux_status_updated(3).
196 * Relevant libselinux commit: https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503
197 * Debian Bullseye is going to ship libselinux 3.1, so stay compatible for backports. */
198 policyload = selinux_status_policyload();
199 if (policyload < 0) {
200 log_debug_errno(errno, "Failed to get SELinux policyload from status page: %m");
201 return;
202 }
fd5e402f 203
c46c7688
CG
204 if (policyload != last_policyload) {
205 mac_selinux_reload(policyload);
206 last_policyload = policyload;
fd5e402f
CG
207 }
208#endif
209}
210
ecabcf8b
LP
211void mac_selinux_finish(void) {
212
349cc4a5 213#if HAVE_SELINUX
fd5e402f
CG
214 if (label_hnd) {
215 selabel_close(label_hnd);
216 label_hnd = NULL;
217 }
218
fd5e402f 219 selinux_status_close();
c3b8bacd 220 have_status_page = false;
fd5e402f
CG
221
222 initialized = false;
ecabcf8b
LP
223#endif
224}
225
a9dfac21 226#if HAVE_SELINUX
61f3e897 227static int mac_selinux_reload(int seqno) {
fd5e402f 228 log_debug("SELinux reload %d", seqno);
a9dfac21 229
fd5e402f 230 (void) open_label_db();
61f3e897
CG
231
232 return 0;
a9dfac21 233}
61f3e897 234#endif
a9dfac21 235
c3151977 236int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
66b6d9d5 237
9271daee
LP
238 assert(path);
239 assert(inside_path);
240
349cc4a5 241#if HAVE_SELINUX
08c84981 242 _cleanup_close_ int fd = -1;
5dfc5461
LP
243
244 /* if mac_selinux_init() wasn't called before we are a NOOP */
66b6d9d5
WC
245 if (!label_hnd)
246 return 0;
247
08c84981
LP
248 /* Open the file as O_PATH, to pin it while we determine and adjust the label */
249 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
250 if (fd < 0) {
251 if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
252 return 0;
253
254 return -errno;
255 }
256
9271daee
LP
257 return mac_selinux_fix_container_fd(fd, path, inside_path, flags);
258#endif
259
260 return 0;
261}
262
263int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags) {
264
265 assert(fd >= 0);
266 assert(inside_path);
267
268#if HAVE_SELINUX
9271daee
LP
269 _cleanup_freecon_ char* fcon = NULL;
270 struct stat st;
271 int r;
272
273 /* if mac_selinux_init() wasn't called before we are a NOOP */
274 if (!label_hnd)
275 return 0;
276
08c84981
LP
277 if (fstat(fd, &st) < 0)
278 return -errno;
5dfc5461 279
61f3e897 280 /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
fd5e402f 281 mac_selinux_maybe_reload();
7960ba96
ZJS
282 if (!label_hnd)
283 return 0;
61f3e897 284
c3151977 285 if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) {
66b6d9d5 286 /* If there's no label to set, then exit without warning */
9271daee 287 if (errno == ENOENT)
66b6d9d5
WC
288 return 0;
289
9271daee 290 r = -errno;
08c84981 291 goto fail;
66b6d9d5
WC
292 }
293
ddb6eeaf 294 if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) {
08c84981
LP
295 _cleanup_freecon_ char *oldcon = NULL;
296
08c84981 297 /* If the FS doesn't support labels, then exit without warning */
9271daee 298 if (ERRNO_IS_NOT_SUPPORTED(errno))
66b6d9d5
WC
299 return 0;
300
08c84981 301 /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
9271daee 302 if (errno == EROFS && (flags & LABEL_IGNORE_EROFS))
66b6d9d5
WC
303 return 0;
304
9271daee
LP
305 r = -errno;
306
08c84981 307 /* If the old label is identical to the new one, suppress any kind of error */
ddb6eeaf 308 if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq(fcon, oldcon))
08c84981
LP
309 return 0;
310
311 goto fail;
66b6d9d5 312 }
08c84981
LP
313
314 return 0;
315
316fail:
9271daee 317 return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", strna(path), strna(inside_path));
66b6d9d5
WC
318#endif
319
ecabcf8b 320 return 0;
66b6d9d5
WC
321}
322
ecabcf8b 323int mac_selinux_apply(const char *path, const char *label) {
66b6d9d5 324
9271daee
LP
325 assert(path);
326
349cc4a5 327#if HAVE_SELINUX
ecabcf8b
LP
328 if (!mac_selinux_use())
329 return 0;
330
0f474365
LP
331 assert(label);
332
65804d6a
LP
333 if (setfilecon(path, label) < 0)
334 return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
66b6d9d5 335#endif
ecabcf8b 336 return 0;
d682b3a7
LP
337}
338
9271daee
LP
339int mac_selinux_apply_fd(int fd, const char *path, const char *label) {
340
341 assert(fd >= 0);
342
343#if HAVE_SELINUX
344 if (!mac_selinux_use())
345 return 0;
346
347 assert(label);
348
349 if (fsetfilecon(fd, label) < 0)
350 return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path));
351#endif
352 return 0;
353}
354
cc56fafe 355int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
349cc4a5 356#if HAVE_SELINUX
2ed96880 357 _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
66b6d9d5 358 security_class_t sclass;
65804d6a 359 int r;
66b6d9d5 360
7f416dae
LP
361 assert(exe);
362 assert(label);
363
6d395665 364 if (!mac_selinux_use())
7f416dae 365 return -EOPNOTSUPP;
66b6d9d5 366
24154879 367 r = getcon_raw(&mycon);
66b6d9d5 368 if (r < 0)
7f416dae 369 return -errno;
66b6d9d5 370
24154879 371 r = getfilecon_raw(exe, &fcon);
66b6d9d5 372 if (r < 0)
7f416dae 373 return -errno;
66b6d9d5
WC
374
375 sclass = string_to_security_class("process");
fdb0405e
CG
376 if (sclass == 0)
377 return -ENOSYS;
378
2ed96880 379 r = security_compute_create_raw(mycon, fcon, sclass, label);
7f416dae
LP
380 if (r < 0)
381 return -errno;
66b6d9d5 382
65804d6a
LP
383 return 0;
384#else
385 return -EOPNOTSUPP;
386#endif
66b6d9d5
WC
387}
388
cc56fafe 389int mac_selinux_get_our_label(char **label) {
65804d6a
LP
390#if HAVE_SELINUX
391 int r;
66b6d9d5 392
7f416dae
LP
393 assert(label);
394
6d395665 395 if (!mac_selinux_use())
7f416dae 396 return -EOPNOTSUPP;
66b6d9d5 397
24154879 398 r = getcon_raw(label);
66b6d9d5 399 if (r < 0)
7f416dae 400 return -errno;
66b6d9d5 401
65804d6a
LP
402 return 0;
403#else
404 return -EOPNOTSUPP;
405#endif
66b6d9d5
WC
406}
407
9008e1ac 408int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
349cc4a5 409#if HAVE_SELINUX
2ed96880 410 _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
66b6d9d5
WC
411 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
412 security_class_t sclass;
66b6d9d5 413 const char *range = NULL;
65804d6a 414 int r;
66b6d9d5
WC
415
416 assert(socket_fd >= 0);
417 assert(exe);
418 assert(label);
419
6d395665 420 if (!mac_selinux_use())
7f416dae
LP
421 return -EOPNOTSUPP;
422
24154879 423 r = getcon_raw(&mycon);
7f416dae
LP
424 if (r < 0)
425 return -errno;
66b6d9d5 426
a1d2de07 427 r = getpeercon_raw(socket_fd, &peercon);
7f416dae
LP
428 if (r < 0)
429 return -errno;
66b6d9d5 430
9008e1ac 431 if (!exec_label) {
66b6d9d5
WC
432 /* If there is no context set for next exec let's use context
433 of target executable */
24154879 434 r = getfilecon_raw(exe, &fcon);
7f416dae
LP
435 if (r < 0)
436 return -errno;
66b6d9d5
WC
437 }
438
439 bcon = context_new(mycon);
7f416dae
LP
440 if (!bcon)
441 return -ENOMEM;
66b6d9d5
WC
442
443 pcon = context_new(peercon);
7f416dae
LP
444 if (!pcon)
445 return -ENOMEM;
66b6d9d5
WC
446
447 range = context_range_get(pcon);
7f416dae
LP
448 if (!range)
449 return -errno;
66b6d9d5
WC
450
451 r = context_range_set(bcon, range);
7f416dae
LP
452 if (r)
453 return -errno;
66b6d9d5
WC
454
455 freecon(mycon);
456 mycon = strdup(context_str(bcon));
7f416dae
LP
457 if (!mycon)
458 return -ENOMEM;
66b6d9d5
WC
459
460 sclass = string_to_security_class("process");
fdb0405e
CG
461 if (sclass == 0)
462 return -ENOSYS;
463
2ed96880 464 r = security_compute_create_raw(mycon, fcon, sclass, label);
7f416dae
LP
465 if (r < 0)
466 return -errno;
7f416dae 467
65804d6a
LP
468 return 0;
469#else
470 return -EOPNOTSUPP;
471#endif
66b6d9d5
WC
472}
473
710a6b50 474char* mac_selinux_free(char *label) {
ecabcf8b 475
349cc4a5 476#if HAVE_SELINUX
2ed96880 477 freecon(label);
3d9fbea4
CG
478#else
479 assert(!label);
ecabcf8b 480#endif
710a6b50
LP
481
482 return NULL;
ecabcf8b
LP
483}
484
349cc4a5 485#if HAVE_SELINUX
7e531a52 486static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) {
2ed96880 487 _cleanup_freecon_ char *filecon = NULL;
0f474365 488 int r;
66b6d9d5 489
7e531a52
FB
490 assert(abspath);
491 assert(path_is_absolute(abspath));
c34255bd 492
61f3e897 493 /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
fd5e402f 494 mac_selinux_maybe_reload();
7960ba96
ZJS
495 if (!label_hnd)
496 return 0;
61f3e897 497
7e531a52 498 r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
0f474365
LP
499 if (r < 0) {
500 /* No context specified by the policy? Proceed without setting it. */
501 if (errno == ENOENT)
502 return 0;
2d58aa46 503
65804d6a 504 return log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
66b6d9d5
WC
505 }
506
65804d6a
LP
507 if (setfscreatecon_raw(filecon) < 0)
508 return log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
66b6d9d5 509
0f474365 510 return 0;
66b6d9d5 511}
7e531a52
FB
512#endif
513
514int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
7e531a52
FB
515#if HAVE_SELINUX
516 _cleanup_free_ char *abspath = NULL;
65804d6a
LP
517 int r;
518
7e531a52
FB
519 assert(path);
520
521 if (!label_hnd)
522 return 0;
523
524 if (!path_is_absolute(path)) {
7e531a52 525 if (dirfd == AT_FDCWD)
4ede9802 526 r = safe_getcwd(&abspath);
7e531a52 527 else
4ede9802 528 r = fd_get_path(dirfd, &abspath);
7e531a52
FB
529 if (r < 0)
530 return r;
531
4ede9802 532 if (!path_extend(&abspath, path))
7e531a52 533 return -ENOMEM;
4ede9802
LP
534
535 path = abspath;
7e531a52
FB
536 }
537
65804d6a
LP
538 return selinux_create_file_prepare_abspath(path, mode);
539#else
540 return 0;
7e531a52 541#endif
7e531a52
FB
542}
543
544int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
7e531a52 545#if HAVE_SELINUX
65804d6a
LP
546 int r;
547
7e531a52
FB
548 _cleanup_free_ char *abspath = NULL;
549
550 assert(path);
551
552 if (!label_hnd)
553 return 0;
554
555 r = path_make_absolute_cwd(path, &abspath);
556 if (r < 0)
557 return r;
558
65804d6a
LP
559 return selinux_create_file_prepare_abspath(abspath, mode);
560#else
561 return 0;
7e531a52 562#endif
7e531a52 563}
66b6d9d5 564
ecabcf8b 565void mac_selinux_create_file_clear(void) {
66b6d9d5 566
349cc4a5 567#if HAVE_SELINUX
66b6d9d5
WC
568 PROTECT_ERRNO;
569
6baa7db0 570 if (!mac_selinux_use())
66b6d9d5
WC
571 return;
572
a1d2de07 573 setfscreatecon_raw(NULL);
66b6d9d5
WC
574#endif
575}
576
ecabcf8b 577int mac_selinux_create_socket_prepare(const char *label) {
66b6d9d5 578
349cc4a5 579#if HAVE_SELINUX
ecabcf8b
LP
580 assert(label);
581
65804d6a
LP
582 if (!mac_selinux_use())
583 return 0;
ecabcf8b 584
65804d6a
LP
585 if (setsockcreatecon(label) < 0)
586 return log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
66b6d9d5 587#endif
ecabcf8b
LP
588
589 return 0;
66b6d9d5
WC
590}
591
ecabcf8b 592void mac_selinux_create_socket_clear(void) {
66b6d9d5 593
349cc4a5 594#if HAVE_SELINUX
ecabcf8b
LP
595 PROTECT_ERRNO;
596
6baa7db0 597 if (!mac_selinux_use())
66b6d9d5
WC
598 return;
599
a1d2de07 600 setsockcreatecon_raw(NULL);
66b6d9d5
WC
601#endif
602}
603
cc56fafe 604int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
66b6d9d5
WC
605
606 /* Binds a socket and label its file system object according to the SELinux policy */
607
349cc4a5 608#if HAVE_SELINUX
2ed96880 609 _cleanup_freecon_ char *fcon = NULL;
66b6d9d5 610 const struct sockaddr_un *un;
0f474365 611 bool context_changed = false;
66b6d9d5
WC
612 char *path;
613 int r;
614
615 assert(fd >= 0);
616 assert(addr);
617 assert(addrlen >= sizeof(sa_family_t));
618
ecabcf8b 619 if (!label_hnd)
66b6d9d5
WC
620 goto skipped;
621
622 /* Filter out non-local sockets */
623 if (addr->sa_family != AF_UNIX)
624 goto skipped;
625
626 /* Filter out anonymous sockets */
0f474365 627 if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
66b6d9d5
WC
628 goto skipped;
629
630 /* Filter out abstract namespace sockets */
631 un = (const struct sockaddr_un*) addr;
632 if (un->sun_path[0] == 0)
633 goto skipped;
634
635 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
636
61f3e897 637 /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
fd5e402f 638 mac_selinux_maybe_reload();
7960ba96
ZJS
639 if (!label_hnd)
640 goto skipped;
61f3e897 641
66b6d9d5
WC
642 if (path_is_absolute(path))
643 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
644 else {
0f474365 645 _cleanup_free_ char *newpath = NULL;
66b6d9d5 646
0f474365
LP
647 r = path_make_absolute_cwd(path, &newpath);
648 if (r < 0)
649 return r;
66b6d9d5
WC
650
651 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
652 }
653
0f474365
LP
654 if (r < 0) {
655 /* No context specified by the policy? Proceed without setting it */
656 if (errno == ENOENT)
657 goto skipped;
66b6d9d5 658
65804d6a
LP
659 r = log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
660 if (r < 0)
661 return r;
0f474365 662 } else {
a1d2de07 663 if (setfscreatecon_raw(fcon) < 0) {
65804d6a
LP
664 r = log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
665 if (r < 0)
666 return r;
0f474365
LP
667 } else
668 context_changed = true;
66b6d9d5
WC
669 }
670
0f474365
LP
671 r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
672
673 if (context_changed)
65804d6a 674 (void) setfscreatecon_raw(NULL);
66b6d9d5 675
66b6d9d5
WC
676 return r;
677
678skipped:
679#endif
0f474365
LP
680 if (bind(fd, addr, addrlen) < 0)
681 return -errno;
682
683 return 0;
66b6d9d5 684}