chiark / gitweb /
selinux: mount /sys, /proc, /dev before we load the SELinux policy
[elogind.git] / src / label.c
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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <malloc.h>
26
27 #include "label.h"
28 #include "util.h"
29
30 #ifdef HAVE_SELINUX
31 #include <selinux/selinux.h>
32 #include <selinux/label.h>
33
34 static struct selabel_handle *label_hnd = NULL;
35
36 static inline bool use_selinux(void) {
37         static int use_selinux_cached = -1;
38
39         if (use_selinux_cached < 0)
40                 use_selinux_cached = is_selinux_enabled() > 0;
41
42         return use_selinux_cached;
43 }
44
45 #endif
46
47 int label_init(void) {
48         int r = 0;
49
50 #ifdef HAVE_SELINUX
51         usec_t before_timestamp, after_timestamp;
52         struct mallinfo before_mallinfo, after_mallinfo;
53
54         if (!use_selinux())
55                 return 0;
56
57         if (label_hnd)
58                 return 0;
59
60         before_mallinfo = mallinfo();
61         before_timestamp = now(CLOCK_MONOTONIC);
62
63         label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
64         if (!label_hnd) {
65                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
66                          "Failed to initialize SELinux context: %m");
67                 r = security_getenforce() == 1 ? -errno : 0;
68         } else  {
69                 char timespan[FORMAT_TIMESPAN_MAX];
70                 int l;
71
72                 after_timestamp = now(CLOCK_MONOTONIC);
73                 after_mallinfo = mallinfo();
74
75                 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
76
77                 log_info("Successfully loaded SELinux database in %s, size on heap is %iK.",
78                          format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp),
79                          (l+1023)/1024);
80         }
81 #endif
82
83         return r;
84 }
85
86 int label_fix(const char *path, bool ignore_enoent) {
87         int r = 0;
88
89 #ifdef HAVE_SELINUX
90         struct stat st;
91         security_context_t fcon;
92
93         if (!use_selinux() || !label_hnd)
94                 return 0;
95
96         r = lstat(path, &st);
97         if (r == 0) {
98                 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
99
100                 /* If there's no label to set, then exit without warning */
101                 if (r < 0 && errno == ENOENT)
102                         return 0;
103
104                 if (r == 0) {
105                         r = setfilecon(path, fcon);
106                         freecon(fcon);
107
108                         /* If the FS doesn't support labels, then exit without warning */
109                         if (r < 0 && errno == ENOTSUP)
110                                 return 0;
111                 }
112         }
113
114         if (r < 0) {
115                 /* Ignore ENOENT in some cases */
116                 if (ignore_enoent && errno == ENOENT)
117                         return 0;
118
119                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
120                          "Unable to fix label of %s: %m", path);
121                 r = security_getenforce() == 1 ? -errno : 0;
122         }
123 #endif
124
125         return r;
126 }
127
128 void label_finish(void) {
129
130 #ifdef HAVE_SELINUX
131         if (use_selinux() && label_hnd)
132                 selabel_close(label_hnd);
133 #endif
134 }
135
136 int label_get_create_label_from_exe(const char *exe, char **label) {
137
138         int r = 0;
139
140 #ifdef HAVE_SELINUX
141         security_context_t mycon = NULL, fcon = NULL;
142         security_class_t sclass;
143
144         if (!use_selinux()) {
145                 *label = NULL;
146                 return 0;
147         }
148
149         r = getcon(&mycon);
150         if (r < 0)
151                 goto fail;
152
153         r = getfilecon(exe, &fcon);
154         if (r < 0)
155                 goto fail;
156
157         sclass = string_to_security_class("process");
158         r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
159         if (r == 0)
160                 log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
161
162 fail:
163         if (r < 0 && security_getenforce() == 1)
164                 r = -errno;
165
166         freecon(mycon);
167         freecon(fcon);
168 #endif
169
170         return r;
171 }
172
173 int label_fifofile_set(const char *path) {
174         int r = 0;
175
176 #ifdef HAVE_SELINUX
177         security_context_t filecon = NULL;
178
179         if (!use_selinux() || !label_hnd)
180                 return 0;
181
182         if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFIFO)) == 0) {
183                 if ((r = setfscreatecon(filecon)) < 0) {
184                         log_error("Failed to set SELinux file context on %s: %m", path);
185                         r = -errno;
186                 }
187
188                 freecon(filecon);
189         }
190
191         if (r < 0 && security_getenforce() == 0)
192                 r = 0;
193 #endif
194
195         return r;
196 }
197
198 int label_symlinkfile_set(const char *path) {
199         int r = 0;
200
201 #ifdef HAVE_SELINUX
202         security_context_t filecon = NULL;
203
204         if (!use_selinux() || !label_hnd)
205                 return 0;
206
207         if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFLNK)) == 0) {
208                 if ((r = setfscreatecon(filecon)) < 0) {
209                         log_error("Failed to set SELinux file context on %s: %m", path);
210                         r = -errno;
211                 }
212
213                 freecon(filecon);
214         }
215
216         if (r < 0 && security_getenforce() == 0)
217                 r = 0;
218 #endif
219
220         return r;
221 }
222
223 int label_socket_set(const char *label) {
224
225 #ifdef HAVE_SELINUX
226         if (!use_selinux())
227                 return 0;
228
229         if (setsockcreatecon((security_context_t) label) < 0) {
230                 log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
231                          "Failed to set SELinux context (%s) on socket: %m", label);
232
233                 if (security_getenforce() == 1)
234                         return -errno;
235         }
236 #endif
237
238         return 0;
239 }
240
241 void label_file_clear(void) {
242
243 #ifdef HAVE_SELINUX
244         if (!use_selinux())
245                 return;
246
247         setfscreatecon(NULL);
248 #endif
249 }
250
251 void label_socket_clear(void) {
252
253 #ifdef HAVE_SELINUX
254         if (!use_selinux())
255                 return;
256
257         setsockcreatecon(NULL);
258 #endif
259 }
260
261 void label_free(const char *label) {
262
263 #ifdef HAVE_SELINUX
264         if (!use_selinux())
265                 return;
266
267         freecon((security_context_t) label);
268 #endif
269 }
270
271 int label_mkdir(
272         const char *path,
273         mode_t mode) {
274
275         /* Creates a directory and labels it according to the SELinux policy */
276
277 #ifdef HAVE_SELINUX
278         int r;
279         security_context_t fcon = NULL;
280
281         if (use_selinux() && label_hnd) {
282
283                 if (path_is_absolute(path))
284                         r = selabel_lookup_raw(label_hnd, &fcon, path, mode);
285                 else {
286                         char *newpath = NULL;
287
288                         if (!(newpath = path_make_absolute_cwd(path)))
289                                 return -ENOMEM;
290
291                         r = selabel_lookup_raw(label_hnd, &fcon, newpath, mode);
292                         free(newpath);
293                 }
294
295                 if (r == 0)
296                         r = setfscreatecon(fcon);
297
298                 if (r < 0 && errno != ENOENT) {
299                         log_error("Failed to set security context %s for %s: %m", fcon, path);
300                         r = -errno;
301
302                         if (security_getenforce() == 1)
303                                 goto finish;
304                 }
305         }
306
307         if ((r = mkdir(path, mode)) < 0)
308                 r = -errno;
309
310 finish:
311         if (use_selinux() && label_hnd) {
312                 setfscreatecon(NULL);
313                 freecon(fcon);
314         }
315
316         return r;
317 #else
318         return mkdir(path, mode);
319 #endif
320 }