• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
16 #include "selinux_internal.h"
17 #include "policy.h"
18 #include "mapping.h"
19 
20 #define MAXVECTORS 8*sizeof(access_vector_t)
21 
22 struct discover_class_node {
23 	char *name;
24 	security_class_t value;
25 	char **perms;
26 
27 	struct discover_class_node *next;
28 };
29 
30 static struct discover_class_node *discover_class_cache = NULL;
31 
get_class_cache_entry_name(const char * s)32 static 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 
get_class_cache_entry_value(security_class_t c)41 static 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 
discover_class(const char * s)50 static 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 	if (strchr(s, '/') != NULL)
67 		return NULL;
68 
69 	/* allocate a node */
70 	node = malloc(sizeof(struct discover_class_node));
71 	if (node == NULL)
72 		return NULL;
73 
74 	/* allocate array for perms */
75 	node->perms = calloc(MAXVECTORS,sizeof(char*));
76 	if (node->perms == NULL)
77 		goto err1;
78 
79 	/* load up the name */
80 	node->name = strdup(s);
81 	if (node->name == NULL)
82 		goto err2;
83 
84 	/* load up class index */
85 	ret = snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
86 	if (ret < 0 || (size_t)ret >= sizeof path)
87 		goto err3;
88 
89 	fd = open(path, O_RDONLY | O_CLOEXEC);
90 	if (fd < 0)
91 		goto err3;
92 
93 	memset(buf, 0, sizeof(buf));
94 	ret = read(fd, buf, sizeof(buf) - 1);
95 	close(fd);
96 	if (ret < 0)
97 		goto err3;
98 
99 	if (sscanf(buf, "%hu", &node->value) != 1)
100 		goto err3;
101 
102 	/* load up permission indices */
103 	ret = snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
104 	if (ret < 0 || (size_t)ret >= sizeof path)
105 		goto err3;
106 
107 	dir = opendir(path);
108 	if (dir == NULL)
109 		goto err3;
110 
111 	dentry = readdir(dir);
112 	while (dentry != NULL) {
113 		unsigned int value;
114 		struct stat m;
115 
116 		ret = snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
117 		if (ret < 0 || (size_t)ret >= sizeof path)
118 			goto err4;
119 
120 		fd = open(path, O_RDONLY | O_CLOEXEC);
121 		if (fd < 0)
122 			goto err4;
123 
124 		if (fstat(fd, &m) < 0) {
125 			close(fd);
126 			goto err4;
127 		}
128 
129 		if (m.st_mode & S_IFDIR) {
130 			close(fd);
131 			dentry = readdir(dir);
132 			continue;
133 		}
134 
135 		memset(buf, 0, sizeof(buf));
136 		ret = read(fd, buf, sizeof(buf) - 1);
137 		close(fd);
138 		if (ret < 0)
139 			goto err4;
140 
141 		if (sscanf(buf, "%u", &value) != 1)
142 			goto err4;
143 
144 		if (value == 0 || value > MAXVECTORS)
145 			goto err4;
146 
147 		node->perms[value-1] = strdup(dentry->d_name);
148 		if (node->perms[value-1] == NULL)
149 			goto err4;
150 
151 		dentry = readdir(dir);
152 	}
153 	closedir(dir);
154 
155 	node->next = discover_class_cache;
156 	discover_class_cache = node;
157 
158 	return node;
159 
160 err4:
161 	closedir(dir);
162 	for (i = 0; i < MAXVECTORS; i++)
163 		free(node->perms[i]);
164 err3:
165 	free(node->name);
166 err2:
167 	free(node->perms);
168 err1:
169 	free(node);
170 	return NULL;
171 }
172 
selinux_flush_class_cache(void)173 void selinux_flush_class_cache(void)
174 {
175 	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
176 	size_t i;
177 
178 	while (cur != NULL) {
179 		free(cur->name);
180 
181 		for (i = 0; i < MAXVECTORS; i++)
182 			free(cur->perms[i]);
183 
184 		free(cur->perms);
185 
186 		prev = cur;
187 		cur = cur->next;
188 
189 		free(prev);
190 	}
191 
192 	discover_class_cache = NULL;
193 }
194 
195 
string_to_security_class(const char * s)196 security_class_t string_to_security_class(const char *s)
197 {
198 	struct discover_class_node *node;
199 
200 	node = get_class_cache_entry_name(s);
201 	if (node == NULL) {
202 		node = discover_class(s);
203 
204 		if (node == NULL) {
205 			errno = EINVAL;
206 			return 0;
207 		}
208 	}
209 
210 	return map_class(node->value);
211 }
212 
mode_to_security_class(mode_t m)213 security_class_t mode_to_security_class(mode_t m) {
214 
215 	if (S_ISREG(m))
216 		return string_to_security_class("file");
217 	if (S_ISDIR(m))
218 		return string_to_security_class("dir");
219 	if (S_ISCHR(m))
220 		return string_to_security_class("chr_file");
221 	if (S_ISBLK(m))
222 		return string_to_security_class("blk_file");
223 	if (S_ISFIFO(m))
224 		return string_to_security_class("fifo_file");
225 	if (S_ISLNK(m))
226 		return string_to_security_class("lnk_file");
227 	if (S_ISSOCK(m))
228 		return string_to_security_class("sock_file");
229 
230 	errno = EINVAL;
231 	return 0;
232 }
233 
string_to_av_perm(security_class_t tclass,const char * s)234 access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
235 {
236 	struct discover_class_node *node;
237 	security_class_t kclass = unmap_class(tclass);
238 
239 	node = get_class_cache_entry_value(kclass);
240 	if (node != NULL) {
241 		size_t i;
242 		for (i = 0; i < MAXVECTORS && node->perms[i] != NULL; i++)
243 			if (strcmp(node->perms[i],s) == 0)
244 				return map_perm(tclass, UINT32_C(1)<<i);
245 	}
246 
247 	errno = EINVAL;
248 	return 0;
249 }
250 
security_class_to_string(security_class_t tclass)251 const char *security_class_to_string(security_class_t tclass)
252 {
253 	struct discover_class_node *node;
254 
255 	tclass = unmap_class(tclass);
256 
257 	node = get_class_cache_entry_value(tclass);
258 	if (node == NULL)
259 		return NULL;
260 	else
261 		return node->name;
262 }
263 
security_av_perm_to_string(security_class_t tclass,access_vector_t av)264 const char *security_av_perm_to_string(security_class_t tclass,
265 				       access_vector_t av)
266 {
267 	struct discover_class_node *node;
268 	size_t i;
269 
270 	av = unmap_perm(tclass, av);
271 	tclass = unmap_class(tclass);
272 
273 	node = get_class_cache_entry_value(tclass);
274 	if (av && node)
275 		for (i = 0; i<MAXVECTORS; i++)
276 			if ((UINT32_C(1)<<i) & av)
277 				return node->perms[i];
278 
279 	return NULL;
280 }
281 
security_av_string(security_class_t tclass,access_vector_t av,char ** res)282 int security_av_string(security_class_t tclass, access_vector_t av, char **res)
283 {
284 	unsigned int i;
285 	size_t len = 5;
286 	access_vector_t tmp = av;
287 	int rc = 0;
288 	const char *str;
289 	char *ptr;
290 
291 	/* first pass computes the required length */
292 	for (i = 0; tmp; tmp >>= 1, i++) {
293 		if (tmp & 1) {
294 			str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i));
295 			if (str)
296 				len += strlen(str) + 1;
297 		}
298 	}
299 
300 	*res = malloc(len);
301 	if (!*res) {
302 		rc = -1;
303 		goto out;
304 	}
305 
306 	/* second pass constructs the string */
307 	tmp = av;
308 	ptr = *res;
309 
310 	if (!av) {
311 		sprintf(ptr, "null");
312 		goto out;
313 	}
314 
315 	ptr += sprintf(ptr, "{ ");
316 	for (i = 0; tmp; tmp >>= 1, i++) {
317 		if (tmp & 1) {
318 			str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i));
319 			if (str)
320 				ptr += sprintf(ptr, "%s ", str);
321 		}
322 	}
323 	sprintf(ptr, "}");
324 out:
325 	return rc;
326 }
327 
print_access_vector(security_class_t tclass,access_vector_t av)328 void print_access_vector(security_class_t tclass, access_vector_t av)
329 {
330 	const char *permstr;
331 	access_vector_t bit = 1;
332 
333 	if (av == 0) {
334 		printf(" null");
335 		return;
336 	}
337 
338 	printf(" {");
339 
340 	while (av) {
341 		if (av & bit) {
342 			permstr = security_av_perm_to_string(tclass, bit);
343 			if (!permstr)
344 				break;
345 			printf(" %s", permstr);
346 			av &= ~bit;
347 		}
348 		bit <<= 1;
349 	}
350 
351 	if (av)
352 		printf(" 0x%x", av);
353 	printf(" }");
354 }
355