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