1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3   Copyright © 2013 Intel Corporation
4 
5   Author: Auke Kok <auke-jan.h.kok@intel.com>
6 ***/
7 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <sys/xattr.h>
12 #include <unistd.h>
13 
14 #include "alloc-util.h"
15 #include "fd-util.h"
16 #include "fileio.h"
17 #include "log.h"
18 #include "macro.h"
19 #include "path-util.h"
20 #include "process-util.h"
21 #include "smack-util.h"
22 #include "stdio-util.h"
23 #include "string-table.h"
24 #include "xattr-util.h"
25 
26 #if ENABLE_SMACK
mac_smack_use(void)27 bool mac_smack_use(void) {
28         static int cached_use = -1;
29 
30         if (cached_use < 0)
31                 cached_use = access("/sys/fs/smackfs/", F_OK) >= 0;
32 
33         return cached_use;
34 }
35 
36 static const char* const smack_attr_table[_SMACK_ATTR_MAX] = {
37         [SMACK_ATTR_ACCESS]     = "security.SMACK64",
38         [SMACK_ATTR_EXEC]       = "security.SMACK64EXEC",
39         [SMACK_ATTR_MMAP]       = "security.SMACK64MMAP",
40         [SMACK_ATTR_TRANSMUTE]  = "security.SMACK64TRANSMUTE",
41         [SMACK_ATTR_IPIN]       = "security.SMACK64IPIN",
42         [SMACK_ATTR_IPOUT]      = "security.SMACK64IPOUT",
43 };
44 
45 DEFINE_STRING_TABLE_LOOKUP(smack_attr, SmackAttr);
46 
mac_smack_read(const char * path,SmackAttr attr,char ** label)47 int mac_smack_read(const char *path, SmackAttr attr, char **label) {
48         assert(path);
49         assert(attr >= 0 && attr < _SMACK_ATTR_MAX);
50         assert(label);
51 
52         if (!mac_smack_use())
53                 return 0;
54 
55         return getxattr_malloc(path, smack_attr_to_string(attr), label);
56 }
57 
mac_smack_read_fd(int fd,SmackAttr attr,char ** label)58 int mac_smack_read_fd(int fd, SmackAttr attr, char **label) {
59         assert(fd >= 0);
60         assert(attr >= 0 && attr < _SMACK_ATTR_MAX);
61         assert(label);
62 
63         if (!mac_smack_use())
64                 return 0;
65 
66         return fgetxattr_malloc(fd, smack_attr_to_string(attr), label);
67 }
68 
mac_smack_apply(const char * path,SmackAttr attr,const char * label)69 int mac_smack_apply(const char *path, SmackAttr attr, const char *label) {
70         int r;
71 
72         assert(path);
73         assert(attr >= 0 && attr < _SMACK_ATTR_MAX);
74 
75         if (!mac_smack_use())
76                 return 0;
77 
78         if (label)
79                 r = lsetxattr(path, smack_attr_to_string(attr), label, strlen(label), 0);
80         else
81                 r = lremovexattr(path, smack_attr_to_string(attr));
82         if (r < 0)
83                 return -errno;
84 
85         return 0;
86 }
87 
mac_smack_apply_fd(int fd,SmackAttr attr,const char * label)88 int mac_smack_apply_fd(int fd, SmackAttr attr, const char *label) {
89         int r;
90 
91         assert(fd >= 0);
92         assert(attr >= 0 && attr < _SMACK_ATTR_MAX);
93 
94         if (!mac_smack_use())
95                 return 0;
96 
97         if (label)
98                 r = setxattr(FORMAT_PROC_FD_PATH(fd), smack_attr_to_string(attr), label, strlen(label), 0);
99         else
100                 r = removexattr(FORMAT_PROC_FD_PATH(fd), smack_attr_to_string(attr));
101         if (r < 0)
102                 return -errno;
103 
104         return 0;
105 }
106 
mac_smack_apply_pid(pid_t pid,const char * label)107 int mac_smack_apply_pid(pid_t pid, const char *label) {
108         const char *p;
109         int r;
110 
111         assert(label);
112 
113         if (!mac_smack_use())
114                 return 0;
115 
116         p = procfs_file_alloca(pid, "attr/current");
117         r = write_string_file(p, label, WRITE_STRING_FILE_DISABLE_BUFFER);
118         if (r < 0)
119                 return r;
120 
121         return r;
122 }
123 
smack_fix_fd(int fd,const char * abspath,LabelFixFlags flags)124 static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
125         const char *label;
126         struct stat st;
127         int r;
128 
129         /* The caller should have done the sanity checks. */
130         assert(abspath);
131         assert(path_is_absolute(abspath));
132 
133         /* Path must be in /dev. */
134         if (!path_startswith(abspath, "/dev"))
135                 return 0;
136 
137         if (fstat(fd, &st) < 0)
138                 return -errno;
139 
140         /*
141          * Label directories and character devices "*".
142          * Label symlinks "_".
143          * Don't change anything else.
144          */
145 
146         if (S_ISDIR(st.st_mode))
147                 label = SMACK_STAR_LABEL;
148         else if (S_ISLNK(st.st_mode))
149                 label = SMACK_FLOOR_LABEL;
150         else if (S_ISCHR(st.st_mode))
151                 label = SMACK_STAR_LABEL;
152         else
153                 return 0;
154 
155         if (setxattr(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", label, strlen(label), 0) < 0) {
156                 _cleanup_free_ char *old_label = NULL;
157 
158                 r = -errno;
159 
160                 /* If the FS doesn't support labels, then exit without warning */
161                 if (r == -EOPNOTSUPP)
162                         return 0;
163 
164                 /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
165                 if (r == -EROFS && (flags & LABEL_IGNORE_EROFS))
166                         return 0;
167 
168                 /* If the old label is identical to the new one, suppress any kind of error */
169                 if (lgetxattr_malloc(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", &old_label) >= 0 &&
170                     streq(old_label, label))
171                         return 0;
172 
173                 return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", abspath);
174         }
175 
176         return 0;
177 }
178 
mac_smack_fix_at(int dir_fd,const char * path,LabelFixFlags flags)179 int mac_smack_fix_at(int dir_fd, const char *path, LabelFixFlags flags) {
180         _cleanup_free_ char *p = NULL;
181         _cleanup_close_ int fd = -1;
182         int r;
183 
184         assert(path);
185 
186         if (!mac_smack_use())
187                 return 0;
188 
189         if (dir_fd < 0) {
190                 if (dir_fd != AT_FDCWD)
191                         return -EBADF;
192 
193                 return mac_smack_fix(path, flags);
194         }
195 
196         fd = openat(dir_fd, path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
197         if (fd < 0) {
198                 if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
199                         return 0;
200 
201                 return -errno;
202         }
203 
204         if (!path_is_absolute(path)) {
205                 r = fd_get_path(fd, &p);
206                 if (r < 0)
207                         return r;
208                 path = p;
209         }
210 
211         return smack_fix_fd(fd, path, flags);
212 }
213 
mac_smack_fix_container(const char * path,const char * inside_path,LabelFixFlags flags)214 int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
215         _cleanup_free_ char *abspath = NULL;
216         _cleanup_close_ int fd = -1;
217         int r;
218 
219         assert(path);
220 
221         if (!mac_smack_use())
222                 return 0;
223 
224         r = path_make_absolute_cwd(path, &abspath);
225         if (r < 0)
226                 return r;
227 
228         fd = open(abspath, O_NOFOLLOW|O_CLOEXEC|O_PATH);
229         if (fd < 0) {
230                 if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
231                         return 0;
232 
233                 return -errno;
234         }
235 
236         return smack_fix_fd(fd, inside_path, flags);
237 }
238 
mac_smack_copy(const char * dest,const char * src)239 int mac_smack_copy(const char *dest, const char *src) {
240         int r;
241         _cleanup_free_ char *label = NULL;
242 
243         assert(dest);
244         assert(src);
245 
246         r = mac_smack_read(src, SMACK_ATTR_ACCESS, &label);
247         if (r < 0)
248                 return r;
249 
250         r = mac_smack_apply(dest, SMACK_ATTR_ACCESS, label);
251         if (r < 0)
252                 return r;
253 
254         return r;
255 }
256 
257 #else
mac_smack_use(void)258 bool mac_smack_use(void) {
259         return false;
260 }
261 
mac_smack_read(const char * path,SmackAttr attr,char ** label)262 int mac_smack_read(const char *path, SmackAttr attr, char **label) {
263         return -EOPNOTSUPP;
264 }
265 
mac_smack_read_fd(int fd,SmackAttr attr,char ** label)266 int mac_smack_read_fd(int fd, SmackAttr attr, char **label) {
267         return -EOPNOTSUPP;
268 }
269 
mac_smack_apply(const char * path,SmackAttr attr,const char * label)270 int mac_smack_apply(const char *path, SmackAttr attr, const char *label) {
271         return 0;
272 }
273 
mac_smack_apply_fd(int fd,SmackAttr attr,const char * label)274 int mac_smack_apply_fd(int fd, SmackAttr attr, const char *label) {
275         return 0;
276 }
277 
mac_smack_apply_pid(pid_t pid,const char * label)278 int mac_smack_apply_pid(pid_t pid, const char *label) {
279         return 0;
280 }
281 
mac_smack_fix_container(const char * path,const char * inside_path,LabelFixFlags flags)282 int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
283         return 0;
284 }
285 
mac_smack_fix_at(int dirfd,const char * path,LabelFixFlags flags)286 int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags) {
287         return 0;
288 }
289 
mac_smack_copy(const char * dest,const char * src)290 int mac_smack_copy(const char *dest, const char *src) {
291         return 0;
292 }
293 #endif
294 
rename_and_apply_smack_floor_label(const char * from,const char * to)295 int rename_and_apply_smack_floor_label(const char *from, const char *to) {
296 
297         if (rename(from, to) < 0)
298                 return -errno;
299 
300 #if HAVE_SMACK_RUN_LABEL
301         return mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
302 #else
303         return 0;
304 #endif
305 }
306