1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation
5 Nathaniel Chen <nathaniel.chen@intel.com>
12 #include "sd-messages.h"
14 #include "alloc-util.h"
15 #include "dirent-util.h"
16 #include "errno-util.h"
20 #include "smack-setup.h"
21 #include "string-util.h"
25 static int fdopen_unlocked_at(int dfd
, const char *dir
, const char *name
, int *status
, FILE **ret_file
) {
29 fd
= openat(dfd
, name
, O_RDONLY
|O_CLOEXEC
);
34 return log_warning_errno(errno
, "Failed to open \"%s/%s\": %m", dir
, name
);
37 r
= fdopen_unlocked(fd
, "r", &f
);
43 return log_error_errno(r
, "Failed to open \"%s/%s\": %m", dir
, name
);
50 static int write_access2_rules(const char *srcdir
) {
51 _cleanup_close_
int load2_fd
= -EBADF
, change_fd
= -EBADF
;
52 _cleanup_closedir_
DIR *dir
= NULL
;
55 load2_fd
= r
= RET_NERRNO(open("/sys/fs/smackfs/load2", O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
));
58 log_warning_errno(r
, "Failed to open %s: %m", "/sys/fs/smackfs/load2");
62 change_fd
= r
= RET_NERRNO(open("/sys/fs/smackfs/change-rule", O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
));
65 log_warning_errno(r
, "Failed to open %s: %m", "/sys/fs/smackfs/change-rule");
69 /* write rules to load2 or change-rule from every file in the directory */
70 dir
= opendir(srcdir
);
73 log_warning_errno(errno
, "Failed to open %s/: %m", srcdir
);
74 return errno
; /* positive on purpose */
81 FOREACH_DIRENT(entry
, dir
, return 0) {
82 _cleanup_fclose_
FILE *policy
= NULL
;
84 if (!dirent_is_file(entry
))
87 if (fdopen_unlocked_at(dfd
, srcdir
, entry
->d_name
, &r
, &policy
) < 0)
90 /* load2 write rules in the kernel require a line buffered stream */
92 _cleanup_free_
char *buf
= NULL
, *sbj
= NULL
, *obj
= NULL
, *acc1
= NULL
, *acc2
= NULL
;
95 q
= read_line(policy
, NAME_MAX
, &buf
);
97 return log_error_errno(q
, "%s/%s: failed to read line: %m", srcdir
, entry
->d_name
);
101 if (isempty(buf
) || strchr(COMMENTS
, buf
[0]))
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) {
107 log_error_errno(errno
, "%s/%s: failed to parse rule '%s', ignoring.",
108 srcdir
, entry
->d_name
, buf
);
112 q
= RET_NERRNO(write(isempty(acc2
) ? load2_fd
: change_fd
, buf
, strlen(buf
)));
114 log_error_errno(q
, "%s/%s: failed to write '%s' to '%s': %m",
115 srcdir
, entry
->d_name
,
116 buf
, isempty(acc2
) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule");
125 static int write_cipso2_rules(const char *srcdir
) {
126 _cleanup_close_
int cipso2_fd
= -EBADF
;
127 _cleanup_closedir_
DIR *dir
= NULL
;
130 cipso2_fd
= r
= RET_NERRNO(open("/sys/fs/smackfs/cipso2", O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
));
133 log_warning_errno(r
, "Failed to open %s: %m", "/sys/fs/smackfs/cipso2");
137 /* write rules to cipso2 from every file in the directory */
138 dir
= opendir(srcdir
);
141 log_warning_errno(errno
, "Failed to open %s/: %m", srcdir
);
142 return errno
; /* positive on purpose */
149 FOREACH_DIRENT(entry
, dir
, return 0) {
150 _cleanup_fclose_
FILE *policy
= NULL
;
152 if (!dirent_is_file(entry
))
155 if (fdopen_unlocked_at(dfd
, srcdir
, entry
->d_name
, &r
, &policy
) < 0)
158 /* cipso2 write rules in the kernel require a line buffered stream */
160 _cleanup_free_
char *buf
= NULL
;
163 q
= read_line(policy
, NAME_MAX
, &buf
);
165 return log_error_errno(q
, "%s/%s: failed to read line: %m",
166 srcdir
, entry
->d_name
);
170 if (isempty(buf
) || strchr(COMMENTS
, buf
[0]))
173 q
= RET_NERRNO(write(cipso2_fd
, buf
, strlen(buf
)));
175 log_error_errno(q
, "%s/%s: failed to write '%s' to %s: %m",
176 srcdir
, entry
->d_name
,
177 buf
, "/sys/fs/smackfs/cipso2");
187 static int write_netlabel_rules(const char *srcdir
) {
188 _cleanup_fclose_
FILE *dst
= NULL
;
189 _cleanup_closedir_
DIR *dir
= NULL
;
192 dst
= fopen("/sys/fs/smackfs/netlabel", "we");
195 log_warning_errno(errno
, "Failed to open %s/: %m", "/sys/fs/smackfs/netlabel");
196 return -errno
; /* negative error */
199 /* write rules to dst from every file in the directory */
200 dir
= opendir(srcdir
);
203 log_warning_errno(errno
, "Failed to open %s/: %m", srcdir
);
204 return errno
; /* positive on purpose */
211 FOREACH_DIRENT(entry
, dir
, return 0) {
212 _cleanup_fclose_
FILE *policy
= NULL
;
214 if (fdopen_unlocked_at(dfd
, srcdir
, entry
->d_name
, &r
, &policy
) < 0)
217 /* load2 write rules in the kernel require a line buffered stream */
219 _cleanup_free_
char *buf
= NULL
;
222 q
= read_line(policy
, NAME_MAX
, &buf
);
224 return log_error_errno(q
, "%s/%s: failed to read line: %m",
225 srcdir
, entry
->d_name
);
229 if (!fputs(buf
, dst
)) {
230 log_error_errno(errno
, "Failed to write line to %s: %m", "/sys/fs/smackfs/netlabel");
231 RET_GATHER(r
, -errno
);
234 q
= fflush_and_check(dst
);
236 log_error_errno(q
, "Failed to flush %s: %m", "/sys/fs/smackfs/netlabel");
246 static int write_onlycap_list(void) {
247 _cleanup_close_
int onlycap_fd
= -EBADF
;
248 _cleanup_free_
char *list
= NULL
;
249 _cleanup_fclose_
FILE *f
= NULL
;
253 f
= fopen("/etc/smack/onlycap", "re");
256 log_warning_errno(errno
, "Failed to open %s: %m", "/etc/smack/onlycap");
258 return errno
== ENOENT
? ENOENT
: -errno
;
262 _cleanup_free_
char *buf
= NULL
;
265 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
267 return log_error_errno(r
, "%s: failed to read line: %m", "/etc/smack/onlycap");
271 if (isempty(buf
) || strchr(COMMENTS
, *buf
))
275 if (!GREEDY_REALLOC(list
, len
+ l
+ 1))
278 stpcpy(list
+ len
, buf
)[0] = ' ';
287 onlycap_fd
= r
= RET_NERRNO(open("/sys/fs/smackfs/onlycap", O_WRONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
));
290 log_warning_errno(r
, "Failed to open %s: %m", "/sys/fs/smackfs/onlycap");
294 r
= RET_NERRNO(write(onlycap_fd
, list
, len
));
296 return log_error_errno(r
, "%s: failed to write onlycap list(%s): %m",
297 "/sys/fs/smackfs/onlycap", list
);
304 int mac_smack_setup(bool *loaded_policy
) {
309 assert(loaded_policy
);
311 r
= write_access2_rules("/etc/smack/accesses.d");
314 log_debug("Smack is not enabled in the kernel.");
317 log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
320 log_info("Successfully loaded Smack policies.");
323 log_warning_errno(r
, "Failed to load Smack access rules, ignoring: %m");
327 #if HAVE_SMACK_RUN_LABEL
328 r
= write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL
, WRITE_STRING_FILE_DISABLE_BUFFER
);
330 log_warning_errno(r
, "Failed to set SMACK label \"" SMACK_RUN_LABEL
"\" on self: %m");
331 r
= write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL
, WRITE_STRING_FILE_DISABLE_BUFFER
);
333 log_warning_errno(r
, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL
"\": %m");
334 r
= write_string_file("/sys/fs/smackfs/netlabel",
335 "0.0.0.0/0 " SMACK_RUN_LABEL
, WRITE_STRING_FILE_DISABLE_BUFFER
);
337 log_warning_errno(r
, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL
"\": %m");
338 r
= write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", WRITE_STRING_FILE_DISABLE_BUFFER
);
340 log_warning_errno(r
, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
343 r
= write_cipso2_rules("/etc/smack/cipso.d");
346 log_debug("Smack/CIPSO is not enabled in the kernel.");
349 log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
352 log_info("Successfully loaded Smack/CIPSO policies.");
355 log_warning_errno(r
, "Failed to load Smack/CIPSO access rules, ignoring: %m");
358 r
= write_netlabel_rules("/etc/smack/netlabel.d");
361 log_debug("Smack/CIPSO is not enabled in the kernel.");
364 log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
367 log_info("Successfully loaded Smack network host rules.");
370 log_warning_errno(r
, "Failed to load Smack network host rules: %m, ignoring.");
373 r
= write_onlycap_list();
376 log_debug("Smack is not enabled in the kernel.");
379 log_debug("Smack onlycap list file '/etc/smack/onlycap' not found");
382 log_info("Successfully wrote Smack onlycap list.");
385 return log_struct_errno(LOG_EMERG
, r
,
386 LOG_MESSAGE("Failed to write Smack onlycap list: %m"),
387 LOG_MESSAGE_ID(SD_MESSAGE_SMACK_FAILED_WRITE_STR
));
390 *loaded_policy
= true;