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