]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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 |
66b6d9d5 | 32 | DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free); |
66b6d9d5 | 33 | #define _cleanup_context_free_ _cleanup_(context_freep) |
0b6018f3 | 34 | |
61f3e897 CG |
35 | static int mac_selinux_reload(int seqno); |
36 | ||
6baa7db0 | 37 | static int cached_use = -1; |
257188f8 | 38 | static int cached_enforcing = -1; |
66b6d9d5 | 39 | static struct selabel_handle *label_hnd = NULL; |
66cedb30 | 40 | |
257188f8 CG |
41 | #define log_enforcing(...) log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__) |
42 | #define log_enforcing_errno(r, ...) log_full_errno(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, r, __VA_ARGS__) | |
66b6d9d5 | 43 | #endif |
cad45ba1 | 44 | |
6d395665 | 45 | bool mac_selinux_use(void) { |
349cc4a5 | 46 | #if HAVE_SELINUX |
2073bf3f | 47 | if (_unlikely_(cached_use < 0)) { |
6baa7db0 | 48 | cached_use = is_selinux_enabled() > 0; |
2073bf3f CG |
49 | log_debug("SELinux enabled state cached to: %s", cached_use ? "enabled" : "disabled"); |
50 | } | |
cad45ba1 | 51 | |
6baa7db0 | 52 | return cached_use; |
66b6d9d5 WC |
53 | #else |
54 | return false; | |
55 | #endif | |
cad45ba1 LP |
56 | } |
57 | ||
257188f8 CG |
58 | bool mac_selinux_enforcing(void) { |
59 | #if HAVE_SELINUX | |
c8aa389c | 60 | if (_unlikely_(cached_enforcing < 0)) { |
257188f8 | 61 | cached_enforcing = security_getenforce(); |
2073bf3f CG |
62 | if (cached_enforcing == -1) |
63 | log_error_errno(errno, "Failed to get SELinux enforced status, continue in enforcing mode: %m"); | |
64 | else | |
65 | log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive"); | |
257188f8 CG |
66 | } |
67 | ||
2073bf3f | 68 | /* treat failure as enforcing mode */ |
257188f8 CG |
69 | return (cached_enforcing != 0); |
70 | #else | |
71 | return false; | |
72 | #endif | |
73 | } | |
74 | ||
6baa7db0 | 75 | void mac_selinux_retest(void) { |
349cc4a5 | 76 | #if HAVE_SELINUX |
6baa7db0 | 77 | cached_use = -1; |
257188f8 | 78 | cached_enforcing = -1; |
66b6d9d5 | 79 | #endif |
cad45ba1 | 80 | } |
0b6018f3 | 81 | |
257188f8 CG |
82 | #if HAVE_SELINUX |
83 | static int setenforce_callback(int enforcing) { | |
84 | cached_enforcing = enforcing; | |
85 | ||
2073bf3f CG |
86 | log_debug("SELinux enforcing state updated to: %s", cached_enforcing ? "enforcing" : "permissive"); |
87 | ||
257188f8 CG |
88 | return 0; |
89 | } | |
90 | #endif | |
91 | ||
c3dacc8b | 92 | int mac_selinux_init(void) { |
66b6d9d5 | 93 | int r = 0; |
d682b3a7 | 94 | |
349cc4a5 | 95 | #if HAVE_SELINUX |
66b6d9d5 WC |
96 | usec_t before_timestamp, after_timestamp; |
97 | struct mallinfo before_mallinfo, after_mallinfo; | |
98 | ||
61f3e897 | 99 | selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload); |
257188f8 | 100 | selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_callback); |
61f3e897 | 101 | |
c3dacc8b | 102 | if (label_hnd) |
66b6d9d5 WC |
103 | return 0; |
104 | ||
c3dacc8b | 105 | if (!mac_selinux_use()) |
66b6d9d5 WC |
106 | return 0; |
107 | ||
108 | before_mallinfo = mallinfo(); | |
109 | before_timestamp = now(CLOCK_MONOTONIC); | |
110 | ||
c3dacc8b | 111 | label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); |
66b6d9d5 | 112 | if (!label_hnd) { |
b8b846d7 | 113 | log_enforcing_errno(errno, "Failed to initialize SELinux context: %m"); |
257188f8 | 114 | r = mac_selinux_enforcing() ? -errno : 0; |
66b6d9d5 WC |
115 | } else { |
116 | char timespan[FORMAT_TIMESPAN_MAX]; | |
117 | int l; | |
118 | ||
119 | after_timestamp = now(CLOCK_MONOTONIC); | |
120 | after_mallinfo = mallinfo(); | |
121 | ||
122 | l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0; | |
123 | ||
124 | log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.", | |
125 | format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0), | |
126 | (l+1023)/1024); | |
127 | } | |
128 | #endif | |
129 | ||
130 | return r; | |
d682b3a7 LP |
131 | } |
132 | ||
ecabcf8b LP |
133 | void mac_selinux_finish(void) { |
134 | ||
349cc4a5 | 135 | #if HAVE_SELINUX |
ecabcf8b LP |
136 | if (!label_hnd) |
137 | return; | |
138 | ||
139 | selabel_close(label_hnd); | |
f5ce2b49 | 140 | label_hnd = NULL; |
ecabcf8b LP |
141 | #endif |
142 | } | |
143 | ||
a9dfac21 | 144 | #if HAVE_SELINUX |
61f3e897 | 145 | static int mac_selinux_reload(int seqno) { |
a9dfac21 CG |
146 | struct selabel_handle *backup_label_hnd; |
147 | ||
148 | if (!label_hnd) | |
61f3e897 | 149 | return 0; |
a9dfac21 CG |
150 | |
151 | backup_label_hnd = TAKE_PTR(label_hnd); | |
152 | ||
153 | /* try to initialize new handle | |
154 | * on success close backup | |
155 | * on failure restore backup */ | |
156 | if (mac_selinux_init() == 0) | |
157 | selabel_close(backup_label_hnd); | |
158 | else | |
159 | label_hnd = backup_label_hnd; | |
61f3e897 CG |
160 | |
161 | return 0; | |
a9dfac21 | 162 | } |
61f3e897 | 163 | #endif |
a9dfac21 | 164 | |
c3151977 | 165 | int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) { |
66b6d9d5 | 166 | |
349cc4a5 | 167 | #if HAVE_SELINUX |
08c84981 LP |
168 | char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; |
169 | _cleanup_freecon_ char* fcon = NULL; | |
170 | _cleanup_close_ int fd = -1; | |
66b6d9d5 | 171 | struct stat st; |
ecabcf8b | 172 | int r; |
66b6d9d5 | 173 | |
5dfc5461 LP |
174 | assert(path); |
175 | ||
176 | /* if mac_selinux_init() wasn't called before we are a NOOP */ | |
66b6d9d5 WC |
177 | if (!label_hnd) |
178 | return 0; | |
179 | ||
08c84981 LP |
180 | /* Open the file as O_PATH, to pin it while we determine and adjust the label */ |
181 | fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); | |
182 | if (fd < 0) { | |
183 | if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) | |
184 | return 0; | |
185 | ||
186 | return -errno; | |
187 | } | |
188 | ||
189 | if (fstat(fd, &st) < 0) | |
190 | return -errno; | |
5dfc5461 | 191 | |
61f3e897 CG |
192 | /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ |
193 | (void) avc_netlink_check_nb(); | |
194 | ||
c3151977 | 195 | if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) { |
08c84981 | 196 | r = -errno; |
66b6d9d5 WC |
197 | |
198 | /* If there's no label to set, then exit without warning */ | |
08c84981 | 199 | if (r == -ENOENT) |
66b6d9d5 WC |
200 | return 0; |
201 | ||
08c84981 | 202 | goto fail; |
66b6d9d5 WC |
203 | } |
204 | ||
08c84981 LP |
205 | xsprintf(procfs_path, "/proc/self/fd/%i", fd); |
206 | if (setfilecon_raw(procfs_path, fcon) < 0) { | |
207 | _cleanup_freecon_ char *oldcon = NULL; | |
208 | ||
209 | r = -errno; | |
210 | ||
211 | /* If the FS doesn't support labels, then exit without warning */ | |
212 | if (r == -EOPNOTSUPP) | |
66b6d9d5 WC |
213 | return 0; |
214 | ||
08c84981 LP |
215 | /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */ |
216 | if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) | |
66b6d9d5 WC |
217 | return 0; |
218 | ||
08c84981 LP |
219 | /* If the old label is identical to the new one, suppress any kind of error */ |
220 | if (getfilecon_raw(procfs_path, &oldcon) >= 0 && streq(fcon, oldcon)) | |
221 | return 0; | |
222 | ||
223 | goto fail; | |
66b6d9d5 | 224 | } |
08c84981 LP |
225 | |
226 | return 0; | |
227 | ||
228 | fail: | |
c3151977 | 229 | log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path); |
257188f8 | 230 | if (mac_selinux_enforcing()) |
08c84981 | 231 | return r; |
66b6d9d5 WC |
232 | #endif |
233 | ||
ecabcf8b | 234 | return 0; |
66b6d9d5 WC |
235 | } |
236 | ||
ecabcf8b | 237 | int mac_selinux_apply(const char *path, const char *label) { |
66b6d9d5 | 238 | |
349cc4a5 | 239 | #if HAVE_SELINUX |
ecabcf8b LP |
240 | if (!mac_selinux_use()) |
241 | return 0; | |
242 | ||
0f474365 LP |
243 | assert(path); |
244 | assert(label); | |
245 | ||
2ed96880 | 246 | if (setfilecon(path, label) < 0) { |
b8b846d7 | 247 | log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path); |
257188f8 | 248 | if (mac_selinux_enforcing()) |
ecabcf8b LP |
249 | return -errno; |
250 | } | |
66b6d9d5 | 251 | #endif |
ecabcf8b | 252 | return 0; |
d682b3a7 LP |
253 | } |
254 | ||
cc56fafe | 255 | int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { |
7f416dae | 256 | int r = -EOPNOTSUPP; |
66b6d9d5 | 257 | |
349cc4a5 | 258 | #if HAVE_SELINUX |
2ed96880 | 259 | _cleanup_freecon_ char *mycon = NULL, *fcon = NULL; |
66b6d9d5 WC |
260 | security_class_t sclass; |
261 | ||
7f416dae LP |
262 | assert(exe); |
263 | assert(label); | |
264 | ||
6d395665 | 265 | if (!mac_selinux_use()) |
7f416dae | 266 | return -EOPNOTSUPP; |
66b6d9d5 | 267 | |
24154879 | 268 | r = getcon_raw(&mycon); |
66b6d9d5 | 269 | if (r < 0) |
7f416dae | 270 | return -errno; |
66b6d9d5 | 271 | |
24154879 | 272 | r = getfilecon_raw(exe, &fcon); |
66b6d9d5 | 273 | if (r < 0) |
7f416dae | 274 | return -errno; |
66b6d9d5 WC |
275 | |
276 | sclass = string_to_security_class("process"); | |
fdb0405e CG |
277 | if (sclass == 0) |
278 | return -ENOSYS; | |
279 | ||
2ed96880 | 280 | r = security_compute_create_raw(mycon, fcon, sclass, label); |
7f416dae LP |
281 | if (r < 0) |
282 | return -errno; | |
66b6d9d5 WC |
283 | #endif |
284 | ||
285 | return r; | |
286 | } | |
287 | ||
cc56fafe | 288 | int mac_selinux_get_our_label(char **label) { |
66b6d9d5 WC |
289 | int r = -EOPNOTSUPP; |
290 | ||
7f416dae LP |
291 | assert(label); |
292 | ||
349cc4a5 | 293 | #if HAVE_SELINUX |
6d395665 | 294 | if (!mac_selinux_use()) |
7f416dae | 295 | return -EOPNOTSUPP; |
66b6d9d5 | 296 | |
24154879 | 297 | r = getcon_raw(label); |
66b6d9d5 | 298 | if (r < 0) |
7f416dae | 299 | return -errno; |
0b6018f3 | 300 | #endif |
66b6d9d5 WC |
301 | |
302 | return r; | |
303 | } | |
304 | ||
9008e1ac | 305 | int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) { |
66b6d9d5 WC |
306 | int r = -EOPNOTSUPP; |
307 | ||
349cc4a5 | 308 | #if HAVE_SELINUX |
2ed96880 | 309 | _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL; |
66b6d9d5 WC |
310 | _cleanup_context_free_ context_t pcon = NULL, bcon = NULL; |
311 | security_class_t sclass; | |
66b6d9d5 WC |
312 | const char *range = NULL; |
313 | ||
314 | assert(socket_fd >= 0); | |
315 | assert(exe); | |
316 | assert(label); | |
317 | ||
6d395665 | 318 | if (!mac_selinux_use()) |
7f416dae LP |
319 | return -EOPNOTSUPP; |
320 | ||
24154879 | 321 | r = getcon_raw(&mycon); |
7f416dae LP |
322 | if (r < 0) |
323 | return -errno; | |
66b6d9d5 | 324 | |
a1d2de07 | 325 | r = getpeercon_raw(socket_fd, &peercon); |
7f416dae LP |
326 | if (r < 0) |
327 | return -errno; | |
66b6d9d5 | 328 | |
9008e1ac | 329 | if (!exec_label) { |
66b6d9d5 WC |
330 | /* If there is no context set for next exec let's use context |
331 | of target executable */ | |
24154879 | 332 | r = getfilecon_raw(exe, &fcon); |
7f416dae LP |
333 | if (r < 0) |
334 | return -errno; | |
66b6d9d5 WC |
335 | } |
336 | ||
337 | bcon = context_new(mycon); | |
7f416dae LP |
338 | if (!bcon) |
339 | return -ENOMEM; | |
66b6d9d5 WC |
340 | |
341 | pcon = context_new(peercon); | |
7f416dae LP |
342 | if (!pcon) |
343 | return -ENOMEM; | |
66b6d9d5 WC |
344 | |
345 | range = context_range_get(pcon); | |
7f416dae LP |
346 | if (!range) |
347 | return -errno; | |
66b6d9d5 WC |
348 | |
349 | r = context_range_set(bcon, range); | |
7f416dae LP |
350 | if (r) |
351 | return -errno; | |
66b6d9d5 WC |
352 | |
353 | freecon(mycon); | |
354 | mycon = strdup(context_str(bcon)); | |
7f416dae LP |
355 | if (!mycon) |
356 | return -ENOMEM; | |
66b6d9d5 WC |
357 | |
358 | sclass = string_to_security_class("process"); | |
fdb0405e CG |
359 | if (sclass == 0) |
360 | return -ENOSYS; | |
361 | ||
2ed96880 | 362 | r = security_compute_create_raw(mycon, fcon, sclass, label); |
7f416dae LP |
363 | if (r < 0) |
364 | return -errno; | |
66b6d9d5 | 365 | #endif |
7f416dae | 366 | |
66b6d9d5 WC |
367 | return r; |
368 | } | |
369 | ||
710a6b50 | 370 | char* mac_selinux_free(char *label) { |
ecabcf8b | 371 | |
349cc4a5 | 372 | #if HAVE_SELINUX |
710a6b50 LP |
373 | if (!label) |
374 | return NULL; | |
375 | ||
6d395665 | 376 | if (!mac_selinux_use()) |
710a6b50 LP |
377 | return NULL; |
378 | ||
2ed96880 | 379 | freecon(label); |
ecabcf8b | 380 | #endif |
710a6b50 LP |
381 | |
382 | return NULL; | |
ecabcf8b LP |
383 | } |
384 | ||
349cc4a5 | 385 | #if HAVE_SELINUX |
7e531a52 | 386 | static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) { |
2ed96880 | 387 | _cleanup_freecon_ char *filecon = NULL; |
0f474365 | 388 | int r; |
66b6d9d5 | 389 | |
7e531a52 FB |
390 | assert(abspath); |
391 | assert(path_is_absolute(abspath)); | |
c34255bd | 392 | |
61f3e897 CG |
393 | /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ |
394 | (void) avc_netlink_check_nb(); | |
395 | ||
7e531a52 | 396 | r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode); |
0f474365 LP |
397 | if (r < 0) { |
398 | /* No context specified by the policy? Proceed without setting it. */ | |
399 | if (errno == ENOENT) | |
400 | return 0; | |
2d58aa46 | 401 | |
7e531a52 | 402 | log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath); |
0f474365 | 403 | } else { |
5c5433ad | 404 | if (setfscreatecon_raw(filecon) >= 0) |
0f474365 LP |
405 | return 0; /* Success! */ |
406 | ||
7e531a52 | 407 | log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath); |
66b6d9d5 WC |
408 | } |
409 | ||
257188f8 | 410 | if (mac_selinux_enforcing()) |
0f474365 | 411 | return -errno; |
66b6d9d5 | 412 | |
0f474365 | 413 | return 0; |
66b6d9d5 | 414 | } |
7e531a52 FB |
415 | #endif |
416 | ||
417 | int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) { | |
418 | int r = 0; | |
419 | ||
420 | #if HAVE_SELINUX | |
421 | _cleanup_free_ char *abspath = NULL; | |
7e531a52 FB |
422 | |
423 | assert(path); | |
424 | ||
425 | if (!label_hnd) | |
426 | return 0; | |
427 | ||
428 | if (!path_is_absolute(path)) { | |
429 | _cleanup_free_ char *p = NULL; | |
430 | ||
431 | if (dirfd == AT_FDCWD) | |
432 | r = safe_getcwd(&p); | |
433 | else | |
434 | r = fd_get_path(dirfd, &p); | |
435 | if (r < 0) | |
436 | return r; | |
437 | ||
62a85ee0 | 438 | path = abspath = path_join(p, path); |
30016f21 | 439 | if (!path) |
7e531a52 | 440 | return -ENOMEM; |
7e531a52 FB |
441 | } |
442 | ||
443 | r = selinux_create_file_prepare_abspath(path, mode); | |
444 | #endif | |
445 | return r; | |
446 | } | |
447 | ||
448 | int mac_selinux_create_file_prepare(const char *path, mode_t mode) { | |
449 | int r = 0; | |
450 | ||
451 | #if HAVE_SELINUX | |
452 | _cleanup_free_ char *abspath = NULL; | |
453 | ||
454 | assert(path); | |
455 | ||
456 | if (!label_hnd) | |
457 | return 0; | |
458 | ||
459 | r = path_make_absolute_cwd(path, &abspath); | |
460 | if (r < 0) | |
461 | return r; | |
462 | ||
463 | r = selinux_create_file_prepare_abspath(abspath, mode); | |
464 | #endif | |
465 | return r; | |
466 | } | |
66b6d9d5 | 467 | |
ecabcf8b | 468 | void mac_selinux_create_file_clear(void) { |
66b6d9d5 | 469 | |
349cc4a5 | 470 | #if HAVE_SELINUX |
66b6d9d5 WC |
471 | PROTECT_ERRNO; |
472 | ||
6baa7db0 | 473 | if (!mac_selinux_use()) |
66b6d9d5 WC |
474 | return; |
475 | ||
a1d2de07 | 476 | setfscreatecon_raw(NULL); |
66b6d9d5 WC |
477 | #endif |
478 | } | |
479 | ||
ecabcf8b | 480 | int mac_selinux_create_socket_prepare(const char *label) { |
66b6d9d5 | 481 | |
349cc4a5 | 482 | #if HAVE_SELINUX |
6baa7db0 | 483 | if (!mac_selinux_use()) |
ecabcf8b | 484 | return 0; |
66b6d9d5 | 485 | |
ecabcf8b LP |
486 | assert(label); |
487 | ||
2ed96880 | 488 | if (setsockcreatecon(label) < 0) { |
b8b846d7 | 489 | log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label); |
ecabcf8b | 490 | |
257188f8 | 491 | if (mac_selinux_enforcing()) |
ecabcf8b LP |
492 | return -errno; |
493 | } | |
66b6d9d5 | 494 | #endif |
ecabcf8b LP |
495 | |
496 | return 0; | |
66b6d9d5 WC |
497 | } |
498 | ||
ecabcf8b | 499 | void mac_selinux_create_socket_clear(void) { |
66b6d9d5 | 500 | |
349cc4a5 | 501 | #if HAVE_SELINUX |
ecabcf8b LP |
502 | PROTECT_ERRNO; |
503 | ||
6baa7db0 | 504 | if (!mac_selinux_use()) |
66b6d9d5 WC |
505 | return; |
506 | ||
a1d2de07 | 507 | setsockcreatecon_raw(NULL); |
66b6d9d5 WC |
508 | #endif |
509 | } | |
510 | ||
cc56fafe | 511 | int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { |
66b6d9d5 WC |
512 | |
513 | /* Binds a socket and label its file system object according to the SELinux policy */ | |
514 | ||
349cc4a5 | 515 | #if HAVE_SELINUX |
2ed96880 | 516 | _cleanup_freecon_ char *fcon = NULL; |
66b6d9d5 | 517 | const struct sockaddr_un *un; |
0f474365 | 518 | bool context_changed = false; |
66b6d9d5 WC |
519 | char *path; |
520 | int r; | |
521 | ||
522 | assert(fd >= 0); | |
523 | assert(addr); | |
524 | assert(addrlen >= sizeof(sa_family_t)); | |
525 | ||
ecabcf8b | 526 | if (!label_hnd) |
66b6d9d5 WC |
527 | goto skipped; |
528 | ||
529 | /* Filter out non-local sockets */ | |
530 | if (addr->sa_family != AF_UNIX) | |
531 | goto skipped; | |
532 | ||
533 | /* Filter out anonymous sockets */ | |
0f474365 | 534 | if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1) |
66b6d9d5 WC |
535 | goto skipped; |
536 | ||
537 | /* Filter out abstract namespace sockets */ | |
538 | un = (const struct sockaddr_un*) addr; | |
539 | if (un->sun_path[0] == 0) | |
540 | goto skipped; | |
541 | ||
542 | path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path)); | |
543 | ||
61f3e897 CG |
544 | /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ |
545 | (void) avc_netlink_check_nb(); | |
546 | ||
66b6d9d5 WC |
547 | if (path_is_absolute(path)) |
548 | r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); | |
549 | else { | |
0f474365 | 550 | _cleanup_free_ char *newpath = NULL; |
66b6d9d5 | 551 | |
0f474365 LP |
552 | r = path_make_absolute_cwd(path, &newpath); |
553 | if (r < 0) | |
554 | return r; | |
66b6d9d5 WC |
555 | |
556 | r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); | |
557 | } | |
558 | ||
0f474365 LP |
559 | if (r < 0) { |
560 | /* No context specified by the policy? Proceed without setting it */ | |
561 | if (errno == ENOENT) | |
562 | goto skipped; | |
66b6d9d5 | 563 | |
b8b846d7 | 564 | log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path); |
257188f8 | 565 | if (mac_selinux_enforcing()) |
0f474365 | 566 | return -errno; |
66b6d9d5 | 567 | |
0f474365 | 568 | } else { |
a1d2de07 | 569 | if (setfscreatecon_raw(fcon) < 0) { |
b8b846d7 | 570 | log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path); |
257188f8 | 571 | if (mac_selinux_enforcing()) |
0f474365 LP |
572 | return -errno; |
573 | } else | |
574 | context_changed = true; | |
66b6d9d5 WC |
575 | } |
576 | ||
0f474365 LP |
577 | r = bind(fd, addr, addrlen) < 0 ? -errno : 0; |
578 | ||
579 | if (context_changed) | |
a1d2de07 | 580 | setfscreatecon_raw(NULL); |
66b6d9d5 | 581 | |
66b6d9d5 WC |
582 | return r; |
583 | ||
584 | skipped: | |
585 | #endif | |
0f474365 LP |
586 | if (bind(fd, addr, addrlen) < 0) |
587 | return -errno; | |
588 | ||
589 | return 0; | |
66b6d9d5 | 590 | } |