1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation
5 Author: Auke Kok <auke-jan.h.kok@intel.com>
11 #include <sys/xattr.h>
14 #include "alloc-util.h"
15 #include "errno-util.h"
21 #include "path-util.h"
22 #include "process-util.h"
23 #include "smack-util.h"
24 #include "stdio-util.h"
25 #include "string-table.h"
26 #include "xattr-util.h"
29 bool mac_smack_use(void) {
30 static int cached_use
= -1;
33 cached_use
= access("/sys/fs/smackfs/", F_OK
) >= 0;
38 static const char* const smack_attr_table
[_SMACK_ATTR_MAX
] = {
39 [SMACK_ATTR_ACCESS
] = "security.SMACK64",
40 [SMACK_ATTR_EXEC
] = "security.SMACK64EXEC",
41 [SMACK_ATTR_MMAP
] = "security.SMACK64MMAP",
42 [SMACK_ATTR_TRANSMUTE
] = "security.SMACK64TRANSMUTE",
43 [SMACK_ATTR_IPIN
] = "security.SMACK64IPIN",
44 [SMACK_ATTR_IPOUT
] = "security.SMACK64IPOUT",
47 DEFINE_STRING_TABLE_LOOKUP(smack_attr
, SmackAttr
);
49 int mac_smack_read(const char *path
, SmackAttr attr
, char **label
) {
51 assert(attr
>= 0 && attr
< _SMACK_ATTR_MAX
);
57 return getxattr_malloc(path
, smack_attr_to_string(attr
), label
);
60 int mac_smack_read_fd(int fd
, SmackAttr attr
, char **label
) {
62 assert(attr
>= 0 && attr
< _SMACK_ATTR_MAX
);
68 return fgetxattr_malloc(fd
, smack_attr_to_string(attr
), label
);
71 int mac_smack_apply_at(int dir_fd
, const char *path
, SmackAttr attr
, const char *label
) {
72 _cleanup_close_
int fd
= -EBADF
;
75 assert(attr
>= 0 && attr
< _SMACK_ATTR_MAX
);
80 fd
= openat(dir_fd
, path
, O_PATH
|O_CLOEXEC
|O_NOFOLLOW
);
84 return mac_smack_apply_fd(fd
, attr
, label
);
87 int mac_smack_apply_fd(int fd
, SmackAttr attr
, const char *label
) {
91 assert(attr
>= 0 && attr
< _SMACK_ATTR_MAX
);
97 r
= setxattr(FORMAT_PROC_FD_PATH(fd
), smack_attr_to_string(attr
), label
, strlen(label
), 0);
99 r
= removexattr(FORMAT_PROC_FD_PATH(fd
), smack_attr_to_string(attr
));
106 int mac_smack_apply_pid(pid_t pid
, const char *label
) {
112 if (!mac_smack_use())
115 p
= procfs_file_alloca(pid
, "attr/current");
116 r
= write_string_file(p
, label
, WRITE_STRING_FILE_DISABLE_BUFFER
);
123 static int smack_fix_fd(
125 const char *label_path
,
126 LabelFixFlags flags
) {
132 /* The caller should have done the sanity checks. */
135 assert(path_is_absolute(label_path
));
137 /* Path must be in /dev. */
138 if (!path_startswith(label_path
, "/dev"))
141 if (fstat(fd
, &st
) < 0)
145 * Label directories and character devices "*".
146 * Label symlinks "_".
147 * Don't change anything else.
150 if (S_ISDIR(st
.st_mode
))
151 label
= SMACK_STAR_LABEL
;
152 else if (S_ISLNK(st
.st_mode
))
153 label
= SMACK_FLOOR_LABEL
;
154 else if (S_ISCHR(st
.st_mode
))
155 label
= SMACK_STAR_LABEL
;
159 if (setxattr(FORMAT_PROC_FD_PATH(fd
), "security.SMACK64", label
, strlen(label
), 0) < 0) {
160 _cleanup_free_
char *old_label
= NULL
;
164 /* If the FS doesn't support labels, then exit without warning */
165 if (ERRNO_IS_NOT_SUPPORTED(r
))
168 /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
169 if (r
== -EROFS
&& (flags
& LABEL_IGNORE_EROFS
))
172 /* If the old label is identical to the new one, suppress any kind of error */
173 if (lgetxattr_malloc(FORMAT_PROC_FD_PATH(fd
), "security.SMACK64", &old_label
) >= 0 &&
174 streq(old_label
, label
))
177 return log_debug_errno(r
, "Unable to fix SMACK label of %s: %m", label_path
);
183 int mac_smack_fix_full(
185 const char *inode_path
,
186 const char *label_path
,
187 LabelFixFlags flags
) {
189 _cleanup_close_
int opened_fd
= -EBADF
;
190 _cleanup_free_
char *p
= NULL
;
193 assert(atfd
>= 0 || atfd
== AT_FDCWD
);
194 assert(atfd
>= 0 || inode_path
);
196 if (!mac_smack_use())
200 opened_fd
= openat(atfd
, inode_path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
202 if ((flags
& LABEL_IGNORE_ENOENT
) && errno
== ENOENT
)
207 inode_fd
= opened_fd
;
212 if (path_is_absolute(inode_path
))
213 label_path
= inode_path
;
215 r
= fd_get_path(inode_fd
, &p
);
223 return smack_fix_fd(inode_fd
, label_path
, flags
);
226 int mac_smack_copy(const char *dest
, const char *src
) {
228 _cleanup_free_
char *label
= NULL
;
233 r
= mac_smack_read(src
, SMACK_ATTR_ACCESS
, &label
);
237 r
= mac_smack_apply(dest
, SMACK_ATTR_ACCESS
, label
);
245 bool mac_smack_use(void) {
249 int mac_smack_read(const char *path
, SmackAttr attr
, char **label
) {
253 int mac_smack_read_fd(int fd
, SmackAttr attr
, char **label
) {
257 int mac_smack_apply_at(int dir_fd
, const char *path
, SmackAttr attr
, const char *label
) {
261 int mac_smack_apply_fd(int fd
, SmackAttr attr
, const char *label
) {
265 int mac_smack_apply_pid(pid_t pid
, const char *label
) {
269 int mac_smack_fix_full(int atfd
, const char *inode_path
, const char *label_path
, LabelFixFlags flags
) {
273 int mac_smack_copy(const char *dest
, const char *src
) {
278 int renameat_and_apply_smack_floor_label(int fdf
, const char *from
, int fdt
, const char *to
) {
280 assert(fdf
>= 0 || fdf
== AT_FDCWD
);
281 assert(fdt
>= 0 || fdt
== AT_FDCWD
);
283 if (renameat(fdf
, from
, fdt
, to
) < 0)
286 #if HAVE_SMACK_RUN_LABEL
287 return mac_smack_apply_at(fdt
, to
, SMACK_ATTR_ACCESS
, SMACK_FLOOR_LABEL
);
293 static int mac_smack_label_pre(int dir_fd
, const char *path
, mode_t mode
) {
297 static int mac_smack_label_post(int dir_fd
, const char *path
) {
298 return mac_smack_fix_full(dir_fd
, path
, NULL
, 0);
301 int mac_smack_init(void) {
302 static const LabelOps label_ops
= {
303 .pre
= mac_smack_label_pre
,
304 .post
= mac_smack_label_post
,
307 if (!mac_smack_use())
310 return label_ops_set(&label_ops
);