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 #include <dso.h>
31
32 struct val_to_name {
33 unsigned int val;
34 char *name;
35 };
36
37 /* Add an unsigned integer to a dynamically reallocated array. *cnt
38 * is a reference pointer to the number of values already within array
39 * *a; it will be incremented upon successfully appending i. If *a is
40 * NULL then this function will create a new array (*cnt is reset to
41 * 0). Return 0 on success, -1 on out of memory. */
add_i_to_a(uint32_t i,uint32_t * cnt,uint32_t ** a)42 int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
43 {
44 if (cnt == NULL || a == NULL)
45 return -1;
46
47 /* FIX ME: This is not very elegant! We use an array that we
48 * grow as new uint32_t are added to an array. But rather
49 * than be smart about it, for now we realloc() the array each
50 * time a new uint32_t is added! */
51 if (*a != NULL)
52 *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
53 else { /* empty list */
54
55 *cnt = 0;
56 *a = (uint32_t *) malloc(sizeof(uint32_t));
57 }
58 if (*a == NULL) {
59 return -1;
60 }
61 (*a)[*cnt] = i;
62 (*cnt)++;
63 return 0;
64 }
65
perm_name(hashtab_key_t key,hashtab_datum_t datum,void * data)66 static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
67 {
68 struct val_to_name *v = data;
69 perm_datum_t *perdatum;
70
71 perdatum = (perm_datum_t *) datum;
72
73 if (v->val == perdatum->s.value) {
74 v->name = key;
75 return 1;
76 }
77
78 return 0;
79 }
80
sepol_av_to_string(policydb_t * policydbp,uint32_t tclass,sepol_access_vector_t av)81 char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
82 sepol_access_vector_t av)
83 {
84 struct val_to_name v;
85 static char avbuf[1024];
86 class_datum_t *cladatum;
87 char *perm = NULL, *p;
88 unsigned int i;
89 int rc;
90 int avlen = 0, len;
91
92 memset(avbuf, 0, sizeof avbuf);
93 cladatum = policydbp->class_val_to_struct[tclass - 1];
94 p = avbuf;
95 for (i = 0; i < cladatum->permissions.nprim; i++) {
96 if (av & (1 << i)) {
97 v.val = i + 1;
98 rc = hashtab_map(cladatum->permissions.table,
99 perm_name, &v);
100 if (!rc && cladatum->comdatum) {
101 rc = hashtab_map(cladatum->comdatum->
102 permissions.table, perm_name,
103 &v);
104 }
105 if (rc)
106 perm = v.name;
107 if (perm) {
108 len =
109 snprintf(p, sizeof(avbuf) - avlen, " %s",
110 perm);
111 if (len < 0
112 || (size_t) len >= (sizeof(avbuf) - avlen))
113 return NULL;
114 p += len;
115 avlen += len;
116 }
117 }
118 }
119
120 return avbuf;
121 }
122
123 #define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
124
sepol_extended_perms_to_string(avtab_extended_perms_t * xperms)125 char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
126 {
127 uint16_t value;
128 uint16_t low_bit;
129 uint16_t low_value;
130 unsigned int bit;
131 unsigned int in_range = 0;
132 static char xpermsbuf[2048];
133 xpermsbuf[0] = '\0';
134 char *p;
135 int len, xpermslen = 0;
136 p = xpermsbuf;
137
138 if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
139 && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
140 return NULL;
141
142 len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
143 p += len;
144 xpermslen += len;
145
146 for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
147 if (!xperm_test(bit, xperms->perms))
148 continue;
149
150 if (in_range && next_bit_in_range(bit, xperms->perms)) {
151 /* continue until high value found */
152 continue;
153 } else if (next_bit_in_range(bit, xperms->perms)) {
154 /* low value */
155 low_bit = bit;
156 in_range = 1;
157 continue;
158 }
159
160 if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
161 value = xperms->driver<<8 | bit;
162 if (in_range) {
163 low_value = xperms->driver<<8 | low_bit;
164 len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
165 } else {
166 len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
167 }
168 } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
169 value = bit << 8;
170 if (in_range) {
171 low_value = low_bit << 8;
172 len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
173 } else {
174 len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
175 }
176
177 }
178
179 if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
180 return NULL;
181
182 p += len;
183 xpermslen += len;
184 if (in_range)
185 in_range = 0;
186 }
187
188 len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
189 if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
190 return NULL;
191
192 return xpermsbuf;
193 }
194
195 /*
196 * The tokenize and tokenize_str functions may be used to
197 * replace sscanf to read tokens from buffers.
198 */
199
200 /* Read a token from a buffer */
tokenize_str(char delim,char ** str,char ** ptr,size_t * len)201 static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
202 {
203 char *tmp_buf = *ptr;
204 *str = NULL;
205
206 while (**ptr != '\0') {
207 if (isspace(delim) && isspace(**ptr)) {
208 (*ptr)++;
209 break;
210 } else if (!isspace(delim) && **ptr == delim) {
211 (*ptr)++;
212 break;
213 }
214
215 (*ptr)++;
216 }
217
218 *len = *ptr - tmp_buf;
219 /* If the end of the string has not been reached, this will ensure the
220 * delimiter is not included when returning the token.
221 */
222 if (**ptr != '\0') {
223 (*len)--;
224 }
225
226 *str = strndup(tmp_buf, *len);
227 if (!*str) {
228 return -1;
229 }
230
231 /* Squash spaces if the delimiter is a whitespace character */
232 while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
233 (*ptr)++;
234 }
235
236 return 0;
237 }
238
239 /*
240 * line_buf - Buffer containing string to tokenize.
241 * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
242 * be tokenized using isspace().
243 * num_args - The number of parameter entries to process.
244 * ... - A 'char **' for each parameter.
245 * returns - The number of items processed.
246 *
247 * This function calls tokenize_str() to do the actual string processing. The
248 * caller is responsible for calling free() on each additional argument. The
249 * function will not tokenize more than num_args and the last argument will
250 * contain the remaining content of line_buf. If the delimiter is any whitespace
251 * character, then all whitespace will be squashed.
252 */
tokenize(char * line_buf,char delim,int num_args,...)253 int hidden tokenize(char *line_buf, char delim, int num_args, ...)
254 {
255 char **arg, *buf_p;
256 int rc, items;
257 size_t arg_len = 0;
258 va_list ap;
259
260 buf_p = line_buf;
261
262 /* Process the arguments */
263 va_start(ap, num_args);
264
265 for (items = 0; items < num_args && *buf_p != '\0'; items++) {
266 arg = va_arg(ap, char **);
267
268 /* Save the remainder of the string in arg */
269 if (items == num_args - 1) {
270 *arg = strdup(buf_p);
271 if (*arg == NULL) {
272 goto exit;
273 }
274
275 continue;
276 }
277
278 rc = tokenize_str(delim, arg, &buf_p, &arg_len);
279 if (rc < 0) {
280 goto exit;
281 }
282 }
283
284 exit:
285 va_end(ap);
286 return items;
287 }
288