2 * Implementation of the extensible bitmap type.
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
7 * Updated: Hewlett-Packard <paul.moore@hp.com>
9 * Added support to import/export the NetLabel category bitmap
11 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14 * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
15 * Applied standard bit operations to improve bitmap scanning.
18 #include <linux/kernel.h>
19 #include <linux/slab.h>
20 #include <linux/errno.h>
21 #include <net/netlabel.h>
25 int ebitmap_cmp(struct ebitmap
*e1
, struct ebitmap
*e2
)
27 struct ebitmap_node
*n1
, *n2
;
29 if (e1
->highbit
!= e2
->highbit
)
35 (n1
->startbit
== n2
->startbit
) &&
36 !memcmp(n1
->maps
, n2
->maps
, EBITMAP_SIZE
/ 8)) {
47 int ebitmap_cpy(struct ebitmap
*dst
, struct ebitmap
*src
)
49 struct ebitmap_node
*n
, *new, *prev
;
55 new = kzalloc(sizeof(*new), GFP_ATOMIC
);
60 new->startbit
= n
->startbit
;
61 memcpy(new->maps
, n
->maps
, EBITMAP_SIZE
/ 8);
71 dst
->highbit
= src
->highbit
;
75 #ifdef CONFIG_NETLABEL
77 * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap
78 * @ebmap: the ebitmap to export
79 * @catmap: the NetLabel category bitmap
82 * Export a SELinux extensibile bitmap into a NetLabel category bitmap.
83 * Returns zero on success, negative values on error.
86 int ebitmap_netlbl_export(struct ebitmap
*ebmap
,
87 struct netlbl_lsm_secattr_catmap
**catmap
)
89 struct ebitmap_node
*e_iter
= ebmap
->node
;
90 struct netlbl_lsm_secattr_catmap
*c_iter
;
91 u32 cmap_idx
, cmap_sft
;
94 /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
95 * however, it is not always compatible with an array of unsigned long
97 * In addition, you should pay attention the following implementation
98 * assumes unsigned long has a width equal with or less than 64-bit.
101 if (e_iter
== NULL
) {
106 c_iter
= netlbl_secattr_catmap_alloc(GFP_ATOMIC
);
110 c_iter
->startbit
= e_iter
->startbit
& ~(NETLBL_CATMAP_SIZE
- 1);
112 while (e_iter
!= NULL
) {
113 for (i
= 0; i
< EBITMAP_UNIT_NUMS
; i
++) {
114 unsigned int delta
, e_startbit
, c_endbit
;
116 e_startbit
= e_iter
->startbit
+ i
* EBITMAP_UNIT_SIZE
;
117 c_endbit
= c_iter
->startbit
+ NETLBL_CATMAP_SIZE
;
118 if (e_startbit
>= c_endbit
) {
120 = netlbl_secattr_catmap_alloc(GFP_ATOMIC
);
121 if (c_iter
->next
== NULL
)
122 goto netlbl_export_failure
;
123 c_iter
= c_iter
->next
;
125 = e_startbit
& ~(NETLBL_CATMAP_SIZE
- 1);
127 delta
= e_startbit
- c_iter
->startbit
;
128 cmap_idx
= delta
/ NETLBL_CATMAP_MAPSIZE
;
129 cmap_sft
= delta
% NETLBL_CATMAP_MAPSIZE
;
130 c_iter
->bitmap
[cmap_idx
]
131 |= e_iter
->maps
[cmap_idx
] << cmap_sft
;
133 e_iter
= e_iter
->next
;
138 netlbl_export_failure
:
139 netlbl_secattr_catmap_free(*catmap
);
144 * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
145 * @ebmap: the ebitmap to import
146 * @catmap: the NetLabel category bitmap
149 * Import a NetLabel category bitmap into a SELinux extensibile bitmap.
150 * Returns zero on success, negative values on error.
153 int ebitmap_netlbl_import(struct ebitmap
*ebmap
,
154 struct netlbl_lsm_secattr_catmap
*catmap
)
156 struct ebitmap_node
*e_iter
= NULL
;
157 struct ebitmap_node
*emap_prev
= NULL
;
158 struct netlbl_lsm_secattr_catmap
*c_iter
= catmap
;
159 u32 c_idx
, c_pos
, e_idx
, e_sft
;
161 /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
162 * however, it is not always compatible with an array of unsigned long
164 * In addition, you should pay attention the following implementation
165 * assumes unsigned long has a width equal with or less than 64-bit.
169 for (c_idx
= 0; c_idx
< NETLBL_CATMAP_MAPCNT
; c_idx
++) {
171 u64 map
= c_iter
->bitmap
[c_idx
];
176 c_pos
= c_iter
->startbit
177 + c_idx
* NETLBL_CATMAP_MAPSIZE
;
179 || c_pos
>= e_iter
->startbit
+ EBITMAP_SIZE
) {
180 e_iter
= kzalloc(sizeof(*e_iter
), GFP_ATOMIC
);
182 goto netlbl_import_failure
;
184 = c_pos
- (c_pos
% EBITMAP_SIZE
);
185 if (emap_prev
== NULL
)
186 ebmap
->node
= e_iter
;
188 emap_prev
->next
= e_iter
;
191 delta
= c_pos
- e_iter
->startbit
;
192 e_idx
= delta
/ EBITMAP_UNIT_SIZE
;
193 e_sft
= delta
% EBITMAP_UNIT_SIZE
;
195 e_iter
->maps
[e_idx
++] |= map
& (-1UL);
196 map
= EBITMAP_SHIFT_UNIT_SIZE(map
);
199 c_iter
= c_iter
->next
;
200 } while (c_iter
!= NULL
);
202 ebmap
->highbit
= e_iter
->startbit
+ EBITMAP_SIZE
;
204 ebitmap_destroy(ebmap
);
208 netlbl_import_failure
:
209 ebitmap_destroy(ebmap
);
212 #endif /* CONFIG_NETLABEL */
214 int ebitmap_contains(struct ebitmap
*e1
, struct ebitmap
*e2
)
216 struct ebitmap_node
*n1
, *n2
;
219 if (e1
->highbit
< e2
->highbit
)
224 while (n1
&& n2
&& (n1
->startbit
<= n2
->startbit
)) {
225 if (n1
->startbit
< n2
->startbit
) {
229 for (i
= 0; i
< EBITMAP_UNIT_NUMS
; i
++) {
230 if ((n1
->maps
[i
] & n2
->maps
[i
]) != n2
->maps
[i
])
244 int ebitmap_get_bit(struct ebitmap
*e
, unsigned long bit
)
246 struct ebitmap_node
*n
;
248 if (e
->highbit
< bit
)
252 while (n
&& (n
->startbit
<= bit
)) {
253 if ((n
->startbit
+ EBITMAP_SIZE
) > bit
)
254 return ebitmap_node_get_bit(n
, bit
);
261 int ebitmap_set_bit(struct ebitmap
*e
, unsigned long bit
, int value
)
263 struct ebitmap_node
*n
, *prev
, *new;
267 while (n
&& n
->startbit
<= bit
) {
268 if ((n
->startbit
+ EBITMAP_SIZE
) > bit
) {
270 ebitmap_node_set_bit(n
, bit
);
274 ebitmap_node_clr_bit(n
, bit
);
276 s
= find_first_bit(n
->maps
, EBITMAP_SIZE
);
277 if (s
< EBITMAP_SIZE
)
280 /* drop this node from the bitmap */
283 * this was the highest map
287 e
->highbit
= prev
->startbit
293 prev
->next
= n
->next
;
307 new = kzalloc(sizeof(*new), GFP_ATOMIC
);
311 new->startbit
= bit
- (bit
% EBITMAP_SIZE
);
312 ebitmap_node_set_bit(new, bit
);
315 /* this node will be the highest map within the bitmap */
316 e
->highbit
= new->startbit
+ EBITMAP_SIZE
;
319 new->next
= prev
->next
;
329 void ebitmap_destroy(struct ebitmap
*e
)
331 struct ebitmap_node
*n
, *temp
;
348 int ebitmap_read(struct ebitmap
*e
, void *fp
)
350 struct ebitmap_node
*n
= NULL
;
351 u32 mapunit
, count
, startbit
, index
;
358 rc
= next_entry(buf
, fp
, sizeof buf
);
362 mapunit
= le32_to_cpu(buf
[0]);
363 e
->highbit
= le32_to_cpu(buf
[1]);
364 count
= le32_to_cpu(buf
[2]);
366 if (mapunit
!= sizeof(u64
) * 8) {
367 printk(KERN_ERR
"SELinux: ebitmap: map size %u does not "
368 "match my size %Zd (high bit was %d)\n",
369 mapunit
, sizeof(u64
) * 8, e
->highbit
);
373 /* round up e->highbit */
374 e
->highbit
+= EBITMAP_SIZE
- 1;
375 e
->highbit
-= (e
->highbit
% EBITMAP_SIZE
);
382 for (i
= 0; i
< count
; i
++) {
383 rc
= next_entry(&startbit
, fp
, sizeof(u32
));
385 printk(KERN_ERR
"SELinux: ebitmap: truncated map\n");
388 startbit
= le32_to_cpu(startbit
);
390 if (startbit
& (mapunit
- 1)) {
391 printk(KERN_ERR
"SELinux: ebitmap start bit (%d) is "
392 "not a multiple of the map unit size (%u)\n",
396 if (startbit
> e
->highbit
- mapunit
) {
397 printk(KERN_ERR
"SELinux: ebitmap start bit (%d) is "
398 "beyond the end of the bitmap (%u)\n",
399 startbit
, (e
->highbit
- mapunit
));
403 if (!n
|| startbit
>= n
->startbit
+ EBITMAP_SIZE
) {
404 struct ebitmap_node
*tmp
;
405 tmp
= kzalloc(sizeof(*tmp
), GFP_KERNEL
);
408 "SELinux: ebitmap: out of memory\n");
413 tmp
->startbit
= startbit
- (startbit
% EBITMAP_SIZE
);
419 } else if (startbit
<= n
->startbit
) {
420 printk(KERN_ERR
"SELinux: ebitmap: start bit %d"
421 " comes after start bit %d\n",
422 startbit
, n
->startbit
);
426 rc
= next_entry(&map
, fp
, sizeof(u64
));
428 printk(KERN_ERR
"SELinux: ebitmap: truncated map\n");
431 map
= le64_to_cpu(map
);
433 index
= (startbit
- n
->startbit
) / EBITMAP_UNIT_SIZE
;
435 n
->maps
[index
++] = map
& (-1UL);
436 map
= EBITMAP_SHIFT_UNIT_SIZE(map
);