18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Implementation of the extensible bitmap type.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author : Stephen Smalley, <sds@tycho.nsa.gov>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *      Added support to import/export the NetLabel category bitmap
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
168c2ecf20Sopenharmony_ci *      Applied standard bit operations to improve bitmap scanning.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/errno.h>
228c2ecf20Sopenharmony_ci#include <linux/jhash.h>
238c2ecf20Sopenharmony_ci#include <net/netlabel.h>
248c2ecf20Sopenharmony_ci#include "ebitmap.h"
258c2ecf20Sopenharmony_ci#include "policydb.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define BITS_PER_U64	(sizeof(u64) * 8)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic struct kmem_cache *ebitmap_node_cachep;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciint ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct ebitmap_node *n1, *n2;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (e1->highbit != e2->highbit)
368c2ecf20Sopenharmony_ci		return 0;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	n1 = e1->node;
398c2ecf20Sopenharmony_ci	n2 = e2->node;
408c2ecf20Sopenharmony_ci	while (n1 && n2 &&
418c2ecf20Sopenharmony_ci	       (n1->startbit == n2->startbit) &&
428c2ecf20Sopenharmony_ci	       !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
438c2ecf20Sopenharmony_ci		n1 = n1->next;
448c2ecf20Sopenharmony_ci		n2 = n2->next;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (n1 || n2)
488c2ecf20Sopenharmony_ci		return 0;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	return 1;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciint ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct ebitmap_node *n, *new, *prev;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	ebitmap_init(dst);
588c2ecf20Sopenharmony_ci	n = src->node;
598c2ecf20Sopenharmony_ci	prev = NULL;
608c2ecf20Sopenharmony_ci	while (n) {
618c2ecf20Sopenharmony_ci		new = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC);
628c2ecf20Sopenharmony_ci		if (!new) {
638c2ecf20Sopenharmony_ci			ebitmap_destroy(dst);
648c2ecf20Sopenharmony_ci			return -ENOMEM;
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci		new->startbit = n->startbit;
678c2ecf20Sopenharmony_ci		memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
688c2ecf20Sopenharmony_ci		new->next = NULL;
698c2ecf20Sopenharmony_ci		if (prev)
708c2ecf20Sopenharmony_ci			prev->next = new;
718c2ecf20Sopenharmony_ci		else
728c2ecf20Sopenharmony_ci			dst->node = new;
738c2ecf20Sopenharmony_ci		prev = new;
748c2ecf20Sopenharmony_ci		n = n->next;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	dst->highbit = src->highbit;
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint ebitmap_and(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct ebitmap_node *n;
848c2ecf20Sopenharmony_ci	int bit, rc;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	ebitmap_init(dst);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	ebitmap_for_each_positive_bit(e1, n, bit) {
898c2ecf20Sopenharmony_ci		if (ebitmap_get_bit(e2, bit)) {
908c2ecf20Sopenharmony_ci			rc = ebitmap_set_bit(dst, bit, 1);
918c2ecf20Sopenharmony_ci			if (rc < 0)
928c2ecf20Sopenharmony_ci				return rc;
938c2ecf20Sopenharmony_ci		}
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#ifdef CONFIG_NETLABEL
1008c2ecf20Sopenharmony_ci/**
1018c2ecf20Sopenharmony_ci * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap
1028c2ecf20Sopenharmony_ci * @ebmap: the ebitmap to export
1038c2ecf20Sopenharmony_ci * @catmap: the NetLabel category bitmap
1048c2ecf20Sopenharmony_ci *
1058c2ecf20Sopenharmony_ci * Description:
1068c2ecf20Sopenharmony_ci * Export a SELinux extensibile bitmap into a NetLabel category bitmap.
1078c2ecf20Sopenharmony_ci * Returns zero on success, negative values on error.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_ciint ebitmap_netlbl_export(struct ebitmap *ebmap,
1118c2ecf20Sopenharmony_ci			  struct netlbl_lsm_catmap **catmap)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct ebitmap_node *e_iter = ebmap->node;
1148c2ecf20Sopenharmony_ci	unsigned long e_map;
1158c2ecf20Sopenharmony_ci	u32 offset;
1168c2ecf20Sopenharmony_ci	unsigned int iter;
1178c2ecf20Sopenharmony_ci	int rc;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (e_iter == NULL) {
1208c2ecf20Sopenharmony_ci		*catmap = NULL;
1218c2ecf20Sopenharmony_ci		return 0;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (*catmap != NULL)
1258c2ecf20Sopenharmony_ci		netlbl_catmap_free(*catmap);
1268c2ecf20Sopenharmony_ci	*catmap = NULL;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	while (e_iter) {
1298c2ecf20Sopenharmony_ci		offset = e_iter->startbit;
1308c2ecf20Sopenharmony_ci		for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) {
1318c2ecf20Sopenharmony_ci			e_map = e_iter->maps[iter];
1328c2ecf20Sopenharmony_ci			if (e_map != 0) {
1338c2ecf20Sopenharmony_ci				rc = netlbl_catmap_setlong(catmap,
1348c2ecf20Sopenharmony_ci							   offset,
1358c2ecf20Sopenharmony_ci							   e_map,
1368c2ecf20Sopenharmony_ci							   GFP_ATOMIC);
1378c2ecf20Sopenharmony_ci				if (rc != 0)
1388c2ecf20Sopenharmony_ci					goto netlbl_export_failure;
1398c2ecf20Sopenharmony_ci			}
1408c2ecf20Sopenharmony_ci			offset += EBITMAP_UNIT_SIZE;
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci		e_iter = e_iter->next;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return 0;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cinetlbl_export_failure:
1488c2ecf20Sopenharmony_ci	netlbl_catmap_free(*catmap);
1498c2ecf20Sopenharmony_ci	return -ENOMEM;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/**
1538c2ecf20Sopenharmony_ci * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
1548c2ecf20Sopenharmony_ci * @ebmap: the ebitmap to import
1558c2ecf20Sopenharmony_ci * @catmap: the NetLabel category bitmap
1568c2ecf20Sopenharmony_ci *
1578c2ecf20Sopenharmony_ci * Description:
1588c2ecf20Sopenharmony_ci * Import a NetLabel category bitmap into a SELinux extensibile bitmap.
1598c2ecf20Sopenharmony_ci * Returns zero on success, negative values on error.
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_ciint ebitmap_netlbl_import(struct ebitmap *ebmap,
1638c2ecf20Sopenharmony_ci			  struct netlbl_lsm_catmap *catmap)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	int rc;
1668c2ecf20Sopenharmony_ci	struct ebitmap_node *e_iter = NULL;
1678c2ecf20Sopenharmony_ci	struct ebitmap_node *e_prev = NULL;
1688c2ecf20Sopenharmony_ci	u32 offset = 0, idx;
1698c2ecf20Sopenharmony_ci	unsigned long bitmap;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	for (;;) {
1728c2ecf20Sopenharmony_ci		rc = netlbl_catmap_getlong(catmap, &offset, &bitmap);
1738c2ecf20Sopenharmony_ci		if (rc < 0)
1748c2ecf20Sopenharmony_ci			goto netlbl_import_failure;
1758c2ecf20Sopenharmony_ci		if (offset == (u32)-1)
1768c2ecf20Sopenharmony_ci			return 0;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		/* don't waste ebitmap space if the netlabel bitmap is empty */
1798c2ecf20Sopenharmony_ci		if (bitmap == 0) {
1808c2ecf20Sopenharmony_ci			offset += EBITMAP_UNIT_SIZE;
1818c2ecf20Sopenharmony_ci			continue;
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		if (e_iter == NULL ||
1858c2ecf20Sopenharmony_ci		    offset >= e_iter->startbit + EBITMAP_SIZE) {
1868c2ecf20Sopenharmony_ci			e_prev = e_iter;
1878c2ecf20Sopenharmony_ci			e_iter = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC);
1888c2ecf20Sopenharmony_ci			if (e_iter == NULL)
1898c2ecf20Sopenharmony_ci				goto netlbl_import_failure;
1908c2ecf20Sopenharmony_ci			e_iter->startbit = offset - (offset % EBITMAP_SIZE);
1918c2ecf20Sopenharmony_ci			if (e_prev == NULL)
1928c2ecf20Sopenharmony_ci				ebmap->node = e_iter;
1938c2ecf20Sopenharmony_ci			else
1948c2ecf20Sopenharmony_ci				e_prev->next = e_iter;
1958c2ecf20Sopenharmony_ci			ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
1968c2ecf20Sopenharmony_ci		}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		/* offset will always be aligned to an unsigned long */
1998c2ecf20Sopenharmony_ci		idx = EBITMAP_NODE_INDEX(e_iter, offset);
2008c2ecf20Sopenharmony_ci		e_iter->maps[idx] = bitmap;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		/* next */
2038c2ecf20Sopenharmony_ci		offset += EBITMAP_UNIT_SIZE;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* NOTE: we should never reach this return */
2078c2ecf20Sopenharmony_ci	return 0;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cinetlbl_import_failure:
2108c2ecf20Sopenharmony_ci	ebitmap_destroy(ebmap);
2118c2ecf20Sopenharmony_ci	return -ENOMEM;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci#endif /* CONFIG_NETLABEL */
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/*
2168c2ecf20Sopenharmony_ci * Check to see if all the bits set in e2 are also set in e1. Optionally,
2178c2ecf20Sopenharmony_ci * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed
2188c2ecf20Sopenharmony_ci * last_e2bit.
2198c2ecf20Sopenharmony_ci */
2208c2ecf20Sopenharmony_ciint ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct ebitmap_node *n1, *n2;
2238c2ecf20Sopenharmony_ci	int i;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (e1->highbit < e2->highbit)
2268c2ecf20Sopenharmony_ci		return 0;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	n1 = e1->node;
2298c2ecf20Sopenharmony_ci	n2 = e2->node;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	while (n1 && n2 && (n1->startbit <= n2->startbit)) {
2328c2ecf20Sopenharmony_ci		if (n1->startbit < n2->startbit) {
2338c2ecf20Sopenharmony_ci			n1 = n1->next;
2348c2ecf20Sopenharmony_ci			continue;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci		for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; )
2378c2ecf20Sopenharmony_ci			i--;	/* Skip trailing NULL map entries */
2388c2ecf20Sopenharmony_ci		if (last_e2bit && (i >= 0)) {
2398c2ecf20Sopenharmony_ci			u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE +
2408c2ecf20Sopenharmony_ci					 __fls(n2->maps[i]);
2418c2ecf20Sopenharmony_ci			if (lastsetbit > last_e2bit)
2428c2ecf20Sopenharmony_ci				return 0;
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		while (i >= 0) {
2468c2ecf20Sopenharmony_ci			if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
2478c2ecf20Sopenharmony_ci				return 0;
2488c2ecf20Sopenharmony_ci			i--;
2498c2ecf20Sopenharmony_ci		}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		n1 = n1->next;
2528c2ecf20Sopenharmony_ci		n2 = n2->next;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (n2)
2568c2ecf20Sopenharmony_ci		return 0;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return 1;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciint ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct ebitmap_node *n;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (e->highbit < bit)
2668c2ecf20Sopenharmony_ci		return 0;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	n = e->node;
2698c2ecf20Sopenharmony_ci	while (n && (n->startbit <= bit)) {
2708c2ecf20Sopenharmony_ci		if ((n->startbit + EBITMAP_SIZE) > bit)
2718c2ecf20Sopenharmony_ci			return ebitmap_node_get_bit(n, bit);
2728c2ecf20Sopenharmony_ci		n = n->next;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	return 0;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ciint ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct ebitmap_node *n, *prev, *new;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	prev = NULL;
2838c2ecf20Sopenharmony_ci	n = e->node;
2848c2ecf20Sopenharmony_ci	while (n && n->startbit <= bit) {
2858c2ecf20Sopenharmony_ci		if ((n->startbit + EBITMAP_SIZE) > bit) {
2868c2ecf20Sopenharmony_ci			if (value) {
2878c2ecf20Sopenharmony_ci				ebitmap_node_set_bit(n, bit);
2888c2ecf20Sopenharmony_ci			} else {
2898c2ecf20Sopenharmony_ci				unsigned int s;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci				ebitmap_node_clr_bit(n, bit);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci				s = find_first_bit(n->maps, EBITMAP_SIZE);
2948c2ecf20Sopenharmony_ci				if (s < EBITMAP_SIZE)
2958c2ecf20Sopenharmony_ci					return 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci				/* drop this node from the bitmap */
2988c2ecf20Sopenharmony_ci				if (!n->next) {
2998c2ecf20Sopenharmony_ci					/*
3008c2ecf20Sopenharmony_ci					 * this was the highest map
3018c2ecf20Sopenharmony_ci					 * within the bitmap
3028c2ecf20Sopenharmony_ci					 */
3038c2ecf20Sopenharmony_ci					if (prev)
3048c2ecf20Sopenharmony_ci						e->highbit = prev->startbit
3058c2ecf20Sopenharmony_ci							     + EBITMAP_SIZE;
3068c2ecf20Sopenharmony_ci					else
3078c2ecf20Sopenharmony_ci						e->highbit = 0;
3088c2ecf20Sopenharmony_ci				}
3098c2ecf20Sopenharmony_ci				if (prev)
3108c2ecf20Sopenharmony_ci					prev->next = n->next;
3118c2ecf20Sopenharmony_ci				else
3128c2ecf20Sopenharmony_ci					e->node = n->next;
3138c2ecf20Sopenharmony_ci				kmem_cache_free(ebitmap_node_cachep, n);
3148c2ecf20Sopenharmony_ci			}
3158c2ecf20Sopenharmony_ci			return 0;
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci		prev = n;
3188c2ecf20Sopenharmony_ci		n = n->next;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (!value)
3228c2ecf20Sopenharmony_ci		return 0;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	new = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC);
3258c2ecf20Sopenharmony_ci	if (!new)
3268c2ecf20Sopenharmony_ci		return -ENOMEM;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	new->startbit = bit - (bit % EBITMAP_SIZE);
3298c2ecf20Sopenharmony_ci	ebitmap_node_set_bit(new, bit);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (!n)
3328c2ecf20Sopenharmony_ci		/* this node will be the highest map within the bitmap */
3338c2ecf20Sopenharmony_ci		e->highbit = new->startbit + EBITMAP_SIZE;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (prev) {
3368c2ecf20Sopenharmony_ci		new->next = prev->next;
3378c2ecf20Sopenharmony_ci		prev->next = new;
3388c2ecf20Sopenharmony_ci	} else {
3398c2ecf20Sopenharmony_ci		new->next = e->node;
3408c2ecf20Sopenharmony_ci		e->node = new;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return 0;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_civoid ebitmap_destroy(struct ebitmap *e)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct ebitmap_node *n, *temp;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (!e)
3518c2ecf20Sopenharmony_ci		return;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	n = e->node;
3548c2ecf20Sopenharmony_ci	while (n) {
3558c2ecf20Sopenharmony_ci		temp = n;
3568c2ecf20Sopenharmony_ci		n = n->next;
3578c2ecf20Sopenharmony_ci		kmem_cache_free(ebitmap_node_cachep, temp);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	e->highbit = 0;
3618c2ecf20Sopenharmony_ci	e->node = NULL;
3628c2ecf20Sopenharmony_ci	return;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ciint ebitmap_read(struct ebitmap *e, void *fp)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct ebitmap_node *n = NULL;
3688c2ecf20Sopenharmony_ci	u32 mapunit, count, startbit, index;
3698c2ecf20Sopenharmony_ci	__le32 ebitmap_start;
3708c2ecf20Sopenharmony_ci	u64 map;
3718c2ecf20Sopenharmony_ci	__le64 mapbits;
3728c2ecf20Sopenharmony_ci	__le32 buf[3];
3738c2ecf20Sopenharmony_ci	int rc, i;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ebitmap_init(e);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
3788c2ecf20Sopenharmony_ci	if (rc < 0)
3798c2ecf20Sopenharmony_ci		goto out;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	mapunit = le32_to_cpu(buf[0]);
3828c2ecf20Sopenharmony_ci	e->highbit = le32_to_cpu(buf[1]);
3838c2ecf20Sopenharmony_ci	count = le32_to_cpu(buf[2]);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (mapunit != BITS_PER_U64) {
3868c2ecf20Sopenharmony_ci		pr_err("SELinux: ebitmap: map size %u does not "
3878c2ecf20Sopenharmony_ci		       "match my size %zd (high bit was %d)\n",
3888c2ecf20Sopenharmony_ci		       mapunit, BITS_PER_U64, e->highbit);
3898c2ecf20Sopenharmony_ci		goto bad;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/* round up e->highbit */
3938c2ecf20Sopenharmony_ci	e->highbit += EBITMAP_SIZE - 1;
3948c2ecf20Sopenharmony_ci	e->highbit -= (e->highbit % EBITMAP_SIZE);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (!e->highbit) {
3978c2ecf20Sopenharmony_ci		e->node = NULL;
3988c2ecf20Sopenharmony_ci		goto ok;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (e->highbit && !count)
4028c2ecf20Sopenharmony_ci		goto bad;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
4058c2ecf20Sopenharmony_ci		rc = next_entry(&ebitmap_start, fp, sizeof(u32));
4068c2ecf20Sopenharmony_ci		if (rc < 0) {
4078c2ecf20Sopenharmony_ci			pr_err("SELinux: ebitmap: truncated map\n");
4088c2ecf20Sopenharmony_ci			goto bad;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci		startbit = le32_to_cpu(ebitmap_start);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		if (startbit & (mapunit - 1)) {
4138c2ecf20Sopenharmony_ci			pr_err("SELinux: ebitmap start bit (%d) is "
4148c2ecf20Sopenharmony_ci			       "not a multiple of the map unit size (%u)\n",
4158c2ecf20Sopenharmony_ci			       startbit, mapunit);
4168c2ecf20Sopenharmony_ci			goto bad;
4178c2ecf20Sopenharmony_ci		}
4188c2ecf20Sopenharmony_ci		if (startbit > e->highbit - mapunit) {
4198c2ecf20Sopenharmony_ci			pr_err("SELinux: ebitmap start bit (%d) is "
4208c2ecf20Sopenharmony_ci			       "beyond the end of the bitmap (%u)\n",
4218c2ecf20Sopenharmony_ci			       startbit, (e->highbit - mapunit));
4228c2ecf20Sopenharmony_ci			goto bad;
4238c2ecf20Sopenharmony_ci		}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
4268c2ecf20Sopenharmony_ci			struct ebitmap_node *tmp;
4278c2ecf20Sopenharmony_ci			tmp = kmem_cache_zalloc(ebitmap_node_cachep, GFP_KERNEL);
4288c2ecf20Sopenharmony_ci			if (!tmp) {
4298c2ecf20Sopenharmony_ci				pr_err("SELinux: ebitmap: out of memory\n");
4308c2ecf20Sopenharmony_ci				rc = -ENOMEM;
4318c2ecf20Sopenharmony_ci				goto bad;
4328c2ecf20Sopenharmony_ci			}
4338c2ecf20Sopenharmony_ci			/* round down */
4348c2ecf20Sopenharmony_ci			tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
4358c2ecf20Sopenharmony_ci			if (n)
4368c2ecf20Sopenharmony_ci				n->next = tmp;
4378c2ecf20Sopenharmony_ci			else
4388c2ecf20Sopenharmony_ci				e->node = tmp;
4398c2ecf20Sopenharmony_ci			n = tmp;
4408c2ecf20Sopenharmony_ci		} else if (startbit <= n->startbit) {
4418c2ecf20Sopenharmony_ci			pr_err("SELinux: ebitmap: start bit %d"
4428c2ecf20Sopenharmony_ci			       " comes after start bit %d\n",
4438c2ecf20Sopenharmony_ci			       startbit, n->startbit);
4448c2ecf20Sopenharmony_ci			goto bad;
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		rc = next_entry(&mapbits, fp, sizeof(u64));
4488c2ecf20Sopenharmony_ci		if (rc < 0) {
4498c2ecf20Sopenharmony_ci			pr_err("SELinux: ebitmap: truncated map\n");
4508c2ecf20Sopenharmony_ci			goto bad;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		map = le64_to_cpu(mapbits);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
4558c2ecf20Sopenharmony_ci		while (map) {
4568c2ecf20Sopenharmony_ci			n->maps[index++] = map & (-1UL);
4578c2ecf20Sopenharmony_ci			map = EBITMAP_SHIFT_UNIT_SIZE(map);
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ciok:
4618c2ecf20Sopenharmony_ci	rc = 0;
4628c2ecf20Sopenharmony_ciout:
4638c2ecf20Sopenharmony_ci	return rc;
4648c2ecf20Sopenharmony_cibad:
4658c2ecf20Sopenharmony_ci	if (!rc)
4668c2ecf20Sopenharmony_ci		rc = -EINVAL;
4678c2ecf20Sopenharmony_ci	ebitmap_destroy(e);
4688c2ecf20Sopenharmony_ci	goto out;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ciint ebitmap_write(struct ebitmap *e, void *fp)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct ebitmap_node *n;
4748c2ecf20Sopenharmony_ci	u32 count;
4758c2ecf20Sopenharmony_ci	__le32 buf[3];
4768c2ecf20Sopenharmony_ci	u64 map;
4778c2ecf20Sopenharmony_ci	int bit, last_bit, last_startbit, rc;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	buf[0] = cpu_to_le32(BITS_PER_U64);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	count = 0;
4828c2ecf20Sopenharmony_ci	last_bit = 0;
4838c2ecf20Sopenharmony_ci	last_startbit = -1;
4848c2ecf20Sopenharmony_ci	ebitmap_for_each_positive_bit(e, n, bit) {
4858c2ecf20Sopenharmony_ci		if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
4868c2ecf20Sopenharmony_ci			count++;
4878c2ecf20Sopenharmony_ci			last_startbit = rounddown(bit, BITS_PER_U64);
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci		last_bit = roundup(bit + 1, BITS_PER_U64);
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci	buf[1] = cpu_to_le32(last_bit);
4928c2ecf20Sopenharmony_ci	buf[2] = cpu_to_le32(count);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 3, fp);
4958c2ecf20Sopenharmony_ci	if (rc)
4968c2ecf20Sopenharmony_ci		return rc;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	map = 0;
4998c2ecf20Sopenharmony_ci	last_startbit = INT_MIN;
5008c2ecf20Sopenharmony_ci	ebitmap_for_each_positive_bit(e, n, bit) {
5018c2ecf20Sopenharmony_ci		if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
5028c2ecf20Sopenharmony_ci			__le64 buf64[1];
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci			/* this is the very first bit */
5058c2ecf20Sopenharmony_ci			if (!map) {
5068c2ecf20Sopenharmony_ci				last_startbit = rounddown(bit, BITS_PER_U64);
5078c2ecf20Sopenharmony_ci				map = (u64)1 << (bit - last_startbit);
5088c2ecf20Sopenharmony_ci				continue;
5098c2ecf20Sopenharmony_ci			}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci			/* write the last node */
5128c2ecf20Sopenharmony_ci			buf[0] = cpu_to_le32(last_startbit);
5138c2ecf20Sopenharmony_ci			rc = put_entry(buf, sizeof(u32), 1, fp);
5148c2ecf20Sopenharmony_ci			if (rc)
5158c2ecf20Sopenharmony_ci				return rc;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci			buf64[0] = cpu_to_le64(map);
5188c2ecf20Sopenharmony_ci			rc = put_entry(buf64, sizeof(u64), 1, fp);
5198c2ecf20Sopenharmony_ci			if (rc)
5208c2ecf20Sopenharmony_ci				return rc;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci			/* set up for the next node */
5238c2ecf20Sopenharmony_ci			map = 0;
5248c2ecf20Sopenharmony_ci			last_startbit = rounddown(bit, BITS_PER_U64);
5258c2ecf20Sopenharmony_ci		}
5268c2ecf20Sopenharmony_ci		map |= (u64)1 << (bit - last_startbit);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci	/* write the last node */
5298c2ecf20Sopenharmony_ci	if (map) {
5308c2ecf20Sopenharmony_ci		__le64 buf64[1];
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci		/* write the last node */
5338c2ecf20Sopenharmony_ci		buf[0] = cpu_to_le32(last_startbit);
5348c2ecf20Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
5358c2ecf20Sopenharmony_ci		if (rc)
5368c2ecf20Sopenharmony_ci			return rc;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		buf64[0] = cpu_to_le64(map);
5398c2ecf20Sopenharmony_ci		rc = put_entry(buf64, sizeof(u64), 1, fp);
5408c2ecf20Sopenharmony_ci		if (rc)
5418c2ecf20Sopenharmony_ci			return rc;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci	return 0;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ciu32 ebitmap_hash(const struct ebitmap *e, u32 hash)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct ebitmap_node *node;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* need to change hash even if ebitmap is empty */
5518c2ecf20Sopenharmony_ci	hash = jhash_1word(e->highbit, hash);
5528c2ecf20Sopenharmony_ci	for (node = e->node; node; node = node->next) {
5538c2ecf20Sopenharmony_ci		hash = jhash_1word(node->startbit, hash);
5548c2ecf20Sopenharmony_ci		hash = jhash(node->maps, sizeof(node->maps), hash);
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci	return hash;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_civoid __init ebitmap_cache_init(void)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	ebitmap_node_cachep = kmem_cache_create("ebitmap_node",
5628c2ecf20Sopenharmony_ci							sizeof(struct ebitmap_node),
5638c2ecf20Sopenharmony_ci							0, SLAB_PANIC, NULL);
5648c2ecf20Sopenharmony_ci}
565