blob: 29757b750878a46984a6bc22641eb5e1bde44f2b [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001/*
2 * String representation support for classes and permissions.
3 */
4#include <sys/stat.h>
5#include <dirent.h>
6#include <fcntl.h>
7#include <limits.h>
8#include <unistd.h>
9#include <errno.h>
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <stdint.h>
15#include <ctype.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040016#include "selinux_internal.h"
17#include "policy.h"
18#include "mapping.h"
19
Joshua Brindle13cd4c82008-08-19 15:30:36 -040020#define MAXVECTORS 8*sizeof(access_vector_t)
21
Joshua Brindle13cd4c82008-08-19 15:30:36 -040022struct discover_class_node {
23 char *name;
24 security_class_t value;
25 char **perms;
26
27 struct discover_class_node *next;
28};
29
30static struct discover_class_node *discover_class_cache = NULL;
31
32static struct discover_class_node * get_class_cache_entry_name(const char *s)
33{
34 struct discover_class_node *node = discover_class_cache;
35
36 for (; node != NULL && strcmp(s,node->name) != 0; node = node->next);
37
38 return node;
39}
40
41static struct discover_class_node * get_class_cache_entry_value(security_class_t c)
42{
43 struct discover_class_node *node = discover_class_cache;
44
45 for (; node != NULL && c != node->value; node = node->next);
46
47 return node;
48}
49
50static struct discover_class_node * discover_class(const char *s)
51{
52 int fd, ret;
53 char path[PATH_MAX];
54 char buf[20];
55 DIR *dir;
56 struct dirent *dentry;
57 size_t i;
58
59 struct discover_class_node *node;
60
61 if (!selinux_mnt) {
62 errno = ENOENT;
63 return NULL;
64 }
65
66 /* allocate a node */
67 node = malloc(sizeof(struct discover_class_node));
68 if (node == NULL)
69 return NULL;
70
71 /* allocate array for perms */
Stephen Smalley76913d82014-07-09 13:25:56 -040072 node->perms = calloc(MAXVECTORS,sizeof(char*));
Joshua Brindle13cd4c82008-08-19 15:30:36 -040073 if (node->perms == NULL)
74 goto err1;
75
76 /* load up the name */
77 node->name = strdup(s);
78 if (node->name == NULL)
79 goto err2;
80
81 /* load up class index */
82 snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
Nick Kralevich64afa1a2016-12-11 09:30:16 -080083 fd = open(path, O_RDONLY | O_CLOEXEC);
Joshua Brindle13cd4c82008-08-19 15:30:36 -040084 if (fd < 0)
85 goto err3;
86
87 memset(buf, 0, sizeof(buf));
88 ret = read(fd, buf, sizeof(buf) - 1);
89 close(fd);
90 if (ret < 0)
91 goto err3;
92
Eamon Walshb27ff332009-02-27 18:05:24 -050093 if (sscanf(buf, "%hu", &node->value) != 1)
Joshua Brindle13cd4c82008-08-19 15:30:36 -040094 goto err3;
95
Nicolas Ioossb550c0e2019-08-05 22:11:20 +020096 /* load up permission indices */
Joshua Brindle13cd4c82008-08-19 15:30:36 -040097 snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
98 dir = opendir(path);
99 if (dir == NULL)
100 goto err3;
101
102 dentry = readdir(dir);
103 while (dentry != NULL) {
104 unsigned int value;
105 struct stat m;
106
107 snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
Eric Parisaa62cd62012-11-29 09:41:38 -0500108 fd = open(path, O_RDONLY | O_CLOEXEC);
109 if (fd < 0)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400110 goto err4;
111
Eric Parisaa62cd62012-11-29 09:41:38 -0500112 if (fstat(fd, &m) < 0) {
113 close(fd);
114 goto err4;
115 }
116
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400117 if (m.st_mode & S_IFDIR) {
Eric Parisaa62cd62012-11-29 09:41:38 -0500118 close(fd);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400119 dentry = readdir(dir);
120 continue;
121 }
122
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400123 memset(buf, 0, sizeof(buf));
124 ret = read(fd, buf, sizeof(buf) - 1);
125 close(fd);
126 if (ret < 0)
127 goto err4;
128
129 if (sscanf(buf, "%u", &value) != 1)
130 goto err4;
131
Stephen Smalley76913d82014-07-09 13:25:56 -0400132 if (value == 0 || value > MAXVECTORS)
Eric Parisaa62cd62012-11-29 09:41:38 -0500133 goto err4;
134
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400135 node->perms[value-1] = strdup(dentry->d_name);
136 if (node->perms[value-1] == NULL)
137 goto err4;
138
139 dentry = readdir(dir);
140 }
141 closedir(dir);
142
143 node->next = discover_class_cache;
144 discover_class_cache = node;
145
146 return node;
147
148err4:
149 closedir(dir);
Unto Stene1a74392019-05-10 16:52:08 +0300150 for (i = 0; i < MAXVECTORS; i++)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400151 free(node->perms[i]);
152err3:
153 free(node->name);
154err2:
155 free(node->perms);
156err1:
157 free(node);
158 return NULL;
159}
160
Stephen Smalley7bece372020-01-21 11:18:22 -0500161void selinux_flush_class_cache(void)
Stephen Smalleyb408d722015-09-18 16:03:24 -0400162{
163 struct discover_class_node *cur = discover_class_cache, *prev = NULL;
164 size_t i;
165
166 while (cur != NULL) {
167 free(cur->name);
168
169 for (i = 0; i < MAXVECTORS; i++)
170 free(cur->perms[i]);
171
172 free(cur->perms);
173
174 prev = cur;
175 cur = cur->next;
176
177 free(prev);
178 }
179
180 discover_class_cache = NULL;
181}
182
Stephen Smalley7bece372020-01-21 11:18:22 -0500183hidden_def(selinux_flush_class_cache)
184
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400185security_class_t string_to_security_class(const char *s)
186{
187 struct discover_class_node *node;
188
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400189 node = get_class_cache_entry_name(s);
190 if (node == NULL) {
191 node = discover_class(s);
192
193 if (node == NULL) {
194 errno = EINVAL;
195 return 0;
196 }
197 }
198
199 return map_class(node->value);
200}
201
rhatdan13b599d2012-10-17 15:28:49 -0400202security_class_t mode_to_security_class(mode_t m) {
203
204 if (S_ISREG(m))
205 return string_to_security_class("file");
206 if (S_ISDIR(m))
207 return string_to_security_class("dir");
208 if (S_ISCHR(m))
209 return string_to_security_class("chr_file");
210 if (S_ISBLK(m))
211 return string_to_security_class("blk_file");
212 if (S_ISFIFO(m))
213 return string_to_security_class("fifo_file");
214 if (S_ISLNK(m))
215 return string_to_security_class("lnk_file");
216 if (S_ISSOCK(m))
217 return string_to_security_class("sock_file");
218
Unto Stene1a74392019-05-10 16:52:08 +0300219 errno = EINVAL;
rhatdan13b599d2012-10-17 15:28:49 -0400220 return 0;
221}
222
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400223access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
224{
225 struct discover_class_node *node;
226 security_class_t kclass = unmap_class(tclass);
227
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400228 node = get_class_cache_entry_value(kclass);
229 if (node != NULL) {
230 size_t i;
Unto Stene1a74392019-05-10 16:52:08 +0300231 for (i = 0; i < MAXVECTORS && node->perms[i] != NULL; i++)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400232 if (strcmp(node->perms[i],s) == 0)
233 return map_perm(tclass, 1<<i);
234 }
235
236 errno = EINVAL;
237 return 0;
238}
239
240const char *security_class_to_string(security_class_t tclass)
241{
242 struct discover_class_node *node;
243
244 tclass = unmap_class(tclass);
245
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400246 node = get_class_cache_entry_value(tclass);
247 if (node == NULL)
Stephen Smalley76913d82014-07-09 13:25:56 -0400248 return NULL;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400249 else
250 return node->name;
251}
252
253const char *security_av_perm_to_string(security_class_t tclass,
254 access_vector_t av)
255{
256 struct discover_class_node *node;
257 size_t i;
258
259 av = unmap_perm(tclass, av);
260 tclass = unmap_class(tclass);
261
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400262 node = get_class_cache_entry_value(tclass);
263 if (av && node)
264 for (i = 0; i<MAXVECTORS; i++)
265 if ((1<<i) & av)
266 return node->perms[i];
267
Stephen Smalley76913d82014-07-09 13:25:56 -0400268 return NULL;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400269}
270
271int security_av_string(security_class_t tclass, access_vector_t av, char **res)
272{
Mike Palmiotto86df2b22019-09-16 16:30:15 -0400273 unsigned int i;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400274 size_t len = 5;
275 access_vector_t tmp = av;
276 int rc = 0;
277 const char *str;
278 char *ptr;
279
280 /* first pass computes the required length */
Mike Palmiotto86df2b22019-09-16 16:30:15 -0400281 for (i = 0; tmp; tmp >>= 1, i++) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400282 if (tmp & 1) {
283 str = security_av_perm_to_string(tclass, av & (1<<i));
284 if (str)
285 len += strlen(str) + 1;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400286 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400287 }
288
289 *res = malloc(len);
290 if (!*res) {
291 rc = -1;
292 goto out;
293 }
294
295 /* second pass constructs the string */
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400296 tmp = av;
297 ptr = *res;
298
299 if (!av) {
300 sprintf(ptr, "null");
301 goto out;
302 }
303
304 ptr += sprintf(ptr, "{ ");
Mike Palmiotto86df2b22019-09-16 16:30:15 -0400305 for (i = 0; tmp; tmp >>= 1, i++) {
306 if (tmp & 1) {
307 str = security_av_perm_to_string(tclass, av & (1<<i));
308 if (str)
309 ptr += sprintf(ptr, "%s ", str);
310 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400311 }
312 sprintf(ptr, "}");
313out:
314 return rc;
315}
316
317void print_access_vector(security_class_t tclass, access_vector_t av)
318{
319 const char *permstr;
320 access_vector_t bit = 1;
321
322 if (av == 0) {
323 printf(" null");
324 return;
325 }
326
327 printf(" {");
328
329 while (av) {
330 if (av & bit) {
331 permstr = security_av_perm_to_string(tclass, bit);
332 if (!permstr)
333 break;
334 printf(" %s", permstr);
335 av &= ~bit;
336 }
337 bit <<= 1;
338 }
339
340 if (av)
341 printf(" 0x%x", av);
342 printf(" }");
343}