netlabel_cipso_v4.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * NetLabel CIPSO/IPv4 Support
  4. *
  5. * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
  6. * NetLabel system manages static and dynamic label mappings for network
  7. * protocols such as CIPSO and RIPSO.
  8. *
  9. * Author: Paul Moore <paul@paul-moore.com>
  10. */
  11. /*
  12. * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
  13. */
  14. #include <linux/types.h>
  15. #include <linux/socket.h>
  16. #include <linux/string.h>
  17. #include <linux/skbuff.h>
  18. #include <linux/audit.h>
  19. #include <linux/slab.h>
  20. #include <net/sock.h>
  21. #include <net/netlink.h>
  22. #include <net/genetlink.h>
  23. #include <net/netlabel.h>
  24. #include <net/cipso_ipv4.h>
  25. #include <linux/atomic.h>
  26. #include "netlabel_user.h"
  27. #include "netlabel_cipso_v4.h"
  28. #include "netlabel_mgmt.h"
  29. #include "netlabel_domainhash.h"
  30. /* Argument struct for cipso_v4_doi_walk() */
  31. struct netlbl_cipsov4_doiwalk_arg {
  32. struct netlink_callback *nl_cb;
  33. struct sk_buff *skb;
  34. u32 seq;
  35. };
  36. /* Argument struct for netlbl_domhsh_walk() */
  37. struct netlbl_domhsh_walk_arg {
  38. struct netlbl_audit *audit_info;
  39. u32 doi;
  40. };
  41. /* NetLabel Generic NETLINK CIPSOv4 family */
  42. static struct genl_family netlbl_cipsov4_gnl_family;
  43. /* NetLabel Netlink attribute policy */
  44. static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
  45. [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
  46. [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
  47. [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
  48. [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
  49. [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
  50. [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
  51. [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
  52. [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
  53. [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
  54. [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
  55. [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
  56. [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
  57. };
  58. /*
  59. * Helper Functions
  60. */
  61. /**
  62. * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
  63. * @info: the Generic NETLINK info block
  64. * @doi_def: the CIPSO V4 DOI definition
  65. *
  66. * Description:
  67. * Parse the common sections of a ADD message and fill in the related values
  68. * in @doi_def. Returns zero on success, negative values on failure.
  69. *
  70. */
  71. static int netlbl_cipsov4_add_common(struct genl_info *info,
  72. struct cipso_v4_doi *doi_def)
  73. {
  74. struct nlattr *nla;
  75. int nla_rem;
  76. u32 iter = 0;
  77. doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
  78. if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_TAGLST],
  79. NLBL_CIPSOV4_A_MAX,
  80. netlbl_cipsov4_genl_policy,
  81. NULL) != 0)
  82. return -EINVAL;
  83. nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
  84. if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
  85. if (iter >= CIPSO_V4_TAG_MAXCNT)
  86. return -EINVAL;
  87. doi_def->tags[iter++] = nla_get_u8(nla);
  88. }
  89. while (iter < CIPSO_V4_TAG_MAXCNT)
  90. doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
  91. return 0;
  92. }
  93. /*
  94. * NetLabel Command Handlers
  95. */
  96. /**
  97. * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
  98. * @info: the Generic NETLINK info block
  99. * @audit_info: NetLabel audit information
  100. *
  101. * Description:
  102. * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
  103. * message and add it to the CIPSO V4 engine. Return zero on success and
  104. * non-zero on error.
  105. *
  106. */
  107. static int netlbl_cipsov4_add_std(struct genl_info *info,
  108. struct netlbl_audit *audit_info)
  109. {
  110. int ret_val = -EINVAL;
  111. struct cipso_v4_doi *doi_def = NULL;
  112. struct nlattr *nla_a;
  113. struct nlattr *nla_b;
  114. int nla_a_rem;
  115. int nla_b_rem;
  116. u32 iter;
  117. if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
  118. !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
  119. return -EINVAL;
  120. if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
  121. NLBL_CIPSOV4_A_MAX,
  122. netlbl_cipsov4_genl_policy,
  123. NULL) != 0)
  124. return -EINVAL;
  125. doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
  126. if (doi_def == NULL)
  127. return -ENOMEM;
  128. doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
  129. if (doi_def->map.std == NULL) {
  130. kfree(doi_def);
  131. return -ENOMEM;
  132. }
  133. doi_def->type = CIPSO_V4_MAP_TRANS;
  134. ret_val = netlbl_cipsov4_add_common(info, doi_def);
  135. if (ret_val != 0)
  136. goto add_std_failure;
  137. ret_val = -EINVAL;
  138. nla_for_each_nested(nla_a,
  139. info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
  140. nla_a_rem)
  141. if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
  142. if (nla_validate_nested_deprecated(nla_a,
  143. NLBL_CIPSOV4_A_MAX,
  144. netlbl_cipsov4_genl_policy,
  145. NULL) != 0)
  146. goto add_std_failure;
  147. nla_for_each_nested(nla_b, nla_a, nla_b_rem)
  148. switch (nla_type(nla_b)) {
  149. case NLBL_CIPSOV4_A_MLSLVLLOC:
  150. if (nla_get_u32(nla_b) >
  151. CIPSO_V4_MAX_LOC_LVLS)
  152. goto add_std_failure;
  153. if (nla_get_u32(nla_b) >=
  154. doi_def->map.std->lvl.local_size)
  155. doi_def->map.std->lvl.local_size =
  156. nla_get_u32(nla_b) + 1;
  157. break;
  158. case NLBL_CIPSOV4_A_MLSLVLREM:
  159. if (nla_get_u32(nla_b) >
  160. CIPSO_V4_MAX_REM_LVLS)
  161. goto add_std_failure;
  162. if (nla_get_u32(nla_b) >=
  163. doi_def->map.std->lvl.cipso_size)
  164. doi_def->map.std->lvl.cipso_size =
  165. nla_get_u32(nla_b) + 1;
  166. break;
  167. }
  168. }
  169. doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
  170. sizeof(u32),
  171. GFP_KERNEL | __GFP_NOWARN);
  172. if (doi_def->map.std->lvl.local == NULL) {
  173. ret_val = -ENOMEM;
  174. goto add_std_failure;
  175. }
  176. doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
  177. sizeof(u32),
  178. GFP_KERNEL | __GFP_NOWARN);
  179. if (doi_def->map.std->lvl.cipso == NULL) {
  180. ret_val = -ENOMEM;
  181. goto add_std_failure;
  182. }
  183. for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
  184. doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
  185. for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
  186. doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
  187. nla_for_each_nested(nla_a,
  188. info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
  189. nla_a_rem)
  190. if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
  191. struct nlattr *lvl_loc;
  192. struct nlattr *lvl_rem;
  193. lvl_loc = nla_find_nested(nla_a,
  194. NLBL_CIPSOV4_A_MLSLVLLOC);
  195. lvl_rem = nla_find_nested(nla_a,
  196. NLBL_CIPSOV4_A_MLSLVLREM);
  197. if (lvl_loc == NULL || lvl_rem == NULL)
  198. goto add_std_failure;
  199. doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
  200. nla_get_u32(lvl_rem);
  201. doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
  202. nla_get_u32(lvl_loc);
  203. }
  204. if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
  205. if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
  206. NLBL_CIPSOV4_A_MAX,
  207. netlbl_cipsov4_genl_policy,
  208. NULL) != 0)
  209. goto add_std_failure;
  210. nla_for_each_nested(nla_a,
  211. info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
  212. nla_a_rem)
  213. if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
  214. if (nla_validate_nested_deprecated(nla_a,
  215. NLBL_CIPSOV4_A_MAX,
  216. netlbl_cipsov4_genl_policy,
  217. NULL) != 0)
  218. goto add_std_failure;
  219. nla_for_each_nested(nla_b, nla_a, nla_b_rem)
  220. switch (nla_type(nla_b)) {
  221. case NLBL_CIPSOV4_A_MLSCATLOC:
  222. if (nla_get_u32(nla_b) >
  223. CIPSO_V4_MAX_LOC_CATS)
  224. goto add_std_failure;
  225. if (nla_get_u32(nla_b) >=
  226. doi_def->map.std->cat.local_size)
  227. doi_def->map.std->cat.local_size =
  228. nla_get_u32(nla_b) + 1;
  229. break;
  230. case NLBL_CIPSOV4_A_MLSCATREM:
  231. if (nla_get_u32(nla_b) >
  232. CIPSO_V4_MAX_REM_CATS)
  233. goto add_std_failure;
  234. if (nla_get_u32(nla_b) >=
  235. doi_def->map.std->cat.cipso_size)
  236. doi_def->map.std->cat.cipso_size =
  237. nla_get_u32(nla_b) + 1;
  238. break;
  239. }
  240. }
  241. doi_def->map.std->cat.local = kcalloc(
  242. doi_def->map.std->cat.local_size,
  243. sizeof(u32),
  244. GFP_KERNEL | __GFP_NOWARN);
  245. if (doi_def->map.std->cat.local == NULL) {
  246. ret_val = -ENOMEM;
  247. goto add_std_failure;
  248. }
  249. doi_def->map.std->cat.cipso = kcalloc(
  250. doi_def->map.std->cat.cipso_size,
  251. sizeof(u32),
  252. GFP_KERNEL | __GFP_NOWARN);
  253. if (doi_def->map.std->cat.cipso == NULL) {
  254. ret_val = -ENOMEM;
  255. goto add_std_failure;
  256. }
  257. for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
  258. doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
  259. for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
  260. doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
  261. nla_for_each_nested(nla_a,
  262. info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
  263. nla_a_rem)
  264. if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
  265. struct nlattr *cat_loc;
  266. struct nlattr *cat_rem;
  267. cat_loc = nla_find_nested(nla_a,
  268. NLBL_CIPSOV4_A_MLSCATLOC);
  269. cat_rem = nla_find_nested(nla_a,
  270. NLBL_CIPSOV4_A_MLSCATREM);
  271. if (cat_loc == NULL || cat_rem == NULL)
  272. goto add_std_failure;
  273. doi_def->map.std->cat.local[
  274. nla_get_u32(cat_loc)] =
  275. nla_get_u32(cat_rem);
  276. doi_def->map.std->cat.cipso[
  277. nla_get_u32(cat_rem)] =
  278. nla_get_u32(cat_loc);
  279. }
  280. }
  281. ret_val = cipso_v4_doi_add(doi_def, audit_info);
  282. if (ret_val != 0)
  283. goto add_std_failure;
  284. return 0;
  285. add_std_failure:
  286. cipso_v4_doi_free(doi_def);
  287. return ret_val;
  288. }
  289. /**
  290. * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
  291. * @info: the Generic NETLINK info block
  292. * @audit_info: NetLabel audit information
  293. *
  294. * Description:
  295. * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
  296. * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
  297. * error.
  298. *
  299. */
  300. static int netlbl_cipsov4_add_pass(struct genl_info *info,
  301. struct netlbl_audit *audit_info)
  302. {
  303. int ret_val;
  304. struct cipso_v4_doi *doi_def = NULL;
  305. if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
  306. return -EINVAL;
  307. doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
  308. if (doi_def == NULL)
  309. return -ENOMEM;
  310. doi_def->type = CIPSO_V4_MAP_PASS;
  311. ret_val = netlbl_cipsov4_add_common(info, doi_def);
  312. if (ret_val != 0)
  313. goto add_pass_failure;
  314. ret_val = cipso_v4_doi_add(doi_def, audit_info);
  315. if (ret_val != 0)
  316. goto add_pass_failure;
  317. return 0;
  318. add_pass_failure:
  319. cipso_v4_doi_free(doi_def);
  320. return ret_val;
  321. }
  322. /**
  323. * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
  324. * @info: the Generic NETLINK info block
  325. * @audit_info: NetLabel audit information
  326. *
  327. * Description:
  328. * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
  329. * message and add it to the CIPSO V4 engine. Return zero on success and
  330. * non-zero on error.
  331. *
  332. */
  333. static int netlbl_cipsov4_add_local(struct genl_info *info,
  334. struct netlbl_audit *audit_info)
  335. {
  336. int ret_val;
  337. struct cipso_v4_doi *doi_def = NULL;
  338. if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
  339. return -EINVAL;
  340. doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
  341. if (doi_def == NULL)
  342. return -ENOMEM;
  343. doi_def->type = CIPSO_V4_MAP_LOCAL;
  344. ret_val = netlbl_cipsov4_add_common(info, doi_def);
  345. if (ret_val != 0)
  346. goto add_local_failure;
  347. ret_val = cipso_v4_doi_add(doi_def, audit_info);
  348. if (ret_val != 0)
  349. goto add_local_failure;
  350. return 0;
  351. add_local_failure:
  352. cipso_v4_doi_free(doi_def);
  353. return ret_val;
  354. }
  355. /**
  356. * netlbl_cipsov4_add - Handle an ADD message
  357. * @skb: the NETLINK buffer
  358. * @info: the Generic NETLINK info block
  359. *
  360. * Description:
  361. * Create a new DOI definition based on the given ADD message and add it to the
  362. * CIPSO V4 engine. Returns zero on success, negative values on failure.
  363. *
  364. */
  365. static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
  366. {
  367. int ret_val = -EINVAL;
  368. struct netlbl_audit audit_info;
  369. if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
  370. !info->attrs[NLBL_CIPSOV4_A_MTYPE])
  371. return -EINVAL;
  372. netlbl_netlink_auditinfo(skb, &audit_info);
  373. switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
  374. case CIPSO_V4_MAP_TRANS:
  375. ret_val = netlbl_cipsov4_add_std(info, &audit_info);
  376. break;
  377. case CIPSO_V4_MAP_PASS:
  378. ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
  379. break;
  380. case CIPSO_V4_MAP_LOCAL:
  381. ret_val = netlbl_cipsov4_add_local(info, &audit_info);
  382. break;
  383. }
  384. if (ret_val == 0)
  385. atomic_inc(&netlabel_mgmt_protocount);
  386. return ret_val;
  387. }
  388. /**
  389. * netlbl_cipsov4_list - Handle a LIST message
  390. * @skb: the NETLINK buffer
  391. * @info: the Generic NETLINK info block
  392. *
  393. * Description:
  394. * Process a user generated LIST message and respond accordingly. While the
  395. * response message generated by the kernel is straightforward, determining
  396. * before hand the size of the buffer to allocate is not (we have to generate
  397. * the message to know the size). In order to keep this function sane what we
  398. * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
  399. * that size, if we fail then we restart with a larger buffer and try again.
  400. * We continue in this manner until we hit a limit of failed attempts then we
  401. * give up and just send an error message. Returns zero on success and
  402. * negative values on error.
  403. *
  404. */
  405. static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
  406. {
  407. int ret_val;
  408. struct sk_buff *ans_skb = NULL;
  409. u32 nlsze_mult = 1;
  410. void *data;
  411. u32 doi;
  412. struct nlattr *nla_a;
  413. struct nlattr *nla_b;
  414. struct cipso_v4_doi *doi_def;
  415. u32 iter;
  416. if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
  417. ret_val = -EINVAL;
  418. goto list_failure;
  419. }
  420. list_start:
  421. ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
  422. if (ans_skb == NULL) {
  423. ret_val = -ENOMEM;
  424. goto list_failure;
  425. }
  426. data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
  427. 0, NLBL_CIPSOV4_C_LIST);
  428. if (data == NULL) {
  429. ret_val = -ENOMEM;
  430. goto list_failure;
  431. }
  432. doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
  433. rcu_read_lock();
  434. doi_def = cipso_v4_doi_getdef(doi);
  435. if (doi_def == NULL) {
  436. ret_val = -EINVAL;
  437. goto list_failure_lock;
  438. }
  439. ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
  440. if (ret_val != 0)
  441. goto list_failure_lock;
  442. nla_a = nla_nest_start_noflag(ans_skb, NLBL_CIPSOV4_A_TAGLST);
  443. if (nla_a == NULL) {
  444. ret_val = -ENOMEM;
  445. goto list_failure_lock;
  446. }
  447. for (iter = 0;
  448. iter < CIPSO_V4_TAG_MAXCNT &&
  449. doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
  450. iter++) {
  451. ret_val = nla_put_u8(ans_skb,
  452. NLBL_CIPSOV4_A_TAG,
  453. doi_def->tags[iter]);
  454. if (ret_val != 0)
  455. goto list_failure_lock;
  456. }
  457. nla_nest_end(ans_skb, nla_a);
  458. switch (doi_def->type) {
  459. case CIPSO_V4_MAP_TRANS:
  460. nla_a = nla_nest_start_noflag(ans_skb,
  461. NLBL_CIPSOV4_A_MLSLVLLST);
  462. if (nla_a == NULL) {
  463. ret_val = -ENOMEM;
  464. goto list_failure_lock;
  465. }
  466. for (iter = 0;
  467. iter < doi_def->map.std->lvl.local_size;
  468. iter++) {
  469. if (doi_def->map.std->lvl.local[iter] ==
  470. CIPSO_V4_INV_LVL)
  471. continue;
  472. nla_b = nla_nest_start_noflag(ans_skb,
  473. NLBL_CIPSOV4_A_MLSLVL);
  474. if (nla_b == NULL) {
  475. ret_val = -ENOMEM;
  476. goto list_retry;
  477. }
  478. ret_val = nla_put_u32(ans_skb,
  479. NLBL_CIPSOV4_A_MLSLVLLOC,
  480. iter);
  481. if (ret_val != 0)
  482. goto list_retry;
  483. ret_val = nla_put_u32(ans_skb,
  484. NLBL_CIPSOV4_A_MLSLVLREM,
  485. doi_def->map.std->lvl.local[iter]);
  486. if (ret_val != 0)
  487. goto list_retry;
  488. nla_nest_end(ans_skb, nla_b);
  489. }
  490. nla_nest_end(ans_skb, nla_a);
  491. nla_a = nla_nest_start_noflag(ans_skb,
  492. NLBL_CIPSOV4_A_MLSCATLST);
  493. if (nla_a == NULL) {
  494. ret_val = -ENOMEM;
  495. goto list_retry;
  496. }
  497. for (iter = 0;
  498. iter < doi_def->map.std->cat.local_size;
  499. iter++) {
  500. if (doi_def->map.std->cat.local[iter] ==
  501. CIPSO_V4_INV_CAT)
  502. continue;
  503. nla_b = nla_nest_start_noflag(ans_skb,
  504. NLBL_CIPSOV4_A_MLSCAT);
  505. if (nla_b == NULL) {
  506. ret_val = -ENOMEM;
  507. goto list_retry;
  508. }
  509. ret_val = nla_put_u32(ans_skb,
  510. NLBL_CIPSOV4_A_MLSCATLOC,
  511. iter);
  512. if (ret_val != 0)
  513. goto list_retry;
  514. ret_val = nla_put_u32(ans_skb,
  515. NLBL_CIPSOV4_A_MLSCATREM,
  516. doi_def->map.std->cat.local[iter]);
  517. if (ret_val != 0)
  518. goto list_retry;
  519. nla_nest_end(ans_skb, nla_b);
  520. }
  521. nla_nest_end(ans_skb, nla_a);
  522. break;
  523. }
  524. cipso_v4_doi_putdef(doi_def);
  525. rcu_read_unlock();
  526. genlmsg_end(ans_skb, data);
  527. return genlmsg_reply(ans_skb, info);
  528. list_retry:
  529. /* XXX - this limit is a guesstimate */
  530. if (nlsze_mult < 4) {
  531. cipso_v4_doi_putdef(doi_def);
  532. rcu_read_unlock();
  533. kfree_skb(ans_skb);
  534. nlsze_mult *= 2;
  535. goto list_start;
  536. }
  537. list_failure_lock:
  538. cipso_v4_doi_putdef(doi_def);
  539. rcu_read_unlock();
  540. list_failure:
  541. kfree_skb(ans_skb);
  542. return ret_val;
  543. }
  544. /**
  545. * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
  546. * @doi_def: the CIPSOv4 DOI definition
  547. * @arg: the netlbl_cipsov4_doiwalk_arg structure
  548. *
  549. * Description:
  550. * This function is designed to be used as a callback to the
  551. * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
  552. * message. Returns the size of the message on success, negative values on
  553. * failure.
  554. *
  555. */
  556. static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
  557. {
  558. int ret_val = -ENOMEM;
  559. struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
  560. void *data;
  561. data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
  562. cb_arg->seq, &netlbl_cipsov4_gnl_family,
  563. NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
  564. if (data == NULL)
  565. goto listall_cb_failure;
  566. ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
  567. if (ret_val != 0)
  568. goto listall_cb_failure;
  569. ret_val = nla_put_u32(cb_arg->skb,
  570. NLBL_CIPSOV4_A_MTYPE,
  571. doi_def->type);
  572. if (ret_val != 0)
  573. goto listall_cb_failure;
  574. genlmsg_end(cb_arg->skb, data);
  575. return 0;
  576. listall_cb_failure:
  577. genlmsg_cancel(cb_arg->skb, data);
  578. return ret_val;
  579. }
  580. /**
  581. * netlbl_cipsov4_listall - Handle a LISTALL message
  582. * @skb: the NETLINK buffer
  583. * @cb: the NETLINK callback
  584. *
  585. * Description:
  586. * Process a user generated LISTALL message and respond accordingly. Returns
  587. * zero on success and negative values on error.
  588. *
  589. */
  590. static int netlbl_cipsov4_listall(struct sk_buff *skb,
  591. struct netlink_callback *cb)
  592. {
  593. struct netlbl_cipsov4_doiwalk_arg cb_arg;
  594. u32 doi_skip = cb->args[0];
  595. cb_arg.nl_cb = cb;
  596. cb_arg.skb = skb;
  597. cb_arg.seq = cb->nlh->nlmsg_seq;
  598. cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
  599. cb->args[0] = doi_skip;
  600. return skb->len;
  601. }
  602. /**
  603. * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
  604. * @entry: LSM domain mapping entry
  605. * @arg: the netlbl_domhsh_walk_arg structure
  606. *
  607. * Description:
  608. * This function is intended for use by netlbl_cipsov4_remove() as the callback
  609. * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
  610. * which are associated with the CIPSO DOI specified in @arg. Returns zero on
  611. * success, negative values on failure.
  612. *
  613. */
  614. static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
  615. {
  616. struct netlbl_domhsh_walk_arg *cb_arg = arg;
  617. if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
  618. entry->def.cipso->doi == cb_arg->doi)
  619. return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
  620. return 0;
  621. }
  622. /**
  623. * netlbl_cipsov4_remove - Handle a REMOVE message
  624. * @skb: the NETLINK buffer
  625. * @info: the Generic NETLINK info block
  626. *
  627. * Description:
  628. * Process a user generated REMOVE message and respond accordingly. Returns
  629. * zero on success, negative values on failure.
  630. *
  631. */
  632. static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
  633. {
  634. int ret_val = -EINVAL;
  635. struct netlbl_domhsh_walk_arg cb_arg;
  636. struct netlbl_audit audit_info;
  637. u32 skip_bkt = 0;
  638. u32 skip_chain = 0;
  639. if (!info->attrs[NLBL_CIPSOV4_A_DOI])
  640. return -EINVAL;
  641. netlbl_netlink_auditinfo(skb, &audit_info);
  642. cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
  643. cb_arg.audit_info = &audit_info;
  644. ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
  645. netlbl_cipsov4_remove_cb, &cb_arg);
  646. if (ret_val == 0 || ret_val == -ENOENT) {
  647. ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
  648. if (ret_val == 0)
  649. atomic_dec(&netlabel_mgmt_protocount);
  650. }
  651. return ret_val;
  652. }
  653. /*
  654. * NetLabel Generic NETLINK Command Definitions
  655. */
  656. static const struct genl_small_ops netlbl_cipsov4_ops[] = {
  657. {
  658. .cmd = NLBL_CIPSOV4_C_ADD,
  659. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  660. .flags = GENL_ADMIN_PERM,
  661. .doit = netlbl_cipsov4_add,
  662. .dumpit = NULL,
  663. },
  664. {
  665. .cmd = NLBL_CIPSOV4_C_REMOVE,
  666. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  667. .flags = GENL_ADMIN_PERM,
  668. .doit = netlbl_cipsov4_remove,
  669. .dumpit = NULL,
  670. },
  671. {
  672. .cmd = NLBL_CIPSOV4_C_LIST,
  673. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  674. .flags = 0,
  675. .doit = netlbl_cipsov4_list,
  676. .dumpit = NULL,
  677. },
  678. {
  679. .cmd = NLBL_CIPSOV4_C_LISTALL,
  680. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  681. .flags = 0,
  682. .doit = NULL,
  683. .dumpit = netlbl_cipsov4_listall,
  684. },
  685. };
  686. static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
  687. .hdrsize = 0,
  688. .name = NETLBL_NLTYPE_CIPSOV4_NAME,
  689. .version = NETLBL_PROTO_VERSION,
  690. .maxattr = NLBL_CIPSOV4_A_MAX,
  691. .policy = netlbl_cipsov4_genl_policy,
  692. .module = THIS_MODULE,
  693. .small_ops = netlbl_cipsov4_ops,
  694. .n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
  695. };
  696. /*
  697. * NetLabel Generic NETLINK Protocol Functions
  698. */
  699. /**
  700. * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
  701. *
  702. * Description:
  703. * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
  704. * mechanism. Returns zero on success, negative values on failure.
  705. *
  706. */
  707. int __init netlbl_cipsov4_genl_init(void)
  708. {
  709. return genl_register_family(&netlbl_cipsov4_gnl_family);
  710. }