netlabel_domainhash.c 28 KB

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