]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/smack-setup.c
io.systemd.Unit.List fix context/runtime split (#38172)
[thirdparty/systemd.git] / src / core / smack-setup.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
ffbd2c4d 2/***
810adae9 3 Copyright © 2013 Intel Corporation
ffbd2c4d
NC
4 Authors:
5 Nathaniel Chen <nathaniel.chen@intel.com>
ffbd2c4d
NC
6***/
7
ffbd2c4d 8#include <fcntl.h>
07630cea 9#include <stdio.h>
ca78ad1d 10#include <unistd.h>
ffbd2c4d 11
ad5db940
OJ
12#include "sd-messages.h"
13
b5efdb8a 14#include "alloc-util.h"
a0956174 15#include "dirent-util.h"
3f181218 16#include "errno-util.h"
3ffd4af2 17#include "fd-util.h"
8b197c3a 18#include "fileio.h"
ffbd2c4d 19#include "log.h"
3ffd4af2 20#include "smack-setup.h"
07630cea 21#include "string-util.h"
ffbd2c4d 22
f9fa32f0 23#if ENABLE_SMACK
2b3e18de 24
b636d78a
ZJS
25static int fdopen_unlocked_at(int dfd, const char *dir, const char *name, int *status, FILE **ret_file) {
26 int fd, r;
27 FILE *f;
28
29 fd = openat(dfd, name, O_RDONLY|O_CLOEXEC);
30 if (fd < 0) {
31 if (*status == 0)
32 *status = -errno;
33
34 return log_warning_errno(errno, "Failed to open \"%s/%s\": %m", dir, name);
35 }
36
37 r = fdopen_unlocked(fd, "r", &f);
38 if (r < 0) {
39 if (*status == 0)
40 *status = r;
41
42 safe_close(fd);
43 return log_error_errno(r, "Failed to open \"%s/%s\": %m", dir, name);
44 }
45
46 *ret_file = f;
47 return 0;
48}
49
50static int write_access2_rules(const char *srcdir) {
254d1313 51 _cleanup_close_ int load2_fd = -EBADF, change_fd = -EBADF;
ffbd2c4d 52 _cleanup_closedir_ DIR *dir = NULL;
3f181218 53 int dfd, r;
ffbd2c4d 54
3f181218
ZJS
55 load2_fd = r = RET_NERRNO(open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY));
56 if (r < 0) {
57 if (r != -ENOENT)
58 log_warning_errno(r, "Failed to open %s: %m", "/sys/fs/smackfs/load2");
59 return r;
6656aefb
WC
60 }
61
3f181218
ZJS
62 change_fd = r = RET_NERRNO(open("/sys/fs/smackfs/change-rule", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY));
63 if (r < 0) {
64 if (r != -ENOENT)
65 log_warning_errno(r, "Failed to open %s: %m", "/sys/fs/smackfs/change-rule");
66 return r;
ffbd2c4d
NC
67 }
68
6656aefb 69 /* write rules to load2 or change-rule from every file in the directory */
a4783bd1 70 dir = opendir(srcdir);
ffbd2c4d 71 if (!dir) {
a4783bd1 72 if (errno != ENOENT)
5890a775 73 log_warning_errno(errno, "Failed to open %s/: %m", srcdir);
a4783bd1 74 return errno; /* positive on purpose */
ffbd2c4d
NC
75 }
76
77 dfd = dirfd(dir);
fea7838e 78 assert(dfd >= 0);
ffbd2c4d 79
3f181218 80 r = 0;
ffbd2c4d
NC
81 FOREACH_DIRENT(entry, dir, return 0) {
82 _cleanup_fclose_ FILE *policy = NULL;
ffbd2c4d 83
6656aefb
WC
84 if (!dirent_is_file(entry))
85 continue;
86
b636d78a 87 if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
ffbd2c4d 88 continue;
ffbd2c4d 89
ffbd2c4d 90 /* load2 write rules in the kernel require a line buffered stream */
ea8b6526
LP
91 for (;;) {
92 _cleanup_free_ char *buf = NULL, *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
93 int q;
6656aefb 94
ea8b6526
LP
95 q = read_line(policy, NAME_MAX, &buf);
96 if (q < 0)
5890a775 97 return log_error_errno(q, "%s/%s: failed to read line: %m", srcdir, entry->d_name);
ea8b6526
LP
98 if (q == 0)
99 break;
6656aefb 100
ea8b6526 101 if (isempty(buf) || strchr(COMMENTS, buf[0]))
6656aefb
WC
102 continue;
103
104 /* if 3 args -> load rule : subject object access1 */
105 /* if 4 args -> change rule : subject object access1 access2 */
106 if (sscanf(buf, "%ms %ms %ms %ms", &sbj, &obj, &acc1, &acc2) < 3) {
5890a775
ZJS
107 log_error_errno(errno, "%s/%s: failed to parse rule '%s', ignoring.",
108 srcdir, entry->d_name, buf);
6656aefb
WC
109 continue;
110 }
111
3f181218
ZJS
112 q = RET_NERRNO(write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)));
113 if (q < 0) {
114 log_error_errno(q, "%s/%s: failed to write '%s' to '%s': %m",
5890a775
ZJS
115 srcdir, entry->d_name,
116 buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule");
3f181218 117 RET_GATHER(r, q);
a4783bd1 118 }
6656aefb
WC
119 }
120 }
121
122 return r;
123}
124
b636d78a 125static int write_cipso2_rules(const char *srcdir) {
254d1313 126 _cleanup_close_ int cipso2_fd = -EBADF;
6656aefb 127 _cleanup_closedir_ DIR *dir = NULL;
3f181218 128 int dfd, r;
6656aefb 129
3f181218
ZJS
130 cipso2_fd = r = RET_NERRNO(open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY));
131 if (r < 0) {
132 if (r != -ENOENT)
133 log_warning_errno(r, "Failed to open %s: %m", "/sys/fs/smackfs/cipso2");
134 return r;
6656aefb
WC
135 }
136
137 /* write rules to cipso2 from every file in the directory */
138 dir = opendir(srcdir);
139 if (!dir) {
140 if (errno != ENOENT)
5890a775 141 log_warning_errno(errno, "Failed to open %s/: %m", srcdir);
6656aefb
WC
142 return errno; /* positive on purpose */
143 }
144
145 dfd = dirfd(dir);
146 assert(dfd >= 0);
147
3f181218 148 r = 0;
6656aefb 149 FOREACH_DIRENT(entry, dir, return 0) {
6656aefb
WC
150 _cleanup_fclose_ FILE *policy = NULL;
151
152 if (!dirent_is_file(entry))
153 continue;
154
b636d78a 155 if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
6656aefb 156 continue;
6656aefb
WC
157
158 /* cipso2 write rules in the kernel require a line buffered stream */
ea8b6526
LP
159 for (;;) {
160 _cleanup_free_ char *buf = NULL;
161 int q;
162
163 q = read_line(policy, NAME_MAX, &buf);
164 if (q < 0)
5890a775
ZJS
165 return log_error_errno(q, "%s/%s: failed to read line: %m",
166 srcdir, entry->d_name);
ea8b6526
LP
167 if (q == 0)
168 break;
6656aefb 169
ea8b6526 170 if (isempty(buf) || strchr(COMMENTS, buf[0]))
6656aefb
WC
171 continue;
172
3f181218
ZJS
173 q = RET_NERRNO(write(cipso2_fd, buf, strlen(buf)));
174 if (q < 0) {
175 log_error_errno(q, "%s/%s: failed to write '%s' to %s: %m",
5890a775
ZJS
176 srcdir, entry->d_name,
177 buf, "/sys/fs/smackfs/cipso2");
3f181218 178 RET_GATHER(r, q);
a4783bd1
ZJS
179 break;
180 }
ffbd2c4d
NC
181 }
182 }
183
6656aefb 184 return r;
a4783bd1
ZJS
185}
186
b636d78a 187static int write_netlabel_rules(const char *srcdir) {
ae176752
CS
188 _cleanup_fclose_ FILE *dst = NULL;
189 _cleanup_closedir_ DIR *dir = NULL;
3f181218 190 int dfd, r;
ae176752
CS
191
192 dst = fopen("/sys/fs/smackfs/netlabel", "we");
193 if (!dst) {
194 if (errno != ENOENT)
5890a775 195 log_warning_errno(errno, "Failed to open %s/: %m", "/sys/fs/smackfs/netlabel");
ae176752
CS
196 return -errno; /* negative error */
197 }
198
199 /* write rules to dst from every file in the directory */
200 dir = opendir(srcdir);
201 if (!dir) {
202 if (errno != ENOENT)
5890a775 203 log_warning_errno(errno, "Failed to open %s/: %m", srcdir);
ae176752
CS
204 return errno; /* positive on purpose */
205 }
206
207 dfd = dirfd(dir);
208 assert(dfd >= 0);
209
3f181218 210 r = 0;
ae176752 211 FOREACH_DIRENT(entry, dir, return 0) {
ae176752
CS
212 _cleanup_fclose_ FILE *policy = NULL;
213
b636d78a 214 if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
ae176752 215 continue;
0d536673 216
ae176752 217 /* load2 write rules in the kernel require a line buffered stream */
ea8b6526
LP
218 for (;;) {
219 _cleanup_free_ char *buf = NULL;
0d536673
LP
220 int q;
221
ea8b6526
LP
222 q = read_line(policy, NAME_MAX, &buf);
223 if (q < 0)
5890a775
ZJS
224 return log_error_errno(q, "%s/%s: failed to read line: %m",
225 srcdir, entry->d_name);
ea8b6526
LP
226 if (q == 0)
227 break;
228
0d536673 229 if (!fputs(buf, dst)) {
5890a775 230 log_error_errno(errno, "Failed to write line to %s: %m", "/sys/fs/smackfs/netlabel");
3f181218 231 RET_GATHER(r, -errno);
ae176752
CS
232 break;
233 }
0d536673
LP
234 q = fflush_and_check(dst);
235 if (q < 0) {
5890a775 236 log_error_errno(q, "Failed to flush %s: %m", "/sys/fs/smackfs/netlabel");
3f181218 237 RET_GATHER(r, q);
ae176752
CS
238 break;
239 }
240 }
241 }
242
7f508f2c 243 return r;
ae176752
CS
244}
245
217f95db 246static int write_onlycap_list(void) {
254d1313 247 _cleanup_close_ int onlycap_fd = -EBADF;
217f95db
WC
248 _cleanup_free_ char *list = NULL;
249 _cleanup_fclose_ FILE *f = NULL;
319a4f4b 250 size_t len = 0;
217f95db
WC
251 int r;
252
253 f = fopen("/etc/smack/onlycap", "re");
254 if (!f) {
255 if (errno != ENOENT)
5890a775 256 log_warning_errno(errno, "Failed to open %s: %m", "/etc/smack/onlycap");
9fd0b029 257
217f95db
WC
258 return errno == ENOENT ? ENOENT : -errno;
259 }
260
ea8b6526
LP
261 for (;;) {
262 _cleanup_free_ char *buf = NULL;
217f95db
WC
263 size_t l;
264
ea8b6526
LP
265 r = read_line(f, LONG_LINE_MAX, &buf);
266 if (r < 0)
5890a775 267 return log_error_errno(r, "%s: failed to read line: %m", "/etc/smack/onlycap");
ea8b6526
LP
268 if (r == 0)
269 break;
270
271 if (isempty(buf) || strchr(COMMENTS, *buf))
217f95db
WC
272 continue;
273
274 l = strlen(buf);
319a4f4b 275 if (!GREEDY_REALLOC(list, len + l + 1))
217f95db
WC
276 return log_oom();
277
278 stpcpy(list + len, buf)[0] = ' ';
279 len += l + 1;
280 }
281
9fd0b029 282 if (len == 0)
217f95db
WC
283 return 0;
284
285 list[len - 1] = 0;
286
3f181218
ZJS
287 onlycap_fd = r = RET_NERRNO(open("/sys/fs/smackfs/onlycap", O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY));
288 if (r < 0) {
289 if (r != -ENOENT)
290 log_warning_errno(r, "Failed to open %s: %m", "/sys/fs/smackfs/onlycap");
291 return r;
217f95db
WC
292 }
293
3f181218 294 r = RET_NERRNO(write(onlycap_fd, list, len));
217f95db 295 if (r < 0)
3f181218 296 return log_error_errno(r, "%s: failed to write onlycap list(%s): %m",
5890a775 297 "/sys/fs/smackfs/onlycap", list);
217f95db
WC
298
299 return 0;
300}
301
2b3e18de 302#endif
ffbd2c4d 303
8a188de9 304int mac_smack_setup(bool *loaded_policy) {
2b3e18de 305
f9fa32f0 306#if ENABLE_SMACK
a4783bd1
ZJS
307 int r;
308
e49d3c01
ŁS
309 assert(loaded_policy);
310
5890a775 311 r = write_access2_rules("/etc/smack/accesses.d");
79893116 312 switch (r) {
a4783bd1
ZJS
313 case -ENOENT:
314 log_debug("Smack is not enabled in the kernel.");
315 return 0;
316 case ENOENT:
6656aefb 317 log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
a4783bd1
ZJS
318 return 0;
319 case 0:
320 log_info("Successfully loaded Smack policies.");
abbacb1d
NC
321 break;
322 default:
e53fc357 323 log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m");
abbacb1d
NC
324 return 0;
325 }
326
07b382cc 327#if HAVE_SMACK_RUN_LABEL
57512c89 328 r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
ae176752
CS
329 if (r < 0)
330 log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m");
57512c89 331 r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
ae176752
CS
332 if (r < 0)
333 log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m");
334 r = write_string_file("/sys/fs/smackfs/netlabel",
57512c89 335 "0.0.0.0/0 " SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
ae176752
CS
336 if (r < 0)
337 log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m");
57512c89 338 r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", WRITE_STRING_FILE_DISABLE_BUFFER);
ae176752
CS
339 if (r < 0)
340 log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
8b197c3a
AK
341#endif
342
5890a775 343 r = write_cipso2_rules("/etc/smack/cipso.d");
79893116 344 switch (r) {
abbacb1d
NC
345 case -ENOENT:
346 log_debug("Smack/CIPSO is not enabled in the kernel.");
347 return 0;
348 case ENOENT:
6656aefb 349 log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
ae176752 350 break;
abbacb1d
NC
351 case 0:
352 log_info("Successfully loaded Smack/CIPSO policies.");
b9289d4c 353 break;
a4783bd1 354 default:
e53fc357 355 log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
ae176752
CS
356 }
357
5890a775 358 r = write_netlabel_rules("/etc/smack/netlabel.d");
79893116 359 switch (r) {
ae176752
CS
360 case -ENOENT:
361 log_debug("Smack/CIPSO is not enabled in the kernel.");
a4783bd1 362 return 0;
ae176752
CS
363 case ENOENT:
364 log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
365 break;
366 case 0:
367 log_info("Successfully loaded Smack network host rules.");
368 break;
369 default:
370 log_warning_errno(r, "Failed to load Smack network host rules: %m, ignoring.");
a4783bd1 371 }
2b3e18de 372
217f95db 373 r = write_onlycap_list();
79893116 374 switch (r) {
217f95db
WC
375 case -ENOENT:
376 log_debug("Smack is not enabled in the kernel.");
377 break;
378 case ENOENT:
379 log_debug("Smack onlycap list file '/etc/smack/onlycap' not found");
380 break;
381 case 0:
382 log_info("Successfully wrote Smack onlycap list.");
383 break;
384 default:
ad5db940
OJ
385 return log_struct_errno(LOG_EMERG, r,
386 LOG_MESSAGE("Failed to write Smack onlycap list: %m"),
3cf6a3a3 387 LOG_MESSAGE_ID(SD_MESSAGE_SMACK_FAILED_WRITE_STR));
217f95db
WC
388 }
389
e49d3c01
ŁS
390 *loaded_policy = true;
391
2b3e18de
KL
392#endif
393
394 return 0;
ffbd2c4d 395}