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