1 /* Authors: Joshua Brindle <jbrindle@tresys.com>
2 * Jason Tang <jtang@tresys.com>
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 return NULL;
151
152 retry:
153 if (__builtin_mul_overflow(size, 2, &size))
154 goto err;
155 p = realloc(buffer, size);
156 if (!p)
157 goto err;
158 buffer = p;
159 remaining = size;
160
161 len = snprintf(p, remaining, "ioctl { ");
162 if (len < 0 || (size_t)len >= remaining)
163 goto err;
164 p += len;
165 remaining -= len;
166
167 in_range = 0;
168 for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
169 if (!xperm_test(bit, xperms->perms))
170 continue;
171
172 if (in_range && next_bit_in_range(bit, xperms->perms)) {
173 /* continue until high value found */
174 continue;
175 } else if (next_bit_in_range(bit, xperms->perms)) {
176 /* low value */
177 low_bit = bit;
178 in_range = 1;
179 continue;
180 }
181
182 if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
183 value = xperms->driver<<8 | bit;
184 if (in_range) {
185 low_value = xperms->driver<<8 | low_bit;
186 len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, value);
187 } else {
188 len = snprintf(p, remaining, "0x%hx ", value);
189 }
190 } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
191 value = bit << 8;
192 if (in_range) {
193 low_value = low_bit << 8;
194 len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
195 } else {
196 len = snprintf(p, remaining, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
197 }
198
199 }
200
201 if (len < 0)
202 goto err;
203 if ((size_t) len >= remaining)
204 goto retry;
205
206 p += len;
207 remaining -= len;
208 if (in_range)
209 in_range = 0;
210 }
211
212 len = snprintf(p, remaining, "}");
213 if (len < 0)
214 goto err;
215 if ((size_t) len >= remaining)
216 goto retry;
217
218 return buffer;
219
220 err:
221 free(buffer);
222 return NULL;
223 }
224
225 /*
226 * The tokenize and tokenize_str functions may be used to
227 * replace sscanf to read tokens from buffers.
228 */
229
230 /* Read a token from a buffer */
tokenize_str(char delim,char ** str,const char ** ptr,size_t * len)231 static inline int tokenize_str(char delim, char **str, const char **ptr, size_t *len)
232 {
233 const char *tmp_buf = *ptr;
234 *str = NULL;
235
236 while (**ptr != '\0') {
237 if (isspace(delim) && isspace(**ptr)) {
238 (*ptr)++;
239 break;
240 } else if (!isspace(delim) && **ptr == delim) {
241 (*ptr)++;
242 break;
243 }
244
245 (*ptr)++;
246 }
247
248 *len = *ptr - tmp_buf;
249 /* If the end of the string has not been reached, this will ensure the
250 * delimiter is not included when returning the token.
251 */
252 if (**ptr != '\0') {
253 (*len)--;
254 }
255
256 *str = strndup(tmp_buf, *len);
257 if (!*str) {
258 return -1;
259 }
260
261 /* Squash spaces if the delimiter is a whitespace character */
262 while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
263 (*ptr)++;
264 }
265
266 return 0;
267 }
268
269 /*
270 * line_buf - Buffer containing string to tokenize.
271 * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
272 * be tokenized using isspace().
273 * num_args - The number of parameter entries to process.
274 * ... - A 'char **' for each parameter.
275 * returns - The number of items processed.
276 *
277 * This function calls tokenize_str() to do the actual string processing. The
278 * caller is responsible for calling free() on each additional argument. The
279 * function will not tokenize more than num_args and the last argument will
280 * contain the remaining content of line_buf. If the delimiter is any whitespace
281 * character, then all whitespace will be squashed.
282 */
tokenize(const char * line_buf,char delim,int num_args,...)283 int tokenize(const char *line_buf, char delim, int num_args, ...)
284 {
285 char **arg;
286 const char *buf_p;
287 int rc, items;
288 size_t arg_len = 0;
289 va_list ap;
290
291 buf_p = line_buf;
292
293 /* Process the arguments */
294 va_start(ap, num_args);
295
296 for (items = 0; items < num_args && *buf_p != '\0'; items++) {
297 arg = va_arg(ap, char **);
298
299 /* Save the remainder of the string in arg */
300 if (items == num_args - 1) {
301 *arg = strdup(buf_p);
302 if (*arg == NULL) {
303 goto exit;
304 }
305
306 continue;
307 }
308
309 rc = tokenize_str(delim, arg, &buf_p, &arg_len);
310 if (rc < 0) {
311 goto exit;
312 }
313 }
314
315 exit:
316 va_end(ap);
317 return items;
318 }
319