xref: /aosp_15_r20/external/selinux/libsepol/src/util.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /* Authors: Joshua Brindle <[email protected]>
2  * 	    Jason Tang <[email protected]>
3  *
4  * Copyright (C) 2005-2006 Tresys Technology, LLC
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2.1 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 #include <sepol/policydb/flask_types.h>
28 #include <sepol/policydb/policydb.h>
29 #include <sepol/policydb/util.h>
30 
31 #include "private.h"
32 
33 struct val_to_name {
34 	unsigned int val;
35 	const char *name;
36 };
37 
38 /* Add an unsigned integer to a dynamically reallocated array.  *cnt
39  * is a reference pointer to the number of values already within array
40  * *a; it will be incremented upon successfully appending i.  If *a is
41  * NULL then this function will create a new array (*cnt is reset to
42  * 0).  Return 0 on success, -1 on out of memory. */
add_i_to_a(uint32_t i,uint32_t * cnt,uint32_t ** a)43 int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
44 {
45 	uint32_t *new;
46 
47 	if (cnt == NULL || *cnt == UINT32_MAX || a == NULL)
48 		return -1;
49 
50 	/* FIX ME: This is not very elegant! We use an array that we
51 	 * grow as new uint32_t are added to an array.  But rather
52 	 * than be smart about it, for now we realloc() the array each
53 	 * time a new uint32_t is added! */
54 	if (*a != NULL)
55 		new = (uint32_t *) reallocarray(*a, *cnt + 1, sizeof(uint32_t));
56 	else {			/* empty list */
57 
58 		*cnt = 0;
59 		new = (uint32_t *) malloc(sizeof(uint32_t));
60 	}
61 	if (new == NULL) {
62 		return -1;
63 	}
64 	new[*cnt] = i;
65 	(*cnt)++;
66 	*a = new;
67 	return 0;
68 }
69 
perm_name(hashtab_key_t key,hashtab_datum_t datum,void * data)70 static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
71 {
72 	struct val_to_name *v = data;
73 	perm_datum_t *perdatum;
74 
75 	perdatum = (perm_datum_t *) datum;
76 
77 	if (v->val == perdatum->s.value) {
78 		v->name = key;
79 		return 1;
80 	}
81 
82 	return 0;
83 }
84 
sepol_av_to_string(const policydb_t * policydbp,sepol_security_class_t tclass,sepol_access_vector_t av)85 char *sepol_av_to_string(const policydb_t *policydbp, sepol_security_class_t tclass,
86 			 sepol_access_vector_t av)
87 {
88 	struct val_to_name v;
89 	const class_datum_t *cladatum = policydbp->class_val_to_struct[tclass - 1];
90 	uint32_t i;
91 	int rc;
92 	char *buffer = NULL, *p;
93 	int len;
94 	size_t remaining, size = 64;
95 
96 retry:
97 	if (__builtin_mul_overflow(size, 2, &size))
98 		goto err;
99 	p = realloc(buffer, size);
100 	if (!p)
101 		goto err;
102 	*p = '\0'; /* Just in case there are no permissions */
103 	buffer = p;
104 	remaining = size;
105 
106 	for (i = 0; i < cladatum->permissions.nprim; i++) {
107 		if (av & (UINT32_C(1) << i)) {
108 			v.val = i + 1;
109 			rc = hashtab_map(cladatum->permissions.table,
110 					 perm_name, &v);
111 			if (!rc && cladatum->comdatum) {
112 				rc = hashtab_map(cladatum->comdatum->
113 						 permissions.table, perm_name,
114 						 &v);
115 			}
116 			if (rc == 1) {
117 				len = snprintf(p, remaining, " %s", v.name);
118 				if (len < 0)
119 					goto err;
120 				if ((size_t) len >= remaining)
121 					goto retry;
122 				p += len;
123 				remaining -= len;
124 			}
125 		}
126 	}
127 
128 	return buffer;
129 
130 err:
131 	free(buffer);
132 	return NULL;
133 }
134 
135 #define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p))
136 
sepol_extended_perms_to_string(const avtab_extended_perms_t * xperms)137 char *sepol_extended_perms_to_string(const avtab_extended_perms_t *xperms)
138 {
139 	uint16_t value;
140 	uint16_t low_bit;
141 	uint16_t low_value;
142 	unsigned int bit;
143 	unsigned int in_range;
144 	char *buffer = NULL, *p;
145 	int len;
146 	size_t remaining, size = 128;
147 
148 	if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
149 		&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)
150 		&& (xperms->specified != AVTAB_XPERMS_NLMSG))
151 		return NULL;
152 
153 retry:
154 	if (__builtin_mul_overflow(size, 2, &size))
155 		goto err;
156 	p = realloc(buffer, size);
157 	if (!p)
158 		goto err;
159 	buffer = p;
160 	remaining = size;
161 
162 	if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION)
163 		|| (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
164 		len = snprintf(p, remaining, "ioctl { ");
165 	} else {
166 		len = snprintf(p, remaining, "nlmsg { ");
167 	}
168 	if (len < 0 || (size_t)len >= remaining)
169 		goto err;
170 	p += len;
171 	remaining -= len;
172 
173 	in_range = 0;
174 	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
175 		if (!xperm_test(bit, xperms->perms))
176 			continue;
177 
178 		if (in_range && next_bit_in_range(bit, xperms->perms)) {
179 			/* continue until high value found */
180 			continue;
181 		} else if (next_bit_in_range(bit, xperms->perms)) {
182 			/* low value */
183 			low_bit = bit;
184 			in_range = 1;
185 			continue;
186 		}
187 
188 		if (xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified == AVTAB_XPERMS_NLMSG) {
189 			value = xperms->driver<<8 | bit;
190 			if (in_range) {
191 				low_value = xperms->driver<<8 | low_bit;
192 				len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, value);
193 			} else {
194 				len = snprintf(p, remaining, "0x%hx ", value);
195 			}
196 		} else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
197 			value = bit << 8;
198 			if (in_range) {
199 				low_value = low_bit << 8;
200 				len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
201 			} else {
202 				len = snprintf(p, remaining, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
203 			}
204 
205 		}
206 
207 		if (len < 0)
208 			goto err;
209 		if ((size_t) len >= remaining)
210 			goto retry;
211 
212 		p += len;
213 		remaining -= len;
214 		if (in_range)
215 			in_range = 0;
216 	}
217 
218 	len = snprintf(p, remaining, "}");
219 	if (len < 0)
220 		goto err;
221 	if ((size_t) len >= remaining)
222 		goto retry;
223 
224 	return buffer;
225 
226 err:
227 	free(buffer);
228 	return NULL;
229 }
230 
231 /*
232  * The tokenize and tokenize_str functions may be used to
233  * replace sscanf to read tokens from buffers.
234  */
235 
236 /* Read a token from a buffer */
tokenize_str(char delim,char ** str,const char ** ptr,size_t * len)237 static inline int tokenize_str(char delim, char **str, const char **ptr, size_t *len)
238 {
239 	const char *tmp_buf = *ptr;
240 	*str = NULL;
241 
242 	while (**ptr != '\0') {
243 		if (isspace(delim) && isspace(**ptr)) {
244 			(*ptr)++;
245 			break;
246 		} else if (!isspace(delim) && **ptr == delim) {
247 			(*ptr)++;
248 			break;
249 		}
250 
251 		(*ptr)++;
252 	}
253 
254 	*len = *ptr - tmp_buf;
255 	/* If the end of the string has not been reached, this will ensure the
256 	 * delimiter is not included when returning the token.
257 	 */
258 	if (**ptr != '\0') {
259 		(*len)--;
260 	}
261 
262 	*str = strndup(tmp_buf, *len);
263 	if (!*str) {
264 		return -1;
265 	}
266 
267 	/* Squash spaces if the delimiter is a whitespace character */
268 	while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
269 		(*ptr)++;
270 	}
271 
272 	return 0;
273 }
274 
275 /*
276  * line_buf - Buffer containing string to tokenize.
277  * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
278  *	    be tokenized using isspace().
279  * num_args - The number of parameter entries to process.
280  * ...      - A 'char **' for each parameter.
281  * returns  - The number of items processed.
282  *
283  * This function calls tokenize_str() to do the actual string processing. The
284  * caller is responsible for calling free() on each additional argument. The
285  * function will not tokenize more than num_args and the last argument will
286  * contain the remaining content of line_buf. If the delimiter is any whitespace
287  * character, then all whitespace will be squashed.
288  */
tokenize(const char * line_buf,char delim,int num_args,...)289 int tokenize(const char *line_buf, char delim, int num_args, ...)
290 {
291 	char **arg;
292 	const char *buf_p;
293 	int rc, items;
294 	size_t arg_len = 0;
295 	va_list ap;
296 
297 	buf_p = line_buf;
298 
299 	/* Process the arguments */
300 	va_start(ap, num_args);
301 
302 	for (items = 0; items < num_args && *buf_p != '\0'; items++) {
303 		arg = va_arg(ap, char **);
304 
305 		/* Save the remainder of the string in arg */
306 		if (items == num_args - 1) {
307 			*arg = strdup(buf_p);
308 			if (*arg == NULL) {
309 				goto exit;
310 			}
311 
312 			continue;
313 		}
314 
315 		rc = tokenize_str(delim, arg, &buf_p, &arg_len);
316 		if (rc < 0) {
317 			goto exit;
318 		}
319 	}
320 
321 exit:
322 	va_end(ap);
323 	return items;
324 }
325