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