]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/selinux-util.c
dhcp6-option: Add helper function for uncompressed domain names
[thirdparty/systemd.git] / src / basic / selinux-util.c
CommitLineData
cad45ba1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
66b6d9d5 22#include <errno.h>
66b6d9d5
WC
23#include <malloc.h>
24#include <sys/un.h>
a07e9cfb 25
66b6d9d5
WC
26#ifdef HAVE_SELINUX
27#include <selinux/selinux.h>
28#include <selinux/label.h>
29#include <selinux/context.h>
30#endif
31
32#include "strv.h"
33#include "path-util.h"
cad45ba1
LP
34#include "selinux-util.h"
35
0b6018f3 36#ifdef HAVE_SELINUX
66b6d9d5
WC
37DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon);
38DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
0b6018f3 39
66b6d9d5
WC
40#define _cleanup_security_context_free_ _cleanup_(freeconp)
41#define _cleanup_context_free_ _cleanup_(context_freep)
0b6018f3 42
6baa7db0 43static int cached_use = -1;
66b6d9d5 44static struct selabel_handle *label_hnd = NULL;
66cedb30
LP
45
46#define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)
66b6d9d5 47#endif
cad45ba1 48
6baa7db0 49bool mac_selinux_use(void) {
66b6d9d5 50#ifdef HAVE_SELINUX
6baa7db0
LP
51 if (cached_use < 0)
52 cached_use = is_selinux_enabled() > 0;
cad45ba1 53
6baa7db0 54 return cached_use;
66b6d9d5
WC
55#else
56 return false;
57#endif
cad45ba1
LP
58}
59
6baa7db0 60void mac_selinux_retest(void) {
66b6d9d5 61#ifdef HAVE_SELINUX
6baa7db0 62 cached_use = -1;
66b6d9d5 63#endif
cad45ba1 64}
0b6018f3 65
cc56fafe 66int mac_selinux_init(const char *prefix) {
66b6d9d5 67 int r = 0;
d682b3a7 68
66b6d9d5
WC
69#ifdef HAVE_SELINUX
70 usec_t before_timestamp, after_timestamp;
71 struct mallinfo before_mallinfo, after_mallinfo;
72
6baa7db0 73 if (!mac_selinux_use())
66b6d9d5
WC
74 return 0;
75
76 if (label_hnd)
77 return 0;
78
79 before_mallinfo = mallinfo();
80 before_timestamp = now(CLOCK_MONOTONIC);
81
82 if (prefix) {
83 struct selinux_opt options[] = {
84 { .type = SELABEL_OPT_SUBSET, .value = prefix },
85 };
86
87 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
88 } else
89 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
90
91 if (!label_hnd) {
66cedb30 92 log_enforcing("Failed to initialize SELinux context: %m");
66b6d9d5
WC
93 r = security_getenforce() == 1 ? -errno : 0;
94 } else {
95 char timespan[FORMAT_TIMESPAN_MAX];
96 int l;
97
98 after_timestamp = now(CLOCK_MONOTONIC);
99 after_mallinfo = mallinfo();
100
101 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
102
103 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
104 format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
105 (l+1023)/1024);
106 }
107#endif
108
109 return r;
d682b3a7
LP
110}
111
ecabcf8b
LP
112void mac_selinux_finish(void) {
113
114#ifdef HAVE_SELINUX
115 if (!label_hnd)
116 return;
117
118 selabel_close(label_hnd);
f5ce2b49 119 label_hnd = NULL;
ecabcf8b
LP
120#endif
121}
122
cc56fafe 123int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
66b6d9d5
WC
124
125#ifdef HAVE_SELINUX
126 struct stat st;
ecabcf8b 127 int r;
66b6d9d5 128
5dfc5461
LP
129 assert(path);
130
131 /* if mac_selinux_init() wasn't called before we are a NOOP */
66b6d9d5
WC
132 if (!label_hnd)
133 return 0;
134
135 r = lstat(path, &st);
5dfc5461
LP
136 if (r >= 0) {
137 _cleanup_security_context_free_ security_context_t fcon = NULL;
138
66b6d9d5
WC
139 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
140
141 /* If there's no label to set, then exit without warning */
142 if (r < 0 && errno == ENOENT)
143 return 0;
144
5dfc5461 145 if (r >= 0) {
66b6d9d5 146 r = lsetfilecon(path, fcon);
66b6d9d5
WC
147
148 /* If the FS doesn't support labels, then exit without warning */
15411c0c 149 if (r < 0 && errno == EOPNOTSUPP)
66b6d9d5
WC
150 return 0;
151 }
152 }
153
154 if (r < 0) {
155 /* Ignore ENOENT in some cases */
156 if (ignore_enoent && errno == ENOENT)
157 return 0;
158
159 if (ignore_erofs && errno == EROFS)
160 return 0;
161
ecabcf8b
LP
162 log_enforcing("Unable to fix SELinux security context of %s: %m", path);
163 if (security_getenforce() == 1)
164 return -errno;
66b6d9d5
WC
165 }
166#endif
167
ecabcf8b 168 return 0;
66b6d9d5
WC
169}
170
ecabcf8b 171int mac_selinux_apply(const char *path, const char *label) {
66b6d9d5
WC
172
173#ifdef HAVE_SELINUX
ecabcf8b
LP
174 assert(path);
175 assert(label);
66b6d9d5 176
ecabcf8b
LP
177 if (!mac_selinux_use())
178 return 0;
179
180 if (setfilecon(path, (security_context_t) label) < 0) {
181 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
182 if (security_getenforce() == 1)
183 return -errno;
184 }
66b6d9d5 185#endif
ecabcf8b 186 return 0;
d682b3a7
LP
187}
188
cc56fafe 189int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
7f416dae 190 int r = -EOPNOTSUPP;
66b6d9d5
WC
191
192#ifdef HAVE_SELINUX
1ec220bc 193 _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL;
66b6d9d5
WC
194 security_class_t sclass;
195
7f416dae
LP
196 assert(exe);
197 assert(label);
198
199 if (!mac_selinux_use())
200 return -EOPNOTSUPP;
66b6d9d5
WC
201
202 r = getcon(&mycon);
203 if (r < 0)
7f416dae 204 return -errno;
66b6d9d5
WC
205
206 r = getfilecon(exe, &fcon);
207 if (r < 0)
7f416dae 208 return -errno;
66b6d9d5
WC
209
210 sclass = string_to_security_class("process");
211 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
7f416dae
LP
212 if (r < 0)
213 return -errno;
66b6d9d5
WC
214#endif
215
216 return r;
217}
218
cc56fafe 219int mac_selinux_get_our_label(char **label) {
66b6d9d5
WC
220 int r = -EOPNOTSUPP;
221
7f416dae
LP
222 assert(label);
223
66b6d9d5 224#ifdef HAVE_SELINUX
7f416dae
LP
225 if (!mac_selinux_use())
226 return -EOPNOTSUPP;
66b6d9d5 227
7f416dae 228 r = getcon(label);
66b6d9d5 229 if (r < 0)
7f416dae 230 return -errno;
0b6018f3 231#endif
66b6d9d5
WC
232
233 return r;
234}
235
9008e1ac 236int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
66b6d9d5
WC
237 int r = -EOPNOTSUPP;
238
239#ifdef HAVE_SELINUX
7f416dae 240 _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL;
66b6d9d5
WC
241 _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
242 security_class_t sclass;
66b6d9d5
WC
243 const char *range = NULL;
244
245 assert(socket_fd >= 0);
246 assert(exe);
247 assert(label);
248
7f416dae
LP
249 if (!mac_selinux_use())
250 return -EOPNOTSUPP;
251
66b6d9d5 252 r = getcon(&mycon);
7f416dae
LP
253 if (r < 0)
254 return -errno;
66b6d9d5
WC
255
256 r = getpeercon(socket_fd, &peercon);
7f416dae
LP
257 if (r < 0)
258 return -errno;
66b6d9d5 259
9008e1ac 260 if (!exec_label) {
66b6d9d5
WC
261 /* If there is no context set for next exec let's use context
262 of target executable */
263 r = getfilecon(exe, &fcon);
7f416dae
LP
264 if (r < 0)
265 return -errno;
66b6d9d5
WC
266 }
267
268 bcon = context_new(mycon);
7f416dae
LP
269 if (!bcon)
270 return -ENOMEM;
66b6d9d5
WC
271
272 pcon = context_new(peercon);
7f416dae
LP
273 if (!pcon)
274 return -ENOMEM;
66b6d9d5
WC
275
276 range = context_range_get(pcon);
7f416dae
LP
277 if (!range)
278 return -errno;
66b6d9d5
WC
279
280 r = context_range_set(bcon, range);
7f416dae
LP
281 if (r)
282 return -errno;
66b6d9d5
WC
283
284 freecon(mycon);
285 mycon = strdup(context_str(bcon));
7f416dae
LP
286 if (!mycon)
287 return -ENOMEM;
66b6d9d5
WC
288
289 sclass = string_to_security_class("process");
7f416dae
LP
290 r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
291 if (r < 0)
292 return -errno;
66b6d9d5 293#endif
7f416dae 294
66b6d9d5
WC
295 return r;
296}
297
ecabcf8b
LP
298void mac_selinux_free(char *label) {
299
300#ifdef HAVE_SELINUX
301 if (!mac_selinux_use())
302 return;
303
304 freecon((security_context_t) label);
305#endif
306}
307
308int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
66b6d9d5
WC
309 int r = 0;
310
311#ifdef HAVE_SELINUX
1ec220bc 312 _cleanup_security_context_free_ security_context_t filecon = NULL;
66b6d9d5 313
ecabcf8b
LP
314 assert(path);
315
66cedb30 316 if (!label_hnd)
66b6d9d5
WC
317 return 0;
318
c34255bd
LP
319 if (path_is_absolute(path))
320 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
321 else {
322 _cleanup_free_ char *newpath;
323
324 newpath = path_make_absolute_cwd(path);
325 if (!newpath)
326 return -ENOMEM;
327
a07e9cfb 328 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
c34255bd
LP
329 }
330
2d58aa46
MS
331 /* No context specified by the policy? Proceed without setting it. */
332 if (r < 0 && errno == ENOENT)
333 return 0;
334
335 if (r < 0)
66b6d9d5 336 r = -errno;
2d58aa46 337 else {
66b6d9d5
WC
338 r = setfscreatecon(filecon);
339 if (r < 0) {
ecabcf8b 340 log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
66b6d9d5
WC
341 r = -errno;
342 }
66b6d9d5
WC
343 }
344
345 if (r < 0 && security_getenforce() == 0)
346 r = 0;
347#endif
348
349 return r;
350}
351
ecabcf8b 352void mac_selinux_create_file_clear(void) {
66b6d9d5
WC
353
354#ifdef HAVE_SELINUX
355 PROTECT_ERRNO;
356
6baa7db0 357 if (!mac_selinux_use())
66b6d9d5
WC
358 return;
359
360 setfscreatecon(NULL);
361#endif
362}
363
ecabcf8b 364int mac_selinux_create_socket_prepare(const char *label) {
66b6d9d5
WC
365
366#ifdef HAVE_SELINUX
6baa7db0 367 if (!mac_selinux_use())
ecabcf8b 368 return 0;
66b6d9d5 369
ecabcf8b
LP
370 assert(label);
371
372 if (setsockcreatecon((security_context_t) label) < 0) {
373 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
374
375 if (security_getenforce() == 1)
376 return -errno;
377 }
66b6d9d5 378#endif
ecabcf8b
LP
379
380 return 0;
66b6d9d5
WC
381}
382
ecabcf8b 383void mac_selinux_create_socket_clear(void) {
66b6d9d5
WC
384
385#ifdef HAVE_SELINUX
ecabcf8b
LP
386 PROTECT_ERRNO;
387
6baa7db0 388 if (!mac_selinux_use())
66b6d9d5
WC
389 return;
390
ecabcf8b 391 setsockcreatecon(NULL);
66b6d9d5
WC
392#endif
393}
394
cc56fafe 395int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
66b6d9d5
WC
396
397 /* Binds a socket and label its file system object according to the SELinux policy */
398
399#ifdef HAVE_SELINUX
1ec220bc 400 _cleanup_security_context_free_ security_context_t fcon = NULL;
66b6d9d5
WC
401 const struct sockaddr_un *un;
402 char *path;
403 int r;
404
405 assert(fd >= 0);
406 assert(addr);
407 assert(addrlen >= sizeof(sa_family_t));
408
ecabcf8b 409 if (!label_hnd)
66b6d9d5
WC
410 goto skipped;
411
412 /* Filter out non-local sockets */
413 if (addr->sa_family != AF_UNIX)
414 goto skipped;
415
416 /* Filter out anonymous sockets */
417 if (addrlen < sizeof(sa_family_t) + 1)
418 goto skipped;
419
420 /* Filter out abstract namespace sockets */
421 un = (const struct sockaddr_un*) addr;
422 if (un->sun_path[0] == 0)
423 goto skipped;
424
425 path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
426
427 if (path_is_absolute(path))
428 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
429 else {
430 _cleanup_free_ char *newpath;
431
432 newpath = path_make_absolute_cwd(path);
433 if (!newpath)
434 return -ENOMEM;
435
436 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
437 }
438
439 if (r == 0)
440 r = setfscreatecon(fcon);
441
442 if (r < 0 && errno != ENOENT) {
ecabcf8b 443 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
66b6d9d5
WC
444
445 if (security_getenforce() == 1) {
446 r = -errno;
447 goto finish;
448 }
449 }
450
451 r = bind(fd, addr, addrlen);
452 if (r < 0)
453 r = -errno;
454
455finish:
456 setfscreatecon(NULL);
66b6d9d5
WC
457 return r;
458
459skipped:
460#endif
461 return bind(fd, addr, addrlen) < 0 ? -errno : 0;
462}