1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation
5 Nathaniel Chen <nathaniel.chen@intel.com>
14 #include "sd-messages.h"
16 #include "alloc-util.h"
17 #include "dirent-util.h"
22 #include "smack-setup.h"
23 #include "string-util.h"
27 static int fdopen_unlocked_at(int dfd
, const char *dir
, const char *name
, int *status
, FILE **ret_file
) {
31 fd
= openat(dfd
, name
, O_RDONLY
|O_CLOEXEC
);
36 return log_warning_errno(errno
, "Failed to open \"%s/%s\": %m", dir
, name
);
39 r
= fdopen_unlocked(fd
, "r", &f
);
45 return log_error_errno(r
, "Failed to open \"%s/%s\": %m", dir
, name
);
52 static int write_access2_rules(const char *srcdir
) {
53 _cleanup_close_
int load2_fd
= -EBADF
, change_fd
= -EBADF
;
54 _cleanup_closedir_
DIR *dir
= NULL
;
55 int dfd
= -EBADF
, r
= 0;
57 load2_fd
= open("/sys/fs/smackfs/load2", O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
60 log_warning_errno(errno
, "Failed to open '/sys/fs/smackfs/load2': %m");
61 return -errno
; /* negative error */
64 change_fd
= open("/sys/fs/smackfs/change-rule", O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
67 log_warning_errno(errno
, "Failed to open '/sys/fs/smackfs/change-rule': %m");
68 return -errno
; /* negative error */
71 /* write rules to load2 or change-rule from every file in the directory */
72 dir
= opendir(srcdir
);
75 log_warning_errno(errno
, "Failed to opendir '%s': %m", srcdir
);
76 return errno
; /* positive on purpose */
82 FOREACH_DIRENT(entry
, dir
, return 0) {
83 _cleanup_fclose_
FILE *policy
= NULL
;
85 if (!dirent_is_file(entry
))
88 if (fdopen_unlocked_at(dfd
, srcdir
, entry
->d_name
, &r
, &policy
) < 0)
91 /* load2 write rules in the kernel require a line buffered stream */
93 _cleanup_free_
char *buf
= NULL
, *sbj
= NULL
, *obj
= NULL
, *acc1
= NULL
, *acc2
= NULL
;
96 q
= read_line(policy
, NAME_MAX
, &buf
);
98 return log_error_errno(q
, "Failed to read line from '%s': %m", entry
->d_name
);
102 if (isempty(buf
) || strchr(COMMENTS
, buf
[0]))
105 /* if 3 args -> load rule : subject object access1 */
106 /* if 4 args -> change rule : subject object access1 access2 */
107 if (sscanf(buf
, "%ms %ms %ms %ms", &sbj
, &obj
, &acc1
, &acc2
) < 3) {
108 log_error_errno(errno
, "Failed to parse rule '%s' in '%s', ignoring.", buf
, entry
->d_name
);
112 if (write(isempty(acc2
) ? load2_fd
: change_fd
, buf
, strlen(buf
)) < 0) {
115 log_error_errno(errno
, "Failed to write '%s' to '%s' in '%s': %m",
116 buf
, isempty(acc2
) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry
->d_name
);
124 static int write_cipso2_rules(const char *srcdir
) {
125 _cleanup_close_
int cipso2_fd
= -EBADF
;
126 _cleanup_closedir_
DIR *dir
= NULL
;
127 int dfd
= -EBADF
, r
= 0;
129 cipso2_fd
= open("/sys/fs/smackfs/cipso2", O_RDWR
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
132 log_warning_errno(errno
, "Failed to open '/sys/fs/smackfs/cipso2': %m");
133 return -errno
; /* negative error */
136 /* write rules to cipso2 from every file in the directory */
137 dir
= opendir(srcdir
);
140 log_warning_errno(errno
, "Failed to opendir '%s': %m", srcdir
);
141 return errno
; /* positive on purpose */
147 FOREACH_DIRENT(entry
, dir
, return 0) {
148 _cleanup_fclose_
FILE *policy
= NULL
;
150 if (!dirent_is_file(entry
))
153 if (fdopen_unlocked_at(dfd
, srcdir
, entry
->d_name
, &r
, &policy
) < 0)
156 /* cipso2 write rules in the kernel require a line buffered stream */
158 _cleanup_free_
char *buf
= NULL
;
161 q
= read_line(policy
, NAME_MAX
, &buf
);
163 return log_error_errno(q
, "Failed to read line from '%s': %m", entry
->d_name
);
167 if (isempty(buf
) || strchr(COMMENTS
, buf
[0]))
170 if (write(cipso2_fd
, buf
, strlen(buf
)) < 0) {
173 log_error_errno(errno
, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s': %m",
183 static int write_netlabel_rules(const char *srcdir
) {
184 _cleanup_fclose_
FILE *dst
= NULL
;
185 _cleanup_closedir_
DIR *dir
= NULL
;
186 int dfd
= -EBADF
, r
= 0;
188 dst
= fopen("/sys/fs/smackfs/netlabel", "we");
191 log_warning_errno(errno
, "Failed to open /sys/fs/smackfs/netlabel: %m");
192 return -errno
; /* negative error */
195 /* write rules to dst from every file in the directory */
196 dir
= opendir(srcdir
);
199 log_warning_errno(errno
, "Failed to opendir %s: %m", srcdir
);
200 return errno
; /* positive on purpose */
206 FOREACH_DIRENT(entry
, dir
, return 0) {
207 _cleanup_fclose_
FILE *policy
= NULL
;
209 if (fdopen_unlocked_at(dfd
, srcdir
, entry
->d_name
, &r
, &policy
) < 0)
212 /* load2 write rules in the kernel require a line buffered stream */
214 _cleanup_free_
char *buf
= NULL
;
217 q
= read_line(policy
, NAME_MAX
, &buf
);
219 return log_error_errno(q
, "Failed to read line from %s: %m", entry
->d_name
);
223 if (!fputs(buf
, dst
)) {
226 log_error_errno(errno
, "Failed to write line to /sys/fs/smackfs/netlabel: %m");
229 q
= fflush_and_check(dst
);
233 log_error_errno(q
, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
242 static int write_onlycap_list(void) {
243 _cleanup_close_
int onlycap_fd
= -EBADF
;
244 _cleanup_free_
char *list
= NULL
;
245 _cleanup_fclose_
FILE *f
= NULL
;
249 f
= fopen("/etc/smack/onlycap", "re");
252 log_warning_errno(errno
, "Failed to read '/etc/smack/onlycap': %m");
254 return errno
== ENOENT
? ENOENT
: -errno
;
258 _cleanup_free_
char *buf
= NULL
;
261 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
263 return log_error_errno(r
, "Failed to read line from /etc/smack/onlycap: %m");
267 if (isempty(buf
) || strchr(COMMENTS
, *buf
))
271 if (!GREEDY_REALLOC(list
, len
+ l
+ 1))
274 stpcpy(list
+ len
, buf
)[0] = ' ';
283 onlycap_fd
= open("/sys/fs/smackfs/onlycap", O_WRONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
284 if (onlycap_fd
< 0) {
286 log_warning_errno(errno
, "Failed to open '/sys/fs/smackfs/onlycap': %m");
287 return -errno
; /* negative error */
290 r
= write(onlycap_fd
, list
, len
);
292 return log_error_errno(errno
, "Failed to write onlycap list(%s) to '/sys/fs/smackfs/onlycap': %m", list
);
299 int mac_smack_setup(bool *loaded_policy
) {
305 assert(loaded_policy
);
307 r
= write_access2_rules("/etc/smack/accesses.d/");
310 log_debug("Smack is not enabled in the kernel.");
313 log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
316 log_info("Successfully loaded Smack policies.");
319 log_warning_errno(r
, "Failed to load Smack access rules, ignoring: %m");
323 #if HAVE_SMACK_RUN_LABEL
324 r
= write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL
, WRITE_STRING_FILE_DISABLE_BUFFER
);
326 log_warning_errno(r
, "Failed to set SMACK label \"" SMACK_RUN_LABEL
"\" on self: %m");
327 r
= write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL
, WRITE_STRING_FILE_DISABLE_BUFFER
);
329 log_warning_errno(r
, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL
"\": %m");
330 r
= write_string_file("/sys/fs/smackfs/netlabel",
331 "0.0.0.0/0 " SMACK_RUN_LABEL
, WRITE_STRING_FILE_DISABLE_BUFFER
);
333 log_warning_errno(r
, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL
"\": %m");
334 r
= write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", WRITE_STRING_FILE_DISABLE_BUFFER
);
336 log_warning_errno(r
, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
339 r
= write_cipso2_rules("/etc/smack/cipso.d/");
342 log_debug("Smack/CIPSO is not enabled in the kernel.");
345 log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
348 log_info("Successfully loaded Smack/CIPSO policies.");
351 log_warning_errno(r
, "Failed to load Smack/CIPSO access rules, ignoring: %m");
355 r
= write_netlabel_rules("/etc/smack/netlabel.d/");
358 log_debug("Smack/CIPSO is not enabled in the kernel.");
361 log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
364 log_info("Successfully loaded Smack network host rules.");
367 log_warning_errno(r
, "Failed to load Smack network host rules: %m, ignoring.");
371 r
= write_onlycap_list();
374 log_debug("Smack is not enabled in the kernel.");
377 log_debug("Smack onlycap list file '/etc/smack/onlycap' not found");
380 log_info("Successfully wrote Smack onlycap list.");
383 return log_struct_errno(LOG_EMERG
, r
,
384 LOG_MESSAGE("Failed to write Smack onlycap list: %m"),
385 "MESSAGE_ID=" SD_MESSAGE_SMACK_FAILED_WRITE_STR
);
388 *loaded_policy
= true;