xref: /aosp_15_r20/external/selinux/libselinux/src/stringrep.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
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  	for (;;) {
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  			if (!av)
348  				break;
349  		}
350  		bit <<= 1;
351  	}
352  
353  	if (av)
354  		printf(" 0x%x", av);
355  	printf(" }");
356  }
357