ebitmap.c revision 255e72915d4cbddceb435e13d81601755714e9f3
1
2/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
3
4/* FLASK */
5
6/*
7 * Implementation of the extensible bitmap type.
8 */
9
10#include <stdlib.h>
11
12#include <sepol/policydb/ebitmap.h>
13#include <sepol/policydb/policydb.h>
14
15#include "debug.h"
16#include "private.h"
17
18int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2)
19{
20	ebitmap_node_t *n1, *n2, *new, *prev;
21
22	ebitmap_init(dst);
23
24	n1 = e1->node;
25	n2 = e2->node;
26	prev = 0;
27	while (n1 || n2) {
28		new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
29		if (!new) {
30			ebitmap_destroy(dst);
31			return -ENOMEM;
32		}
33		memset(new, 0, sizeof(ebitmap_node_t));
34		if (n1 && n2 && n1->startbit == n2->startbit) {
35			new->startbit = n1->startbit;
36			new->map = n1->map | n2->map;
37			n1 = n1->next;
38			n2 = n2->next;
39		} else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
40			new->startbit = n1->startbit;
41			new->map = n1->map;
42			n1 = n1->next;
43		} else {
44			new->startbit = n2->startbit;
45			new->map = n2->map;
46			n2 = n2->next;
47		}
48
49		new->next = 0;
50		if (prev)
51			prev->next = new;
52		else
53			dst->node = new;
54		prev = new;
55	}
56
57	dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
58	return 0;
59}
60
61int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1)
62{
63	ebitmap_t tmp;
64
65	if (ebitmap_or(&tmp, dst, e1))
66		return -1;
67	ebitmap_destroy(dst);
68	dst->node = tmp.node;
69	dst->highbit = tmp.highbit;
70
71	return 0;
72}
73
74int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2)
75{
76	ebitmap_node_t *n1, *n2;
77
78	if (e1->highbit != e2->highbit)
79		return 0;
80
81	n1 = e1->node;
82	n2 = e2->node;
83	while (n1 && n2 &&
84	       (n1->startbit == n2->startbit) && (n1->map == n2->map)) {
85		n1 = n1->next;
86		n2 = n2->next;
87	}
88
89	if (n1 || n2)
90		return 0;
91
92	return 1;
93}
94
95int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src)
96{
97	ebitmap_node_t *n, *new, *prev;
98
99	ebitmap_init(dst);
100	n = src->node;
101	prev = 0;
102	while (n) {
103		new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
104		if (!new) {
105			ebitmap_destroy(dst);
106			return -ENOMEM;
107		}
108		memset(new, 0, sizeof(ebitmap_node_t));
109		new->startbit = n->startbit;
110		new->map = n->map;
111		new->next = 0;
112		if (prev)
113			prev->next = new;
114		else
115			dst->node = new;
116		prev = new;
117		n = n->next;
118	}
119
120	dst->highbit = src->highbit;
121	return 0;
122}
123
124int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2)
125{
126	ebitmap_node_t *n1, *n2;
127
128	if (e1->highbit < e2->highbit)
129		return 0;
130
131	n1 = e1->node;
132	n2 = e2->node;
133	while (n1 && n2 && (n1->startbit <= n2->startbit)) {
134		if (n1->startbit < n2->startbit) {
135			n1 = n1->next;
136			continue;
137		}
138		if ((n1->map & n2->map) != n2->map)
139			return 0;
140
141		n1 = n1->next;
142		n2 = n2->next;
143	}
144
145	if (n2)
146		return 0;
147
148	return 1;
149}
150
151int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit)
152{
153	ebitmap_node_t *n;
154
155	if (e->highbit < bit)
156		return 0;
157
158	n = e->node;
159	while (n && (n->startbit <= bit)) {
160		if ((n->startbit + MAPSIZE) > bit) {
161			if (n->map & (MAPBIT << (bit - n->startbit)))
162				return 1;
163			else
164				return 0;
165		}
166		n = n->next;
167	}
168
169	return 0;
170}
171
172int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value)
173{
174	ebitmap_node_t *n, *prev, *new;
175	uint32_t startbit = bit & ~(MAPSIZE - 1);
176	uint32_t highbit = startbit + MAPSIZE;
177
178	if (highbit == 0) {
179		ERR(NULL, "bitmap overflow, bit 0x%x", bit);
180		return -EINVAL;
181	}
182
183	prev = 0;
184	n = e->node;
185	while (n && n->startbit <= bit) {
186		if ((n->startbit + MAPSIZE) > bit) {
187			if (value) {
188				n->map |= (MAPBIT << (bit - n->startbit));
189			} else {
190				n->map &= ~(MAPBIT << (bit - n->startbit));
191				if (!n->map) {
192					/* drop this node from the bitmap */
193
194					if (!n->next) {
195						/*
196						 * this was the highest map
197						 * within the bitmap
198						 */
199						if (prev)
200							e->highbit =
201							    prev->startbit +
202							    MAPSIZE;
203						else
204							e->highbit = 0;
205					}
206					if (prev)
207						prev->next = n->next;
208					else
209						e->node = n->next;
210
211					free(n);
212				}
213			}
214			return 0;
215		}
216		prev = n;
217		n = n->next;
218	}
219
220	if (!value)
221		return 0;
222
223	new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
224	if (!new)
225		return -ENOMEM;
226	memset(new, 0, sizeof(ebitmap_node_t));
227
228	new->startbit = startbit;
229	new->map = (MAPBIT << (bit - new->startbit));
230
231	if (!n) {
232		/* this node will be the highest map within the bitmap */
233		e->highbit = highbit;
234	}
235
236	if (prev) {
237		new->next = prev->next;
238		prev->next = new;
239	} else {
240		new->next = e->node;
241		e->node = new;
242	}
243
244	return 0;
245}
246
247void ebitmap_destroy(ebitmap_t * e)
248{
249	ebitmap_node_t *n, *temp;
250
251	if (!e)
252		return;
253
254	n = e->node;
255	while (n) {
256		temp = n;
257		n = n->next;
258		free(temp);
259	}
260
261	e->highbit = 0;
262	e->node = 0;
263	return;
264}
265
266int ebitmap_read(ebitmap_t * e, void *fp)
267{
268	int rc;
269	ebitmap_node_t *n, *l;
270	uint32_t buf[3], mapsize, count, i;
271	uint64_t map;
272
273	ebitmap_init(e);
274
275	rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
276	if (rc < 0)
277		goto bad;
278
279	mapsize = le32_to_cpu(buf[0]);
280	e->highbit = le32_to_cpu(buf[1]);
281	count = le32_to_cpu(buf[2]);
282
283	if (mapsize != MAPSIZE) {
284		printf
285		    ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n",
286		     mapsize, MAPSIZE, e->highbit);
287		goto bad;
288	}
289	if (!e->highbit) {
290		e->node = NULL;
291		goto ok;
292	}
293	if (e->highbit & (MAPSIZE - 1)) {
294		printf
295		    ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n",
296		     e->highbit, MAPSIZE);
297		goto bad;
298	}
299	l = NULL;
300	for (i = 0; i < count; i++) {
301		rc = next_entry(buf, fp, sizeof(uint32_t));
302		if (rc < 0) {
303			printf("security: ebitmap: truncated map\n");
304			goto bad;
305		}
306		n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
307		if (!n) {
308			printf("security: ebitmap: out of memory\n");
309			rc = -ENOMEM;
310			goto bad;
311		}
312		memset(n, 0, sizeof(ebitmap_node_t));
313
314		n->startbit = le32_to_cpu(buf[0]);
315
316		if (n->startbit & (MAPSIZE - 1)) {
317			printf
318			    ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n",
319			     n->startbit, MAPSIZE);
320			goto bad_free;
321		}
322		if (n->startbit > (e->highbit - MAPSIZE)) {
323			printf
324			    ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n",
325			     n->startbit, (e->highbit - MAPSIZE));
326			goto bad_free;
327		}
328		rc = next_entry(&map, fp, sizeof(uint64_t));
329		if (rc < 0) {
330			printf("security: ebitmap: truncated map\n");
331			goto bad_free;
332		}
333		n->map = le64_to_cpu(map);
334
335		if (!n->map) {
336			printf
337			    ("security: ebitmap: null map in ebitmap (startbit %d)\n",
338			     n->startbit);
339			goto bad_free;
340		}
341		if (l) {
342			if (n->startbit <= l->startbit) {
343				printf
344				    ("security: ebitmap: start bit %d comes after start bit %d\n",
345				     n->startbit, l->startbit);
346				goto bad_free;
347			}
348			l->next = n;
349		} else
350			e->node = n;
351
352		l = n;
353	}
354
355      ok:
356	rc = 0;
357      out:
358	return rc;
359      bad_free:
360	free(n);
361      bad:
362	if (!rc)
363		rc = -EINVAL;
364	ebitmap_destroy(e);
365	goto out;
366}
367
368/* FLASK */
369