162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Implementation of the extensible bitmap type. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author : Stephen Smalley, <stephen.smalley.work@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Added support to import/export the NetLabel category bitmap 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> 1662306a36Sopenharmony_ci * Applied standard bit operations to improve bitmap scanning. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/errno.h> 2262306a36Sopenharmony_ci#include <linux/jhash.h> 2362306a36Sopenharmony_ci#include <net/netlabel.h> 2462306a36Sopenharmony_ci#include "ebitmap.h" 2562306a36Sopenharmony_ci#include "policydb.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define BITS_PER_U64 (sizeof(u64) * 8) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic struct kmem_cache *ebitmap_node_cachep __ro_after_init; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci const struct ebitmap_node *n1, *n2; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (e1->highbit != e2->highbit) 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci n1 = e1->node; 3962306a36Sopenharmony_ci n2 = e2->node; 4062306a36Sopenharmony_ci while (n1 && n2 && 4162306a36Sopenharmony_ci (n1->startbit == n2->startbit) && 4262306a36Sopenharmony_ci !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) { 4362306a36Sopenharmony_ci n1 = n1->next; 4462306a36Sopenharmony_ci n2 = n2->next; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (n1 || n2) 4862306a36Sopenharmony_ci return 0; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return 1; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciint ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct ebitmap_node *new, *prev; 5662306a36Sopenharmony_ci const struct ebitmap_node *n; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci ebitmap_init(dst); 5962306a36Sopenharmony_ci n = src->node; 6062306a36Sopenharmony_ci prev = NULL; 6162306a36Sopenharmony_ci while (n) { 6262306a36Sopenharmony_ci new = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); 6362306a36Sopenharmony_ci if (!new) { 6462306a36Sopenharmony_ci ebitmap_destroy(dst); 6562306a36Sopenharmony_ci return -ENOMEM; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci new->startbit = n->startbit; 6862306a36Sopenharmony_ci memcpy(new->maps, n->maps, EBITMAP_SIZE / 8); 6962306a36Sopenharmony_ci new->next = NULL; 7062306a36Sopenharmony_ci if (prev) 7162306a36Sopenharmony_ci prev->next = new; 7262306a36Sopenharmony_ci else 7362306a36Sopenharmony_ci dst->node = new; 7462306a36Sopenharmony_ci prev = new; 7562306a36Sopenharmony_ci n = n->next; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci dst->highbit = src->highbit; 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct ebitmap_node *n; 8562306a36Sopenharmony_ci int bit, rc; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci ebitmap_init(dst); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ebitmap_for_each_positive_bit(e1, n, bit) { 9062306a36Sopenharmony_ci if (ebitmap_get_bit(e2, bit)) { 9162306a36Sopenharmony_ci rc = ebitmap_set_bit(dst, bit, 1); 9262306a36Sopenharmony_ci if (rc < 0) 9362306a36Sopenharmony_ci return rc; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#ifdef CONFIG_NETLABEL 10162306a36Sopenharmony_ci/** 10262306a36Sopenharmony_ci * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap 10362306a36Sopenharmony_ci * @ebmap: the ebitmap to export 10462306a36Sopenharmony_ci * @catmap: the NetLabel category bitmap 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Description: 10762306a36Sopenharmony_ci * Export a SELinux extensibile bitmap into a NetLabel category bitmap. 10862306a36Sopenharmony_ci * Returns zero on success, negative values on error. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ciint ebitmap_netlbl_export(struct ebitmap *ebmap, 11262306a36Sopenharmony_ci struct netlbl_lsm_catmap **catmap) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct ebitmap_node *e_iter = ebmap->node; 11562306a36Sopenharmony_ci unsigned long e_map; 11662306a36Sopenharmony_ci u32 offset; 11762306a36Sopenharmony_ci unsigned int iter; 11862306a36Sopenharmony_ci int rc; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (e_iter == NULL) { 12162306a36Sopenharmony_ci *catmap = NULL; 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (*catmap != NULL) 12662306a36Sopenharmony_ci netlbl_catmap_free(*catmap); 12762306a36Sopenharmony_ci *catmap = NULL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci while (e_iter) { 13062306a36Sopenharmony_ci offset = e_iter->startbit; 13162306a36Sopenharmony_ci for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) { 13262306a36Sopenharmony_ci e_map = e_iter->maps[iter]; 13362306a36Sopenharmony_ci if (e_map != 0) { 13462306a36Sopenharmony_ci rc = netlbl_catmap_setlong(catmap, 13562306a36Sopenharmony_ci offset, 13662306a36Sopenharmony_ci e_map, 13762306a36Sopenharmony_ci GFP_ATOMIC); 13862306a36Sopenharmony_ci if (rc != 0) 13962306a36Sopenharmony_ci goto netlbl_export_failure; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci offset += EBITMAP_UNIT_SIZE; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci e_iter = e_iter->next; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cinetlbl_export_failure: 14962306a36Sopenharmony_ci netlbl_catmap_free(*catmap); 15062306a36Sopenharmony_ci return -ENOMEM; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/** 15462306a36Sopenharmony_ci * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap 15562306a36Sopenharmony_ci * @ebmap: the ebitmap to import 15662306a36Sopenharmony_ci * @catmap: the NetLabel category bitmap 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Description: 15962306a36Sopenharmony_ci * Import a NetLabel category bitmap into a SELinux extensibile bitmap. 16062306a36Sopenharmony_ci * Returns zero on success, negative values on error. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ciint ebitmap_netlbl_import(struct ebitmap *ebmap, 16462306a36Sopenharmony_ci struct netlbl_lsm_catmap *catmap) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci int rc; 16762306a36Sopenharmony_ci struct ebitmap_node *e_iter = NULL; 16862306a36Sopenharmony_ci struct ebitmap_node *e_prev = NULL; 16962306a36Sopenharmony_ci u32 offset = 0, idx; 17062306a36Sopenharmony_ci unsigned long bitmap; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci for (;;) { 17362306a36Sopenharmony_ci rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); 17462306a36Sopenharmony_ci if (rc < 0) 17562306a36Sopenharmony_ci goto netlbl_import_failure; 17662306a36Sopenharmony_ci if (offset == (u32)-1) 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* don't waste ebitmap space if the netlabel bitmap is empty */ 18062306a36Sopenharmony_ci if (bitmap == 0) { 18162306a36Sopenharmony_ci offset += EBITMAP_UNIT_SIZE; 18262306a36Sopenharmony_ci continue; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (e_iter == NULL || 18662306a36Sopenharmony_ci offset >= e_iter->startbit + EBITMAP_SIZE) { 18762306a36Sopenharmony_ci e_prev = e_iter; 18862306a36Sopenharmony_ci e_iter = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); 18962306a36Sopenharmony_ci if (e_iter == NULL) 19062306a36Sopenharmony_ci goto netlbl_import_failure; 19162306a36Sopenharmony_ci e_iter->startbit = offset - (offset % EBITMAP_SIZE); 19262306a36Sopenharmony_ci if (e_prev == NULL) 19362306a36Sopenharmony_ci ebmap->node = e_iter; 19462306a36Sopenharmony_ci else 19562306a36Sopenharmony_ci e_prev->next = e_iter; 19662306a36Sopenharmony_ci ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* offset will always be aligned to an unsigned long */ 20062306a36Sopenharmony_ci idx = EBITMAP_NODE_INDEX(e_iter, offset); 20162306a36Sopenharmony_ci e_iter->maps[idx] = bitmap; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* next */ 20462306a36Sopenharmony_ci offset += EBITMAP_UNIT_SIZE; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* NOTE: we should never reach this return */ 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cinetlbl_import_failure: 21162306a36Sopenharmony_ci ebitmap_destroy(ebmap); 21262306a36Sopenharmony_ci return -ENOMEM; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci#endif /* CONFIG_NETLABEL */ 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * Check to see if all the bits set in e2 are also set in e1. Optionally, 21862306a36Sopenharmony_ci * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed 21962306a36Sopenharmony_ci * last_e2bit. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ciint ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci const struct ebitmap_node *n1, *n2; 22462306a36Sopenharmony_ci int i; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (e1->highbit < e2->highbit) 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci n1 = e1->node; 23062306a36Sopenharmony_ci n2 = e2->node; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci while (n1 && n2 && (n1->startbit <= n2->startbit)) { 23362306a36Sopenharmony_ci if (n1->startbit < n2->startbit) { 23462306a36Sopenharmony_ci n1 = n1->next; 23562306a36Sopenharmony_ci continue; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; ) 23862306a36Sopenharmony_ci i--; /* Skip trailing NULL map entries */ 23962306a36Sopenharmony_ci if (last_e2bit && (i >= 0)) { 24062306a36Sopenharmony_ci u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE + 24162306a36Sopenharmony_ci __fls(n2->maps[i]); 24262306a36Sopenharmony_ci if (lastsetbit > last_e2bit) 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci while (i >= 0) { 24762306a36Sopenharmony_ci if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci i--; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci n1 = n1->next; 25362306a36Sopenharmony_ci n2 = n2->next; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (n2) 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 1; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciint ebitmap_get_bit(const struct ebitmap *e, unsigned long bit) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci const struct ebitmap_node *n; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (e->highbit < bit) 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci n = e->node; 27062306a36Sopenharmony_ci while (n && (n->startbit <= bit)) { 27162306a36Sopenharmony_ci if ((n->startbit + EBITMAP_SIZE) > bit) 27262306a36Sopenharmony_ci return ebitmap_node_get_bit(n, bit); 27362306a36Sopenharmony_ci n = n->next; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciint ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct ebitmap_node *n, *prev, *new; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci prev = NULL; 28462306a36Sopenharmony_ci n = e->node; 28562306a36Sopenharmony_ci while (n && n->startbit <= bit) { 28662306a36Sopenharmony_ci if ((n->startbit + EBITMAP_SIZE) > bit) { 28762306a36Sopenharmony_ci if (value) { 28862306a36Sopenharmony_ci ebitmap_node_set_bit(n, bit); 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci unsigned int s; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ebitmap_node_clr_bit(n, bit); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci s = find_first_bit(n->maps, EBITMAP_SIZE); 29562306a36Sopenharmony_ci if (s < EBITMAP_SIZE) 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* drop this node from the bitmap */ 29962306a36Sopenharmony_ci if (!n->next) { 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * this was the highest map 30262306a36Sopenharmony_ci * within the bitmap 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci if (prev) 30562306a36Sopenharmony_ci e->highbit = prev->startbit 30662306a36Sopenharmony_ci + EBITMAP_SIZE; 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci e->highbit = 0; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci if (prev) 31162306a36Sopenharmony_ci prev->next = n->next; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci e->node = n->next; 31462306a36Sopenharmony_ci kmem_cache_free(ebitmap_node_cachep, n); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci prev = n; 31962306a36Sopenharmony_ci n = n->next; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (!value) 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci new = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); 32662306a36Sopenharmony_ci if (!new) 32762306a36Sopenharmony_ci return -ENOMEM; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci new->startbit = bit - (bit % EBITMAP_SIZE); 33062306a36Sopenharmony_ci ebitmap_node_set_bit(new, bit); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (!n) 33362306a36Sopenharmony_ci /* this node will be the highest map within the bitmap */ 33462306a36Sopenharmony_ci e->highbit = new->startbit + EBITMAP_SIZE; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (prev) { 33762306a36Sopenharmony_ci new->next = prev->next; 33862306a36Sopenharmony_ci prev->next = new; 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci new->next = e->node; 34162306a36Sopenharmony_ci e->node = new; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_civoid ebitmap_destroy(struct ebitmap *e) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct ebitmap_node *n, *temp; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!e) 35262306a36Sopenharmony_ci return; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci n = e->node; 35562306a36Sopenharmony_ci while (n) { 35662306a36Sopenharmony_ci temp = n; 35762306a36Sopenharmony_ci n = n->next; 35862306a36Sopenharmony_ci kmem_cache_free(ebitmap_node_cachep, temp); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci e->highbit = 0; 36262306a36Sopenharmony_ci e->node = NULL; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ciint ebitmap_read(struct ebitmap *e, void *fp) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct ebitmap_node *n = NULL; 36862306a36Sopenharmony_ci u32 mapunit, count, startbit, index; 36962306a36Sopenharmony_ci __le32 ebitmap_start; 37062306a36Sopenharmony_ci u64 map; 37162306a36Sopenharmony_ci __le64 mapbits; 37262306a36Sopenharmony_ci __le32 buf[3]; 37362306a36Sopenharmony_ci int rc, i; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ebitmap_init(e); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci rc = next_entry(buf, fp, sizeof buf); 37862306a36Sopenharmony_ci if (rc < 0) 37962306a36Sopenharmony_ci goto out; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci mapunit = le32_to_cpu(buf[0]); 38262306a36Sopenharmony_ci e->highbit = le32_to_cpu(buf[1]); 38362306a36Sopenharmony_ci count = le32_to_cpu(buf[2]); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (mapunit != BITS_PER_U64) { 38662306a36Sopenharmony_ci pr_err("SELinux: ebitmap: map size %u does not " 38762306a36Sopenharmony_ci "match my size %zd (high bit was %d)\n", 38862306a36Sopenharmony_ci mapunit, BITS_PER_U64, e->highbit); 38962306a36Sopenharmony_ci goto bad; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* round up e->highbit */ 39362306a36Sopenharmony_ci e->highbit += EBITMAP_SIZE - 1; 39462306a36Sopenharmony_ci e->highbit -= (e->highbit % EBITMAP_SIZE); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!e->highbit) { 39762306a36Sopenharmony_ci e->node = NULL; 39862306a36Sopenharmony_ci goto ok; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (e->highbit && !count) 40262306a36Sopenharmony_ci goto bad; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 40562306a36Sopenharmony_ci rc = next_entry(&ebitmap_start, fp, sizeof(u32)); 40662306a36Sopenharmony_ci if (rc < 0) { 40762306a36Sopenharmony_ci pr_err("SELinux: ebitmap: truncated map\n"); 40862306a36Sopenharmony_ci goto bad; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci startbit = le32_to_cpu(ebitmap_start); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (startbit & (mapunit - 1)) { 41362306a36Sopenharmony_ci pr_err("SELinux: ebitmap start bit (%d) is " 41462306a36Sopenharmony_ci "not a multiple of the map unit size (%u)\n", 41562306a36Sopenharmony_ci startbit, mapunit); 41662306a36Sopenharmony_ci goto bad; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci if (startbit > e->highbit - mapunit) { 41962306a36Sopenharmony_ci pr_err("SELinux: ebitmap start bit (%d) is " 42062306a36Sopenharmony_ci "beyond the end of the bitmap (%u)\n", 42162306a36Sopenharmony_ci startbit, (e->highbit - mapunit)); 42262306a36Sopenharmony_ci goto bad; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (!n || startbit >= n->startbit + EBITMAP_SIZE) { 42662306a36Sopenharmony_ci struct ebitmap_node *tmp; 42762306a36Sopenharmony_ci tmp = kmem_cache_zalloc(ebitmap_node_cachep, GFP_KERNEL); 42862306a36Sopenharmony_ci if (!tmp) { 42962306a36Sopenharmony_ci pr_err("SELinux: ebitmap: out of memory\n"); 43062306a36Sopenharmony_ci rc = -ENOMEM; 43162306a36Sopenharmony_ci goto bad; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci /* round down */ 43462306a36Sopenharmony_ci tmp->startbit = startbit - (startbit % EBITMAP_SIZE); 43562306a36Sopenharmony_ci if (n) 43662306a36Sopenharmony_ci n->next = tmp; 43762306a36Sopenharmony_ci else 43862306a36Sopenharmony_ci e->node = tmp; 43962306a36Sopenharmony_ci n = tmp; 44062306a36Sopenharmony_ci } else if (startbit <= n->startbit) { 44162306a36Sopenharmony_ci pr_err("SELinux: ebitmap: start bit %d" 44262306a36Sopenharmony_ci " comes after start bit %d\n", 44362306a36Sopenharmony_ci startbit, n->startbit); 44462306a36Sopenharmony_ci goto bad; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci rc = next_entry(&mapbits, fp, sizeof(u64)); 44862306a36Sopenharmony_ci if (rc < 0) { 44962306a36Sopenharmony_ci pr_err("SELinux: ebitmap: truncated map\n"); 45062306a36Sopenharmony_ci goto bad; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci map = le64_to_cpu(mapbits); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE; 45562306a36Sopenharmony_ci while (map) { 45662306a36Sopenharmony_ci n->maps[index++] = map & (-1UL); 45762306a36Sopenharmony_ci map = EBITMAP_SHIFT_UNIT_SIZE(map); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ciok: 46162306a36Sopenharmony_ci rc = 0; 46262306a36Sopenharmony_ciout: 46362306a36Sopenharmony_ci return rc; 46462306a36Sopenharmony_cibad: 46562306a36Sopenharmony_ci if (!rc) 46662306a36Sopenharmony_ci rc = -EINVAL; 46762306a36Sopenharmony_ci ebitmap_destroy(e); 46862306a36Sopenharmony_ci goto out; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciint ebitmap_write(const struct ebitmap *e, void *fp) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct ebitmap_node *n; 47462306a36Sopenharmony_ci u32 count; 47562306a36Sopenharmony_ci __le32 buf[3]; 47662306a36Sopenharmony_ci u64 map; 47762306a36Sopenharmony_ci int bit, last_bit, last_startbit, rc; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci buf[0] = cpu_to_le32(BITS_PER_U64); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci count = 0; 48262306a36Sopenharmony_ci last_bit = 0; 48362306a36Sopenharmony_ci last_startbit = -1; 48462306a36Sopenharmony_ci ebitmap_for_each_positive_bit(e, n, bit) { 48562306a36Sopenharmony_ci if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { 48662306a36Sopenharmony_ci count++; 48762306a36Sopenharmony_ci last_startbit = rounddown(bit, BITS_PER_U64); 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci last_bit = roundup(bit + 1, BITS_PER_U64); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci buf[1] = cpu_to_le32(last_bit); 49262306a36Sopenharmony_ci buf[2] = cpu_to_le32(count); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci rc = put_entry(buf, sizeof(u32), 3, fp); 49562306a36Sopenharmony_ci if (rc) 49662306a36Sopenharmony_ci return rc; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci map = 0; 49962306a36Sopenharmony_ci last_startbit = INT_MIN; 50062306a36Sopenharmony_ci ebitmap_for_each_positive_bit(e, n, bit) { 50162306a36Sopenharmony_ci if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { 50262306a36Sopenharmony_ci __le64 buf64[1]; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* this is the very first bit */ 50562306a36Sopenharmony_ci if (!map) { 50662306a36Sopenharmony_ci last_startbit = rounddown(bit, BITS_PER_U64); 50762306a36Sopenharmony_ci map = (u64)1 << (bit - last_startbit); 50862306a36Sopenharmony_ci continue; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* write the last node */ 51262306a36Sopenharmony_ci buf[0] = cpu_to_le32(last_startbit); 51362306a36Sopenharmony_ci rc = put_entry(buf, sizeof(u32), 1, fp); 51462306a36Sopenharmony_ci if (rc) 51562306a36Sopenharmony_ci return rc; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci buf64[0] = cpu_to_le64(map); 51862306a36Sopenharmony_ci rc = put_entry(buf64, sizeof(u64), 1, fp); 51962306a36Sopenharmony_ci if (rc) 52062306a36Sopenharmony_ci return rc; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* set up for the next node */ 52362306a36Sopenharmony_ci map = 0; 52462306a36Sopenharmony_ci last_startbit = rounddown(bit, BITS_PER_U64); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci map |= (u64)1 << (bit - last_startbit); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci /* write the last node */ 52962306a36Sopenharmony_ci if (map) { 53062306a36Sopenharmony_ci __le64 buf64[1]; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* write the last node */ 53362306a36Sopenharmony_ci buf[0] = cpu_to_le32(last_startbit); 53462306a36Sopenharmony_ci rc = put_entry(buf, sizeof(u32), 1, fp); 53562306a36Sopenharmony_ci if (rc) 53662306a36Sopenharmony_ci return rc; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci buf64[0] = cpu_to_le64(map); 53962306a36Sopenharmony_ci rc = put_entry(buf64, sizeof(u64), 1, fp); 54062306a36Sopenharmony_ci if (rc) 54162306a36Sopenharmony_ci return rc; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciu32 ebitmap_hash(const struct ebitmap *e, u32 hash) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct ebitmap_node *node; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* need to change hash even if ebitmap is empty */ 55162306a36Sopenharmony_ci hash = jhash_1word(e->highbit, hash); 55262306a36Sopenharmony_ci for (node = e->node; node; node = node->next) { 55362306a36Sopenharmony_ci hash = jhash_1word(node->startbit, hash); 55462306a36Sopenharmony_ci hash = jhash(node->maps, sizeof(node->maps), hash); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci return hash; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_civoid __init ebitmap_cache_init(void) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci ebitmap_node_cachep = kmem_cache_create("ebitmap_node", 56262306a36Sopenharmony_ci sizeof(struct ebitmap_node), 56362306a36Sopenharmony_ci 0, SLAB_PANIC, NULL); 56462306a36Sopenharmony_ci} 565