netlabel_domainhash.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. /*
  2. * NetLabel Domain Hash Table
  3. *
  4. * This file manages the domain hash table that NetLabel uses to determine
  5. * which network labeling protocol to use for a given domain. The NetLabel
  6. * system manages static and dynamic label mappings for network protocols such
  7. * as CIPSO and RIPSO.
  8. *
  9. * Author: Paul Moore <paul@paul-moore.com>
  10. *
  11. */
  12. /*
  13. * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  14. *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 2 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  23. * the GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  27. *
  28. */
  29. #include <linux/types.h>
  30. #include <linux/rculist.h>
  31. #include <linux/skbuff.h>
  32. #include <linux/spinlock.h>
  33. #include <linux/string.h>
  34. #include <linux/audit.h>
  35. #include <linux/slab.h>
  36. #include <net/netlabel.h>
  37. #include <net/cipso_ipv4.h>
  38. #include <net/calipso.h>
  39. #include <asm/bug.h>
  40. #include "netlabel_mgmt.h"
  41. #include "netlabel_addrlist.h"
  42. #include "netlabel_calipso.h"
  43. #include "netlabel_domainhash.h"
  44. #include "netlabel_user.h"
  45. struct netlbl_domhsh_tbl {
  46. struct list_head *tbl;
  47. u32 size;
  48. };
  49. /* Domain hash table */
  50. /* updates should be so rare that having one spinlock for the entire hash table
  51. * should be okay */
  52. static DEFINE_SPINLOCK(netlbl_domhsh_lock);
  53. #define netlbl_domhsh_rcu_deref(p) \
  54. rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
  55. static struct netlbl_domhsh_tbl __rcu *netlbl_domhsh;
  56. static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv4;
  57. static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv6;
  58. /*
  59. * Domain Hash Table Helper Functions
  60. */
  61. /**
  62. * netlbl_domhsh_free_entry - Frees a domain hash table entry
  63. * @entry: the entry's RCU field
  64. *
  65. * Description:
  66. * This function is designed to be used as a callback to the call_rcu()
  67. * function so that the memory allocated to a hash table entry can be released
  68. * safely.
  69. *
  70. */
  71. static void netlbl_domhsh_free_entry(struct rcu_head *entry)
  72. {
  73. struct netlbl_dom_map *ptr;
  74. struct netlbl_af4list *iter4;
  75. struct netlbl_af4list *tmp4;
  76. #if IS_ENABLED(CONFIG_IPV6)
  77. struct netlbl_af6list *iter6;
  78. struct netlbl_af6list *tmp6;
  79. #endif /* IPv6 */
  80. ptr = container_of(entry, struct netlbl_dom_map, rcu);
  81. if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) {
  82. netlbl_af4list_foreach_safe(iter4, tmp4,
  83. &ptr->def.addrsel->list4) {
  84. netlbl_af4list_remove_entry(iter4);
  85. kfree(netlbl_domhsh_addr4_entry(iter4));
  86. }
  87. #if IS_ENABLED(CONFIG_IPV6)
  88. netlbl_af6list_foreach_safe(iter6, tmp6,
  89. &ptr->def.addrsel->list6) {
  90. netlbl_af6list_remove_entry(iter6);
  91. kfree(netlbl_domhsh_addr6_entry(iter6));
  92. }
  93. #endif /* IPv6 */
  94. }
  95. kfree(ptr->domain);
  96. kfree(ptr);
  97. }
  98. /**
  99. * netlbl_domhsh_hash - Hashing function for the domain hash table
  100. * @domain: the domain name to hash
  101. *
  102. * Description:
  103. * This is the hashing function for the domain hash table, it returns the
  104. * correct bucket number for the domain. The caller is responsible for
  105. * ensuring that the hash table is protected with either a RCU read lock or the
  106. * hash table lock.
  107. *
  108. */
  109. static u32 netlbl_domhsh_hash(const char *key)
  110. {
  111. u32 iter;
  112. u32 val;
  113. u32 len;
  114. /* This is taken (with slight modification) from
  115. * security/selinux/ss/symtab.c:symhash() */
  116. for (iter = 0, val = 0, len = strlen(key); iter < len; iter++)
  117. val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter];
  118. return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
  119. }
  120. static bool netlbl_family_match(u16 f1, u16 f2)
  121. {
  122. return (f1 == f2) || (f1 == AF_UNSPEC) || (f2 == AF_UNSPEC);
  123. }
  124. /**
  125. * netlbl_domhsh_search - Search for a domain entry
  126. * @domain: the domain
  127. * @family: the address family
  128. *
  129. * Description:
  130. * Searches the domain hash table and returns a pointer to the hash table
  131. * entry if found, otherwise NULL is returned. @family may be %AF_UNSPEC
  132. * which matches any address family entries. The caller is responsible for
  133. * ensuring that the hash table is protected with either a RCU read lock or the
  134. * hash table lock.
  135. *
  136. */
  137. static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain,
  138. u16 family)
  139. {
  140. u32 bkt;
  141. struct list_head *bkt_list;
  142. struct netlbl_dom_map *iter;
  143. if (domain != NULL) {
  144. bkt = netlbl_domhsh_hash(domain);
  145. bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
  146. list_for_each_entry_rcu(iter, bkt_list, list)
  147. if (iter->valid &&
  148. netlbl_family_match(iter->family, family) &&
  149. strcmp(iter->domain, domain) == 0)
  150. return iter;
  151. }
  152. return NULL;
  153. }
  154. /**
  155. * netlbl_domhsh_search_def - Search for a domain entry
  156. * @domain: the domain
  157. * @family: the address family
  158. *
  159. * Description:
  160. * Searches the domain hash table and returns a pointer to the hash table
  161. * entry if an exact match is found, if an exact match is not present in the
  162. * hash table then the default entry is returned if valid otherwise NULL is
  163. * returned. @family may be %AF_UNSPEC which matches any address family
  164. * entries. The caller is responsible ensuring that the hash table is
  165. * protected with either a RCU read lock or the hash table lock.
  166. *
  167. */
  168. static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain,
  169. u16 family)
  170. {
  171. struct netlbl_dom_map *entry;
  172. entry = netlbl_domhsh_search(domain, family);
  173. if (entry != NULL)
  174. return entry;
  175. if (family == AF_INET || family == AF_UNSPEC) {
  176. entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv4);
  177. if (entry != NULL && entry->valid)
  178. return entry;
  179. }
  180. if (family == AF_INET6 || family == AF_UNSPEC) {
  181. entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv6);
  182. if (entry != NULL && entry->valid)
  183. return entry;
  184. }
  185. return NULL;
  186. }
  187. /**
  188. * netlbl_domhsh_audit_add - Generate an audit entry for an add event
  189. * @entry: the entry being added
  190. * @addr4: the IPv4 address information
  191. * @addr6: the IPv6 address information
  192. * @result: the result code
  193. * @audit_info: NetLabel audit information
  194. *
  195. * Description:
  196. * Generate an audit record for adding a new NetLabel/LSM mapping entry with
  197. * the given information. Caller is responsible for holding the necessary
  198. * locks.
  199. *
  200. */
  201. static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
  202. struct netlbl_af4list *addr4,
  203. struct netlbl_af6list *addr6,
  204. int result,
  205. struct netlbl_audit *audit_info)
  206. {
  207. struct audit_buffer *audit_buf;
  208. struct cipso_v4_doi *cipsov4 = NULL;
  209. struct calipso_doi *calipso = NULL;
  210. u32 type;
  211. audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
  212. if (audit_buf != NULL) {
  213. audit_log_format(audit_buf, " nlbl_domain=%s",
  214. entry->domain ? entry->domain : "(default)");
  215. if (addr4 != NULL) {
  216. struct netlbl_domaddr4_map *map4;
  217. map4 = netlbl_domhsh_addr4_entry(addr4);
  218. type = map4->def.type;
  219. cipsov4 = map4->def.cipso;
  220. netlbl_af4list_audit_addr(audit_buf, 0, NULL,
  221. addr4->addr, addr4->mask);
  222. #if IS_ENABLED(CONFIG_IPV6)
  223. } else if (addr6 != NULL) {
  224. struct netlbl_domaddr6_map *map6;
  225. map6 = netlbl_domhsh_addr6_entry(addr6);
  226. type = map6->def.type;
  227. calipso = map6->def.calipso;
  228. netlbl_af6list_audit_addr(audit_buf, 0, NULL,
  229. &addr6->addr, &addr6->mask);
  230. #endif /* IPv6 */
  231. } else {
  232. type = entry->def.type;
  233. cipsov4 = entry->def.cipso;
  234. calipso = entry->def.calipso;
  235. }
  236. switch (type) {
  237. case NETLBL_NLTYPE_UNLABELED:
  238. audit_log_format(audit_buf, " nlbl_protocol=unlbl");
  239. break;
  240. case NETLBL_NLTYPE_CIPSOV4:
  241. BUG_ON(cipsov4 == NULL);
  242. audit_log_format(audit_buf,
  243. " nlbl_protocol=cipsov4 cipso_doi=%u",
  244. cipsov4->doi);
  245. break;
  246. case NETLBL_NLTYPE_CALIPSO:
  247. BUG_ON(calipso == NULL);
  248. audit_log_format(audit_buf,
  249. " nlbl_protocol=calipso calipso_doi=%u",
  250. calipso->doi);
  251. break;
  252. }
  253. audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
  254. audit_log_end(audit_buf);
  255. }
  256. }
  257. /**
  258. * netlbl_domhsh_validate - Validate a new domain mapping entry
  259. * @entry: the entry to validate
  260. *
  261. * This function validates the new domain mapping entry to ensure that it is
  262. * a valid entry. Returns zero on success, negative values on failure.
  263. *
  264. */
  265. static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
  266. {
  267. struct netlbl_af4list *iter4;
  268. struct netlbl_domaddr4_map *map4;
  269. #if IS_ENABLED(CONFIG_IPV6)
  270. struct netlbl_af6list *iter6;
  271. struct netlbl_domaddr6_map *map6;
  272. #endif /* IPv6 */
  273. if (entry == NULL)
  274. return -EINVAL;
  275. if (entry->family != AF_INET && entry->family != AF_INET6 &&
  276. (entry->family != AF_UNSPEC ||
  277. entry->def.type != NETLBL_NLTYPE_UNLABELED))
  278. return -EINVAL;
  279. switch (entry->def.type) {
  280. case NETLBL_NLTYPE_UNLABELED:
  281. if (entry->def.cipso != NULL || entry->def.calipso != NULL ||
  282. entry->def.addrsel != NULL)
  283. return -EINVAL;
  284. break;
  285. case NETLBL_NLTYPE_CIPSOV4:
  286. if (entry->family != AF_INET ||
  287. entry->def.cipso == NULL)
  288. return -EINVAL;
  289. break;
  290. case NETLBL_NLTYPE_CALIPSO:
  291. if (entry->family != AF_INET6 ||
  292. entry->def.calipso == NULL)
  293. return -EINVAL;
  294. break;
  295. case NETLBL_NLTYPE_ADDRSELECT:
  296. netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) {
  297. map4 = netlbl_domhsh_addr4_entry(iter4);
  298. switch (map4->def.type) {
  299. case NETLBL_NLTYPE_UNLABELED:
  300. if (map4->def.cipso != NULL)
  301. return -EINVAL;
  302. break;
  303. case NETLBL_NLTYPE_CIPSOV4:
  304. if (map4->def.cipso == NULL)
  305. return -EINVAL;
  306. break;
  307. default:
  308. return -EINVAL;
  309. }
  310. }
  311. #if IS_ENABLED(CONFIG_IPV6)
  312. netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) {
  313. map6 = netlbl_domhsh_addr6_entry(iter6);
  314. switch (map6->def.type) {
  315. case NETLBL_NLTYPE_UNLABELED:
  316. if (map6->def.calipso != NULL)
  317. return -EINVAL;
  318. break;
  319. case NETLBL_NLTYPE_CALIPSO:
  320. if (map6->def.calipso == NULL)
  321. return -EINVAL;
  322. break;
  323. default:
  324. return -EINVAL;
  325. }
  326. }
  327. #endif /* IPv6 */
  328. break;
  329. default:
  330. return -EINVAL;
  331. }
  332. return 0;
  333. }
  334. /*
  335. * Domain Hash Table Functions
  336. */
  337. /**
  338. * netlbl_domhsh_init - Init for the domain hash
  339. * @size: the number of bits to use for the hash buckets
  340. *
  341. * Description:
  342. * Initializes the domain hash table, should be called only by
  343. * netlbl_user_init() during initialization. Returns zero on success, non-zero
  344. * values on error.
  345. *
  346. */
  347. int __init netlbl_domhsh_init(u32 size)
  348. {
  349. u32 iter;
  350. struct netlbl_domhsh_tbl *hsh_tbl;
  351. if (size == 0)
  352. return -EINVAL;
  353. hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
  354. if (hsh_tbl == NULL)
  355. return -ENOMEM;
  356. hsh_tbl->size = 1 << size;
  357. hsh_tbl->tbl = kcalloc(hsh_tbl->size,
  358. sizeof(struct list_head),
  359. GFP_KERNEL);
  360. if (hsh_tbl->tbl == NULL) {
  361. kfree(hsh_tbl);
  362. return -ENOMEM;
  363. }
  364. for (iter = 0; iter < hsh_tbl->size; iter++)
  365. INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
  366. spin_lock(&netlbl_domhsh_lock);
  367. rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
  368. spin_unlock(&netlbl_domhsh_lock);
  369. return 0;
  370. }
  371. /**
  372. * netlbl_domhsh_add - Adds a entry to the domain hash table
  373. * @entry: the entry to add
  374. * @audit_info: NetLabel audit information
  375. *
  376. * Description:
  377. * Adds a new entry to the domain hash table and handles any updates to the
  378. * lower level protocol handler (i.e. CIPSO). @entry->family may be set to
  379. * %AF_UNSPEC which will add an entry that matches all address families. This
  380. * is only useful for the unlabelled type and will only succeed if there is no
  381. * existing entry for any address family with the same domain. Returns zero
  382. * on success, negative on failure.
  383. *
  384. */
  385. int netlbl_domhsh_add(struct netlbl_dom_map *entry,
  386. struct netlbl_audit *audit_info)
  387. {
  388. int ret_val = 0;
  389. struct netlbl_dom_map *entry_old, *entry_b;
  390. struct netlbl_af4list *iter4;
  391. struct netlbl_af4list *tmp4;
  392. #if IS_ENABLED(CONFIG_IPV6)
  393. struct netlbl_af6list *iter6;
  394. struct netlbl_af6list *tmp6;
  395. #endif /* IPv6 */
  396. ret_val = netlbl_domhsh_validate(entry);
  397. if (ret_val != 0)
  398. return ret_val;
  399. /* XXX - we can remove this RCU read lock as the spinlock protects the
  400. * entire function, but before we do we need to fixup the
  401. * netlbl_af[4,6]list RCU functions to do "the right thing" with
  402. * respect to rcu_dereference() when only a spinlock is held. */
  403. rcu_read_lock();
  404. spin_lock(&netlbl_domhsh_lock);
  405. if (entry->domain != NULL)
  406. entry_old = netlbl_domhsh_search(entry->domain, entry->family);
  407. else
  408. entry_old = netlbl_domhsh_search_def(entry->domain,
  409. entry->family);
  410. if (entry_old == NULL) {
  411. entry->valid = 1;
  412. if (entry->domain != NULL) {
  413. u32 bkt = netlbl_domhsh_hash(entry->domain);
  414. list_add_tail_rcu(&entry->list,
  415. &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
  416. } else {
  417. INIT_LIST_HEAD(&entry->list);
  418. switch (entry->family) {
  419. case AF_INET:
  420. rcu_assign_pointer(netlbl_domhsh_def_ipv4,
  421. entry);
  422. break;
  423. case AF_INET6:
  424. rcu_assign_pointer(netlbl_domhsh_def_ipv6,
  425. entry);
  426. break;
  427. case AF_UNSPEC:
  428. if (entry->def.type !=
  429. NETLBL_NLTYPE_UNLABELED) {
  430. ret_val = -EINVAL;
  431. goto add_return;
  432. }
  433. entry_b = kzalloc(sizeof(*entry_b), GFP_ATOMIC);
  434. if (entry_b == NULL) {
  435. ret_val = -ENOMEM;
  436. goto add_return;
  437. }
  438. entry_b->family = AF_INET6;
  439. entry_b->def.type = NETLBL_NLTYPE_UNLABELED;
  440. entry_b->valid = 1;
  441. entry->family = AF_INET;
  442. rcu_assign_pointer(netlbl_domhsh_def_ipv4,
  443. entry);
  444. rcu_assign_pointer(netlbl_domhsh_def_ipv6,
  445. entry_b);
  446. break;
  447. default:
  448. /* Already checked in
  449. * netlbl_domhsh_validate(). */
  450. ret_val = -EINVAL;
  451. goto add_return;
  452. }
  453. }
  454. if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
  455. netlbl_af4list_foreach_rcu(iter4,
  456. &entry->def.addrsel->list4)
  457. netlbl_domhsh_audit_add(entry, iter4, NULL,
  458. ret_val, audit_info);
  459. #if IS_ENABLED(CONFIG_IPV6)
  460. netlbl_af6list_foreach_rcu(iter6,
  461. &entry->def.addrsel->list6)
  462. netlbl_domhsh_audit_add(entry, NULL, iter6,
  463. ret_val, audit_info);
  464. #endif /* IPv6 */
  465. } else
  466. netlbl_domhsh_audit_add(entry, NULL, NULL,
  467. ret_val, audit_info);
  468. } else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT &&
  469. entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
  470. struct list_head *old_list4;
  471. struct list_head *old_list6;
  472. old_list4 = &entry_old->def.addrsel->list4;
  473. old_list6 = &entry_old->def.addrsel->list6;
  474. /* we only allow the addition of address selectors if all of
  475. * the selectors do not exist in the existing domain map */
  476. netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4)
  477. if (netlbl_af4list_search_exact(iter4->addr,
  478. iter4->mask,
  479. old_list4)) {
  480. ret_val = -EEXIST;
  481. goto add_return;
  482. }
  483. #if IS_ENABLED(CONFIG_IPV6)
  484. netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6)
  485. if (netlbl_af6list_search_exact(&iter6->addr,
  486. &iter6->mask,
  487. old_list6)) {
  488. ret_val = -EEXIST;
  489. goto add_return;
  490. }
  491. #endif /* IPv6 */
  492. netlbl_af4list_foreach_safe(iter4, tmp4,
  493. &entry->def.addrsel->list4) {
  494. netlbl_af4list_remove_entry(iter4);
  495. iter4->valid = 1;
  496. ret_val = netlbl_af4list_add(iter4, old_list4);
  497. netlbl_domhsh_audit_add(entry_old, iter4, NULL,
  498. ret_val, audit_info);
  499. if (ret_val != 0)
  500. goto add_return;
  501. }
  502. #if IS_ENABLED(CONFIG_IPV6)
  503. netlbl_af6list_foreach_safe(iter6, tmp6,
  504. &entry->def.addrsel->list6) {
  505. netlbl_af6list_remove_entry(iter6);
  506. iter6->valid = 1;
  507. ret_val = netlbl_af6list_add(iter6, old_list6);
  508. netlbl_domhsh_audit_add(entry_old, NULL, iter6,
  509. ret_val, audit_info);
  510. if (ret_val != 0)
  511. goto add_return;
  512. }
  513. #endif /* IPv6 */
  514. } else
  515. ret_val = -EINVAL;
  516. add_return:
  517. spin_unlock(&netlbl_domhsh_lock);
  518. rcu_read_unlock();
  519. return ret_val;
  520. }
  521. /**
  522. * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
  523. * @entry: the entry to add
  524. * @audit_info: NetLabel audit information
  525. *
  526. * Description:
  527. * Adds a new default entry to the domain hash table and handles any updates
  528. * to the lower level protocol handler (i.e. CIPSO). Returns zero on success,
  529. * negative on failure.
  530. *
  531. */
  532. int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
  533. struct netlbl_audit *audit_info)
  534. {
  535. return netlbl_domhsh_add(entry, audit_info);
  536. }
  537. /**
  538. * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
  539. * @entry: the entry to remove
  540. * @audit_info: NetLabel audit information
  541. *
  542. * Description:
  543. * Removes an entry from the domain hash table and handles any updates to the
  544. * lower level protocol handler (i.e. CIPSO). Caller is responsible for
  545. * ensuring that the RCU read lock is held. Returns zero on success, negative
  546. * on failure.
  547. *
  548. */
  549. int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
  550. struct netlbl_audit *audit_info)
  551. {
  552. int ret_val = 0;
  553. struct audit_buffer *audit_buf;
  554. if (entry == NULL)
  555. return -ENOENT;
  556. spin_lock(&netlbl_domhsh_lock);
  557. if (entry->valid) {
  558. entry->valid = 0;
  559. if (entry == rcu_dereference(netlbl_domhsh_def_ipv4))
  560. RCU_INIT_POINTER(netlbl_domhsh_def_ipv4, NULL);
  561. else if (entry == rcu_dereference(netlbl_domhsh_def_ipv6))
  562. RCU_INIT_POINTER(netlbl_domhsh_def_ipv6, NULL);
  563. else
  564. list_del_rcu(&entry->list);
  565. } else
  566. ret_val = -ENOENT;
  567. spin_unlock(&netlbl_domhsh_lock);
  568. audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
  569. if (audit_buf != NULL) {
  570. audit_log_format(audit_buf,
  571. " nlbl_domain=%s res=%u",
  572. entry->domain ? entry->domain : "(default)",
  573. ret_val == 0 ? 1 : 0);
  574. audit_log_end(audit_buf);
  575. }
  576. if (ret_val == 0) {
  577. struct netlbl_af4list *iter4;
  578. struct netlbl_domaddr4_map *map4;
  579. #if IS_ENABLED(CONFIG_IPV6)
  580. struct netlbl_af6list *iter6;
  581. struct netlbl_domaddr6_map *map6;
  582. #endif /* IPv6 */
  583. switch (entry->def.type) {
  584. case NETLBL_NLTYPE_ADDRSELECT:
  585. netlbl_af4list_foreach_rcu(iter4,
  586. &entry->def.addrsel->list4) {
  587. map4 = netlbl_domhsh_addr4_entry(iter4);
  588. cipso_v4_doi_putdef(map4->def.cipso);
  589. }
  590. #if IS_ENABLED(CONFIG_IPV6)
  591. netlbl_af6list_foreach_rcu(iter6,
  592. &entry->def.addrsel->list6) {
  593. map6 = netlbl_domhsh_addr6_entry(iter6);
  594. calipso_doi_putdef(map6->def.calipso);
  595. }
  596. #endif /* IPv6 */
  597. break;
  598. case NETLBL_NLTYPE_CIPSOV4:
  599. cipso_v4_doi_putdef(entry->def.cipso);
  600. break;
  601. #if IS_ENABLED(CONFIG_IPV6)
  602. case NETLBL_NLTYPE_CALIPSO:
  603. calipso_doi_putdef(entry->def.calipso);
  604. break;
  605. #endif /* IPv6 */
  606. }
  607. call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
  608. }
  609. return ret_val;
  610. }
  611. /**
  612. * netlbl_domhsh_remove_af4 - Removes an address selector entry
  613. * @domain: the domain
  614. * @addr: IPv4 address
  615. * @mask: IPv4 address mask
  616. * @audit_info: NetLabel audit information
  617. *
  618. * Description:
  619. * Removes an individual address selector from a domain mapping and potentially
  620. * the entire mapping if it is empty. Returns zero on success, negative values
  621. * on failure.
  622. *
  623. */
  624. int netlbl_domhsh_remove_af4(const char *domain,
  625. const struct in_addr *addr,
  626. const struct in_addr *mask,
  627. struct netlbl_audit *audit_info)
  628. {
  629. struct netlbl_dom_map *entry_map;
  630. struct netlbl_af4list *entry_addr;
  631. struct netlbl_af4list *iter4;
  632. #if IS_ENABLED(CONFIG_IPV6)
  633. struct netlbl_af6list *iter6;
  634. #endif /* IPv6 */
  635. struct netlbl_domaddr4_map *entry;
  636. rcu_read_lock();
  637. if (domain)
  638. entry_map = netlbl_domhsh_search(domain, AF_INET);
  639. else
  640. entry_map = netlbl_domhsh_search_def(domain, AF_INET);
  641. if (entry_map == NULL ||
  642. entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
  643. goto remove_af4_failure;
  644. spin_lock(&netlbl_domhsh_lock);
  645. entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
  646. &entry_map->def.addrsel->list4);
  647. spin_unlock(&netlbl_domhsh_lock);
  648. if (entry_addr == NULL)
  649. goto remove_af4_failure;
  650. netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
  651. goto remove_af4_single_addr;
  652. #if IS_ENABLED(CONFIG_IPV6)
  653. netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
  654. goto remove_af4_single_addr;
  655. #endif /* IPv6 */
  656. /* the domain mapping is empty so remove it from the mapping table */
  657. netlbl_domhsh_remove_entry(entry_map, audit_info);
  658. remove_af4_single_addr:
  659. rcu_read_unlock();
  660. /* yick, we can't use call_rcu here because we don't have a rcu head
  661. * pointer but hopefully this should be a rare case so the pause
  662. * shouldn't be a problem */
  663. synchronize_rcu();
  664. entry = netlbl_domhsh_addr4_entry(entry_addr);
  665. cipso_v4_doi_putdef(entry->def.cipso);
  666. kfree(entry);
  667. return 0;
  668. remove_af4_failure:
  669. rcu_read_unlock();
  670. return -ENOENT;
  671. }
  672. #if IS_ENABLED(CONFIG_IPV6)
  673. /**
  674. * netlbl_domhsh_remove_af6 - Removes an address selector entry
  675. * @domain: the domain
  676. * @addr: IPv6 address
  677. * @mask: IPv6 address mask
  678. * @audit_info: NetLabel audit information
  679. *
  680. * Description:
  681. * Removes an individual address selector from a domain mapping and potentially
  682. * the entire mapping if it is empty. Returns zero on success, negative values
  683. * on failure.
  684. *
  685. */
  686. int netlbl_domhsh_remove_af6(const char *domain,
  687. const struct in6_addr *addr,
  688. const struct in6_addr *mask,
  689. struct netlbl_audit *audit_info)
  690. {
  691. struct netlbl_dom_map *entry_map;
  692. struct netlbl_af6list *entry_addr;
  693. struct netlbl_af4list *iter4;
  694. struct netlbl_af6list *iter6;
  695. struct netlbl_domaddr6_map *entry;
  696. rcu_read_lock();
  697. if (domain)
  698. entry_map = netlbl_domhsh_search(domain, AF_INET6);
  699. else
  700. entry_map = netlbl_domhsh_search_def(domain, AF_INET6);
  701. if (entry_map == NULL ||
  702. entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
  703. goto remove_af6_failure;
  704. spin_lock(&netlbl_domhsh_lock);
  705. entry_addr = netlbl_af6list_remove(addr, mask,
  706. &entry_map->def.addrsel->list6);
  707. spin_unlock(&netlbl_domhsh_lock);
  708. if (entry_addr == NULL)
  709. goto remove_af6_failure;
  710. netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
  711. goto remove_af6_single_addr;
  712. netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
  713. goto remove_af6_single_addr;
  714. /* the domain mapping is empty so remove it from the mapping table */
  715. netlbl_domhsh_remove_entry(entry_map, audit_info);
  716. remove_af6_single_addr:
  717. rcu_read_unlock();
  718. /* yick, we can't use call_rcu here because we don't have a rcu head
  719. * pointer but hopefully this should be a rare case so the pause
  720. * shouldn't be a problem */
  721. synchronize_rcu();
  722. entry = netlbl_domhsh_addr6_entry(entry_addr);
  723. calipso_doi_putdef(entry->def.calipso);
  724. kfree(entry);
  725. return 0;
  726. remove_af6_failure:
  727. rcu_read_unlock();
  728. return -ENOENT;
  729. }
  730. #endif /* IPv6 */
  731. /**
  732. * netlbl_domhsh_remove - Removes an entry from the domain hash table
  733. * @domain: the domain to remove
  734. * @family: address family
  735. * @audit_info: NetLabel audit information
  736. *
  737. * Description:
  738. * Removes an entry from the domain hash table and handles any updates to the
  739. * lower level protocol handler (i.e. CIPSO). @family may be %AF_UNSPEC which
  740. * removes all address family entries. Returns zero on success, negative on
  741. * failure.
  742. *
  743. */
  744. int netlbl_domhsh_remove(const char *domain, u16 family,
  745. struct netlbl_audit *audit_info)
  746. {
  747. int ret_val = -EINVAL;
  748. struct netlbl_dom_map *entry;
  749. rcu_read_lock();
  750. if (family == AF_INET || family == AF_UNSPEC) {
  751. if (domain)
  752. entry = netlbl_domhsh_search(domain, AF_INET);
  753. else
  754. entry = netlbl_domhsh_search_def(domain, AF_INET);
  755. ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
  756. if (ret_val && ret_val != -ENOENT)
  757. goto done;
  758. }
  759. if (family == AF_INET6 || family == AF_UNSPEC) {
  760. int ret_val2;
  761. if (domain)
  762. entry = netlbl_domhsh_search(domain, AF_INET6);
  763. else
  764. entry = netlbl_domhsh_search_def(domain, AF_INET6);
  765. ret_val2 = netlbl_domhsh_remove_entry(entry, audit_info);
  766. if (ret_val2 != -ENOENT)
  767. ret_val = ret_val2;
  768. }
  769. done:
  770. rcu_read_unlock();
  771. return ret_val;
  772. }
  773. /**
  774. * netlbl_domhsh_remove_default - Removes the default entry from the table
  775. * @family: address family
  776. * @audit_info: NetLabel audit information
  777. *
  778. * Description:
  779. * Removes/resets the default entry corresponding to @family from the domain
  780. * hash table and handles any updates to the lower level protocol handler
  781. * (i.e. CIPSO). @family may be %AF_UNSPEC which removes all address family
  782. * entries. Returns zero on success, negative on failure.
  783. *
  784. */
  785. int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info)
  786. {
  787. return netlbl_domhsh_remove(NULL, family, audit_info);
  788. }
  789. /**
  790. * netlbl_domhsh_getentry - Get an entry from the domain hash table
  791. * @domain: the domain name to search for
  792. * @family: address family
  793. *
  794. * Description:
  795. * Look through the domain hash table searching for an entry to match @domain,
  796. * with address family @family, return a pointer to a copy of the entry or
  797. * NULL. The caller is responsible for ensuring that rcu_read_[un]lock() is
  798. * called.
  799. *
  800. */
  801. struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family)
  802. {
  803. if (family == AF_UNSPEC)
  804. return NULL;
  805. return netlbl_domhsh_search_def(domain, family);
  806. }
  807. /**
  808. * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
  809. * @domain: the domain name to search for
  810. * @addr: the IP address to search for
  811. *
  812. * Description:
  813. * Look through the domain hash table searching for an entry to match @domain
  814. * and @addr, return a pointer to a copy of the entry or NULL. The caller is
  815. * responsible for ensuring that rcu_read_[un]lock() is called.
  816. *
  817. */
  818. struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
  819. __be32 addr)
  820. {
  821. struct netlbl_dom_map *dom_iter;
  822. struct netlbl_af4list *addr_iter;
  823. dom_iter = netlbl_domhsh_search_def(domain, AF_INET);
  824. if (dom_iter == NULL)
  825. return NULL;
  826. if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
  827. return &dom_iter->def;
  828. addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4);
  829. if (addr_iter == NULL)
  830. return NULL;
  831. return &(netlbl_domhsh_addr4_entry(addr_iter)->def);
  832. }
  833. #if IS_ENABLED(CONFIG_IPV6)
  834. /**
  835. * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
  836. * @domain: the domain name to search for
  837. * @addr: the IP address to search for
  838. *
  839. * Description:
  840. * Look through the domain hash table searching for an entry to match @domain
  841. * and @addr, return a pointer to a copy of the entry or NULL. The caller is
  842. * responsible for ensuring that rcu_read_[un]lock() is called.
  843. *
  844. */
  845. struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
  846. const struct in6_addr *addr)
  847. {
  848. struct netlbl_dom_map *dom_iter;
  849. struct netlbl_af6list *addr_iter;
  850. dom_iter = netlbl_domhsh_search_def(domain, AF_INET6);
  851. if (dom_iter == NULL)
  852. return NULL;
  853. if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
  854. return &dom_iter->def;
  855. addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6);
  856. if (addr_iter == NULL)
  857. return NULL;
  858. return &(netlbl_domhsh_addr6_entry(addr_iter)->def);
  859. }
  860. #endif /* IPv6 */
  861. /**
  862. * netlbl_domhsh_walk - Iterate through the domain mapping hash table
  863. * @skip_bkt: the number of buckets to skip at the start
  864. * @skip_chain: the number of entries to skip in the first iterated bucket
  865. * @callback: callback for each entry
  866. * @cb_arg: argument for the callback function
  867. *
  868. * Description:
  869. * Interate over the domain mapping hash table, skipping the first @skip_bkt
  870. * buckets and @skip_chain entries. For each entry in the table call
  871. * @callback, if @callback returns a negative value stop 'walking' through the
  872. * table and return. Updates the values in @skip_bkt and @skip_chain on
  873. * return. Returns zero on success, negative values on failure.
  874. *
  875. */
  876. int netlbl_domhsh_walk(u32 *skip_bkt,
  877. u32 *skip_chain,
  878. int (*callback) (struct netlbl_dom_map *entry, void *arg),
  879. void *cb_arg)
  880. {
  881. int ret_val = -ENOENT;
  882. u32 iter_bkt;
  883. struct list_head *iter_list;
  884. struct netlbl_dom_map *iter_entry;
  885. u32 chain_cnt = 0;
  886. rcu_read_lock();
  887. for (iter_bkt = *skip_bkt;
  888. iter_bkt < rcu_dereference(netlbl_domhsh)->size;
  889. iter_bkt++, chain_cnt = 0) {
  890. iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
  891. list_for_each_entry_rcu(iter_entry, iter_list, list)
  892. if (iter_entry->valid) {
  893. if (chain_cnt++ < *skip_chain)
  894. continue;
  895. ret_val = callback(iter_entry, cb_arg);
  896. if (ret_val < 0) {
  897. chain_cnt--;
  898. goto walk_return;
  899. }
  900. }
  901. }
  902. walk_return:
  903. rcu_read_unlock();
  904. *skip_bkt = iter_bkt;
  905. *skip_chain = chain_cnt;
  906. return ret_val;
  907. }