netlabel_mgmt.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * NetLabel Management Support
  4. *
  5. * This file defines the management 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, 2008
  13. */
  14. #include <linux/types.h>
  15. #include <linux/socket.h>
  16. #include <linux/string.h>
  17. #include <linux/skbuff.h>
  18. #include <linux/in.h>
  19. #include <linux/in6.h>
  20. #include <linux/slab.h>
  21. #include <net/sock.h>
  22. #include <net/netlink.h>
  23. #include <net/genetlink.h>
  24. #include <net/ip.h>
  25. #include <net/ipv6.h>
  26. #include <net/netlabel.h>
  27. #include <net/cipso_ipv4.h>
  28. #include <net/calipso.h>
  29. #include <linux/atomic.h>
  30. #include "netlabel_calipso.h"
  31. #include "netlabel_domainhash.h"
  32. #include "netlabel_user.h"
  33. #include "netlabel_mgmt.h"
  34. /* NetLabel configured protocol counter */
  35. atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
  36. /* Argument struct for netlbl_domhsh_walk() */
  37. struct netlbl_domhsh_walk_arg {
  38. struct netlink_callback *nl_cb;
  39. struct sk_buff *skb;
  40. u32 seq;
  41. };
  42. /* NetLabel Generic NETLINK CIPSOv4 family */
  43. static struct genl_family netlbl_mgmt_gnl_family;
  44. /* NetLabel Netlink attribute policy */
  45. static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
  46. [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
  47. [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
  48. [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
  49. [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
  50. [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
  51. [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
  52. };
  53. /*
  54. * Helper Functions
  55. */
  56. /**
  57. * netlbl_mgmt_add - Handle an ADD message
  58. * @info: the Generic NETLINK info block
  59. * @audit_info: NetLabel audit information
  60. *
  61. * Description:
  62. * Helper function for the ADD and ADDDEF messages to add the domain mappings
  63. * from the message to the hash table. See netlabel.h for a description of the
  64. * message format. Returns zero on success, negative values on failure.
  65. *
  66. */
  67. static int netlbl_mgmt_add_common(struct genl_info *info,
  68. struct netlbl_audit *audit_info)
  69. {
  70. void *pmap = NULL;
  71. int ret_val = -EINVAL;
  72. struct netlbl_domaddr_map *addrmap = NULL;
  73. struct cipso_v4_doi *cipsov4 = NULL;
  74. #if IS_ENABLED(CONFIG_IPV6)
  75. struct calipso_doi *calipso = NULL;
  76. #endif
  77. u32 tmp_val;
  78. struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  79. if (!entry)
  80. return -ENOMEM;
  81. entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
  82. if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
  83. size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
  84. entry->domain = kmalloc(tmp_size, GFP_KERNEL);
  85. if (entry->domain == NULL) {
  86. ret_val = -ENOMEM;
  87. goto add_free_entry;
  88. }
  89. nla_strlcpy(entry->domain,
  90. info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
  91. }
  92. /* NOTE: internally we allow/use a entry->def.type value of
  93. * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
  94. * to pass that as a protocol value because we need to know the
  95. * "real" protocol */
  96. switch (entry->def.type) {
  97. case NETLBL_NLTYPE_UNLABELED:
  98. if (info->attrs[NLBL_MGMT_A_FAMILY])
  99. entry->family =
  100. nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
  101. else
  102. entry->family = AF_UNSPEC;
  103. break;
  104. case NETLBL_NLTYPE_CIPSOV4:
  105. if (!info->attrs[NLBL_MGMT_A_CV4DOI])
  106. goto add_free_domain;
  107. tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
  108. cipsov4 = cipso_v4_doi_getdef(tmp_val);
  109. if (cipsov4 == NULL)
  110. goto add_free_domain;
  111. entry->family = AF_INET;
  112. entry->def.cipso = cipsov4;
  113. break;
  114. #if IS_ENABLED(CONFIG_IPV6)
  115. case NETLBL_NLTYPE_CALIPSO:
  116. if (!info->attrs[NLBL_MGMT_A_CLPDOI])
  117. goto add_free_domain;
  118. tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
  119. calipso = calipso_doi_getdef(tmp_val);
  120. if (calipso == NULL)
  121. goto add_free_domain;
  122. entry->family = AF_INET6;
  123. entry->def.calipso = calipso;
  124. break;
  125. #endif /* IPv6 */
  126. default:
  127. goto add_free_domain;
  128. }
  129. if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
  130. (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
  131. goto add_doi_put_def;
  132. if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
  133. struct in_addr *addr;
  134. struct in_addr *mask;
  135. struct netlbl_domaddr4_map *map;
  136. addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
  137. if (addrmap == NULL) {
  138. ret_val = -ENOMEM;
  139. goto add_doi_put_def;
  140. }
  141. INIT_LIST_HEAD(&addrmap->list4);
  142. INIT_LIST_HEAD(&addrmap->list6);
  143. if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
  144. sizeof(struct in_addr)) {
  145. ret_val = -EINVAL;
  146. goto add_free_addrmap;
  147. }
  148. if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
  149. sizeof(struct in_addr)) {
  150. ret_val = -EINVAL;
  151. goto add_free_addrmap;
  152. }
  153. addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
  154. mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
  155. map = kzalloc(sizeof(*map), GFP_KERNEL);
  156. if (map == NULL) {
  157. ret_val = -ENOMEM;
  158. goto add_free_addrmap;
  159. }
  160. pmap = map;
  161. map->list.addr = addr->s_addr & mask->s_addr;
  162. map->list.mask = mask->s_addr;
  163. map->list.valid = 1;
  164. map->def.type = entry->def.type;
  165. if (cipsov4)
  166. map->def.cipso = cipsov4;
  167. ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
  168. if (ret_val != 0)
  169. goto add_free_map;
  170. entry->family = AF_INET;
  171. entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
  172. entry->def.addrsel = addrmap;
  173. #if IS_ENABLED(CONFIG_IPV6)
  174. } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
  175. struct in6_addr *addr;
  176. struct in6_addr *mask;
  177. struct netlbl_domaddr6_map *map;
  178. addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
  179. if (addrmap == NULL) {
  180. ret_val = -ENOMEM;
  181. goto add_doi_put_def;
  182. }
  183. INIT_LIST_HEAD(&addrmap->list4);
  184. INIT_LIST_HEAD(&addrmap->list6);
  185. if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
  186. sizeof(struct in6_addr)) {
  187. ret_val = -EINVAL;
  188. goto add_free_addrmap;
  189. }
  190. if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
  191. sizeof(struct in6_addr)) {
  192. ret_val = -EINVAL;
  193. goto add_free_addrmap;
  194. }
  195. addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
  196. mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
  197. map = kzalloc(sizeof(*map), GFP_KERNEL);
  198. if (map == NULL) {
  199. ret_val = -ENOMEM;
  200. goto add_free_addrmap;
  201. }
  202. pmap = map;
  203. map->list.addr = *addr;
  204. map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
  205. map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
  206. map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
  207. map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
  208. map->list.mask = *mask;
  209. map->list.valid = 1;
  210. map->def.type = entry->def.type;
  211. if (calipso)
  212. map->def.calipso = calipso;
  213. ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
  214. if (ret_val != 0)
  215. goto add_free_map;
  216. entry->family = AF_INET6;
  217. entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
  218. entry->def.addrsel = addrmap;
  219. #endif /* IPv6 */
  220. }
  221. ret_val = netlbl_domhsh_add(entry, audit_info);
  222. if (ret_val != 0)
  223. goto add_free_map;
  224. return 0;
  225. add_free_map:
  226. kfree(pmap);
  227. add_free_addrmap:
  228. kfree(addrmap);
  229. add_doi_put_def:
  230. cipso_v4_doi_putdef(cipsov4);
  231. #if IS_ENABLED(CONFIG_IPV6)
  232. calipso_doi_putdef(calipso);
  233. #endif
  234. add_free_domain:
  235. kfree(entry->domain);
  236. add_free_entry:
  237. kfree(entry);
  238. return ret_val;
  239. }
  240. /**
  241. * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
  242. * @skb: the NETLINK buffer
  243. * @entry: the map entry
  244. *
  245. * Description:
  246. * This function is a helper function used by the LISTALL and LISTDEF command
  247. * handlers. The caller is responsible for ensuring that the RCU read lock
  248. * is held. Returns zero on success, negative values on failure.
  249. *
  250. */
  251. static int netlbl_mgmt_listentry(struct sk_buff *skb,
  252. struct netlbl_dom_map *entry)
  253. {
  254. int ret_val = 0;
  255. struct nlattr *nla_a;
  256. struct nlattr *nla_b;
  257. struct netlbl_af4list *iter4;
  258. #if IS_ENABLED(CONFIG_IPV6)
  259. struct netlbl_af6list *iter6;
  260. #endif
  261. if (entry->domain != NULL) {
  262. ret_val = nla_put_string(skb,
  263. NLBL_MGMT_A_DOMAIN, entry->domain);
  264. if (ret_val != 0)
  265. return ret_val;
  266. }
  267. ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
  268. if (ret_val != 0)
  269. return ret_val;
  270. switch (entry->def.type) {
  271. case NETLBL_NLTYPE_ADDRSELECT:
  272. nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
  273. if (nla_a == NULL)
  274. return -ENOMEM;
  275. netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
  276. struct netlbl_domaddr4_map *map4;
  277. struct in_addr addr_struct;
  278. nla_b = nla_nest_start_noflag(skb,
  279. NLBL_MGMT_A_ADDRSELECTOR);
  280. if (nla_b == NULL)
  281. return -ENOMEM;
  282. addr_struct.s_addr = iter4->addr;
  283. ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
  284. addr_struct.s_addr);
  285. if (ret_val != 0)
  286. return ret_val;
  287. addr_struct.s_addr = iter4->mask;
  288. ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
  289. addr_struct.s_addr);
  290. if (ret_val != 0)
  291. return ret_val;
  292. map4 = netlbl_domhsh_addr4_entry(iter4);
  293. ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  294. map4->def.type);
  295. if (ret_val != 0)
  296. return ret_val;
  297. switch (map4->def.type) {
  298. case NETLBL_NLTYPE_CIPSOV4:
  299. ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
  300. map4->def.cipso->doi);
  301. if (ret_val != 0)
  302. return ret_val;
  303. break;
  304. }
  305. nla_nest_end(skb, nla_b);
  306. }
  307. #if IS_ENABLED(CONFIG_IPV6)
  308. netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
  309. struct netlbl_domaddr6_map *map6;
  310. nla_b = nla_nest_start_noflag(skb,
  311. NLBL_MGMT_A_ADDRSELECTOR);
  312. if (nla_b == NULL)
  313. return -ENOMEM;
  314. ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
  315. &iter6->addr);
  316. if (ret_val != 0)
  317. return ret_val;
  318. ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
  319. &iter6->mask);
  320. if (ret_val != 0)
  321. return ret_val;
  322. map6 = netlbl_domhsh_addr6_entry(iter6);
  323. ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  324. map6->def.type);
  325. if (ret_val != 0)
  326. return ret_val;
  327. switch (map6->def.type) {
  328. case NETLBL_NLTYPE_CALIPSO:
  329. ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
  330. map6->def.calipso->doi);
  331. if (ret_val != 0)
  332. return ret_val;
  333. break;
  334. }
  335. nla_nest_end(skb, nla_b);
  336. }
  337. #endif /* IPv6 */
  338. nla_nest_end(skb, nla_a);
  339. break;
  340. case NETLBL_NLTYPE_UNLABELED:
  341. ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  342. entry->def.type);
  343. break;
  344. case NETLBL_NLTYPE_CIPSOV4:
  345. ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  346. entry->def.type);
  347. if (ret_val != 0)
  348. return ret_val;
  349. ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
  350. entry->def.cipso->doi);
  351. break;
  352. case NETLBL_NLTYPE_CALIPSO:
  353. ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
  354. entry->def.type);
  355. if (ret_val != 0)
  356. return ret_val;
  357. ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
  358. entry->def.calipso->doi);
  359. break;
  360. }
  361. return ret_val;
  362. }
  363. /*
  364. * NetLabel Command Handlers
  365. */
  366. /**
  367. * netlbl_mgmt_add - Handle an ADD message
  368. * @skb: the NETLINK buffer
  369. * @info: the Generic NETLINK info block
  370. *
  371. * Description:
  372. * Process a user generated ADD message and add the domains from the message
  373. * to the hash table. See netlabel.h for a description of the message format.
  374. * Returns zero on success, negative values on failure.
  375. *
  376. */
  377. static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
  378. {
  379. struct netlbl_audit audit_info;
  380. if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
  381. (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
  382. (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
  383. info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
  384. (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
  385. info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
  386. ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
  387. (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
  388. ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
  389. (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
  390. return -EINVAL;
  391. netlbl_netlink_auditinfo(skb, &audit_info);
  392. return netlbl_mgmt_add_common(info, &audit_info);
  393. }
  394. /**
  395. * netlbl_mgmt_remove - Handle a REMOVE message
  396. * @skb: the NETLINK buffer
  397. * @info: the Generic NETLINK info block
  398. *
  399. * Description:
  400. * Process a user generated REMOVE message and remove the specified domain
  401. * mappings. Returns zero on success, negative values on failure.
  402. *
  403. */
  404. static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
  405. {
  406. char *domain;
  407. struct netlbl_audit audit_info;
  408. if (!info->attrs[NLBL_MGMT_A_DOMAIN])
  409. return -EINVAL;
  410. netlbl_netlink_auditinfo(skb, &audit_info);
  411. domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
  412. return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
  413. }
  414. /**
  415. * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
  416. * @entry: the domain mapping hash table entry
  417. * @arg: the netlbl_domhsh_walk_arg structure
  418. *
  419. * Description:
  420. * This function is designed to be used as a callback to the
  421. * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
  422. * message. Returns the size of the message on success, negative values on
  423. * failure.
  424. *
  425. */
  426. static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
  427. {
  428. int ret_val = -ENOMEM;
  429. struct netlbl_domhsh_walk_arg *cb_arg = arg;
  430. void *data;
  431. data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
  432. cb_arg->seq, &netlbl_mgmt_gnl_family,
  433. NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
  434. if (data == NULL)
  435. goto listall_cb_failure;
  436. ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
  437. if (ret_val != 0)
  438. goto listall_cb_failure;
  439. cb_arg->seq++;
  440. genlmsg_end(cb_arg->skb, data);
  441. return 0;
  442. listall_cb_failure:
  443. genlmsg_cancel(cb_arg->skb, data);
  444. return ret_val;
  445. }
  446. /**
  447. * netlbl_mgmt_listall - Handle a LISTALL message
  448. * @skb: the NETLINK buffer
  449. * @cb: the NETLINK callback
  450. *
  451. * Description:
  452. * Process a user generated LISTALL message and dumps the domain hash table in
  453. * a form suitable for use in a kernel generated LISTALL message. Returns zero
  454. * on success, negative values on failure.
  455. *
  456. */
  457. static int netlbl_mgmt_listall(struct sk_buff *skb,
  458. struct netlink_callback *cb)
  459. {
  460. struct netlbl_domhsh_walk_arg cb_arg;
  461. u32 skip_bkt = cb->args[0];
  462. u32 skip_chain = cb->args[1];
  463. cb_arg.nl_cb = cb;
  464. cb_arg.skb = skb;
  465. cb_arg.seq = cb->nlh->nlmsg_seq;
  466. netlbl_domhsh_walk(&skip_bkt,
  467. &skip_chain,
  468. netlbl_mgmt_listall_cb,
  469. &cb_arg);
  470. cb->args[0] = skip_bkt;
  471. cb->args[1] = skip_chain;
  472. return skb->len;
  473. }
  474. /**
  475. * netlbl_mgmt_adddef - Handle an ADDDEF message
  476. * @skb: the NETLINK buffer
  477. * @info: the Generic NETLINK info block
  478. *
  479. * Description:
  480. * Process a user generated ADDDEF message and respond accordingly. Returns
  481. * zero on success, negative values on failure.
  482. *
  483. */
  484. static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
  485. {
  486. struct netlbl_audit audit_info;
  487. if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
  488. (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
  489. info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
  490. (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
  491. info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
  492. ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
  493. (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
  494. ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
  495. (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
  496. return -EINVAL;
  497. netlbl_netlink_auditinfo(skb, &audit_info);
  498. return netlbl_mgmt_add_common(info, &audit_info);
  499. }
  500. /**
  501. * netlbl_mgmt_removedef - Handle a REMOVEDEF message
  502. * @skb: the NETLINK buffer
  503. * @info: the Generic NETLINK info block
  504. *
  505. * Description:
  506. * Process a user generated REMOVEDEF message and remove the default domain
  507. * mapping. Returns zero on success, negative values on failure.
  508. *
  509. */
  510. static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
  511. {
  512. struct netlbl_audit audit_info;
  513. netlbl_netlink_auditinfo(skb, &audit_info);
  514. return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
  515. }
  516. /**
  517. * netlbl_mgmt_listdef - Handle a LISTDEF message
  518. * @skb: the NETLINK buffer
  519. * @info: the Generic NETLINK info block
  520. *
  521. * Description:
  522. * Process a user generated LISTDEF message and dumps the default domain
  523. * mapping in a form suitable for use in a kernel generated LISTDEF message.
  524. * Returns zero on success, negative values on failure.
  525. *
  526. */
  527. static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
  528. {
  529. int ret_val = -ENOMEM;
  530. struct sk_buff *ans_skb = NULL;
  531. void *data;
  532. struct netlbl_dom_map *entry;
  533. u16 family;
  534. if (info->attrs[NLBL_MGMT_A_FAMILY])
  535. family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
  536. else
  537. family = AF_INET;
  538. ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  539. if (ans_skb == NULL)
  540. return -ENOMEM;
  541. data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
  542. 0, NLBL_MGMT_C_LISTDEF);
  543. if (data == NULL)
  544. goto listdef_failure;
  545. rcu_read_lock();
  546. entry = netlbl_domhsh_getentry(NULL, family);
  547. if (entry == NULL) {
  548. ret_val = -ENOENT;
  549. goto listdef_failure_lock;
  550. }
  551. ret_val = netlbl_mgmt_listentry(ans_skb, entry);
  552. rcu_read_unlock();
  553. if (ret_val != 0)
  554. goto listdef_failure;
  555. genlmsg_end(ans_skb, data);
  556. return genlmsg_reply(ans_skb, info);
  557. listdef_failure_lock:
  558. rcu_read_unlock();
  559. listdef_failure:
  560. kfree_skb(ans_skb);
  561. return ret_val;
  562. }
  563. /**
  564. * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
  565. * @skb: the skb to write to
  566. * @cb: the NETLINK callback
  567. * @protocol: the NetLabel protocol to use in the message
  568. *
  569. * Description:
  570. * This function is to be used in conjunction with netlbl_mgmt_protocols() to
  571. * answer a application's PROTOCOLS message. Returns the size of the message
  572. * on success, negative values on failure.
  573. *
  574. */
  575. static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
  576. struct netlink_callback *cb,
  577. u32 protocol)
  578. {
  579. int ret_val = -ENOMEM;
  580. void *data;
  581. data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
  582. &netlbl_mgmt_gnl_family, NLM_F_MULTI,
  583. NLBL_MGMT_C_PROTOCOLS);
  584. if (data == NULL)
  585. goto protocols_cb_failure;
  586. ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
  587. if (ret_val != 0)
  588. goto protocols_cb_failure;
  589. genlmsg_end(skb, data);
  590. return 0;
  591. protocols_cb_failure:
  592. genlmsg_cancel(skb, data);
  593. return ret_val;
  594. }
  595. /**
  596. * netlbl_mgmt_protocols - Handle a PROTOCOLS message
  597. * @skb: the NETLINK buffer
  598. * @cb: the NETLINK callback
  599. *
  600. * Description:
  601. * Process a user generated PROTOCOLS message and respond accordingly.
  602. *
  603. */
  604. static int netlbl_mgmt_protocols(struct sk_buff *skb,
  605. struct netlink_callback *cb)
  606. {
  607. u32 protos_sent = cb->args[0];
  608. if (protos_sent == 0) {
  609. if (netlbl_mgmt_protocols_cb(skb,
  610. cb,
  611. NETLBL_NLTYPE_UNLABELED) < 0)
  612. goto protocols_return;
  613. protos_sent++;
  614. }
  615. if (protos_sent == 1) {
  616. if (netlbl_mgmt_protocols_cb(skb,
  617. cb,
  618. NETLBL_NLTYPE_CIPSOV4) < 0)
  619. goto protocols_return;
  620. protos_sent++;
  621. }
  622. #if IS_ENABLED(CONFIG_IPV6)
  623. if (protos_sent == 2) {
  624. if (netlbl_mgmt_protocols_cb(skb,
  625. cb,
  626. NETLBL_NLTYPE_CALIPSO) < 0)
  627. goto protocols_return;
  628. protos_sent++;
  629. }
  630. #endif
  631. protocols_return:
  632. cb->args[0] = protos_sent;
  633. return skb->len;
  634. }
  635. /**
  636. * netlbl_mgmt_version - Handle a VERSION message
  637. * @skb: the NETLINK buffer
  638. * @info: the Generic NETLINK info block
  639. *
  640. * Description:
  641. * Process a user generated VERSION message and respond accordingly. Returns
  642. * zero on success, negative values on failure.
  643. *
  644. */
  645. static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
  646. {
  647. int ret_val = -ENOMEM;
  648. struct sk_buff *ans_skb = NULL;
  649. void *data;
  650. ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  651. if (ans_skb == NULL)
  652. return -ENOMEM;
  653. data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
  654. 0, NLBL_MGMT_C_VERSION);
  655. if (data == NULL)
  656. goto version_failure;
  657. ret_val = nla_put_u32(ans_skb,
  658. NLBL_MGMT_A_VERSION,
  659. NETLBL_PROTO_VERSION);
  660. if (ret_val != 0)
  661. goto version_failure;
  662. genlmsg_end(ans_skb, data);
  663. return genlmsg_reply(ans_skb, info);
  664. version_failure:
  665. kfree_skb(ans_skb);
  666. return ret_val;
  667. }
  668. /*
  669. * NetLabel Generic NETLINK Command Definitions
  670. */
  671. static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
  672. {
  673. .cmd = NLBL_MGMT_C_ADD,
  674. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  675. .flags = GENL_ADMIN_PERM,
  676. .doit = netlbl_mgmt_add,
  677. .dumpit = NULL,
  678. },
  679. {
  680. .cmd = NLBL_MGMT_C_REMOVE,
  681. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  682. .flags = GENL_ADMIN_PERM,
  683. .doit = netlbl_mgmt_remove,
  684. .dumpit = NULL,
  685. },
  686. {
  687. .cmd = NLBL_MGMT_C_LISTALL,
  688. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  689. .flags = 0,
  690. .doit = NULL,
  691. .dumpit = netlbl_mgmt_listall,
  692. },
  693. {
  694. .cmd = NLBL_MGMT_C_ADDDEF,
  695. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  696. .flags = GENL_ADMIN_PERM,
  697. .doit = netlbl_mgmt_adddef,
  698. .dumpit = NULL,
  699. },
  700. {
  701. .cmd = NLBL_MGMT_C_REMOVEDEF,
  702. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  703. .flags = GENL_ADMIN_PERM,
  704. .doit = netlbl_mgmt_removedef,
  705. .dumpit = NULL,
  706. },
  707. {
  708. .cmd = NLBL_MGMT_C_LISTDEF,
  709. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  710. .flags = 0,
  711. .doit = netlbl_mgmt_listdef,
  712. .dumpit = NULL,
  713. },
  714. {
  715. .cmd = NLBL_MGMT_C_PROTOCOLS,
  716. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  717. .flags = 0,
  718. .doit = NULL,
  719. .dumpit = netlbl_mgmt_protocols,
  720. },
  721. {
  722. .cmd = NLBL_MGMT_C_VERSION,
  723. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  724. .flags = 0,
  725. .doit = netlbl_mgmt_version,
  726. .dumpit = NULL,
  727. },
  728. };
  729. static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
  730. .hdrsize = 0,
  731. .name = NETLBL_NLTYPE_MGMT_NAME,
  732. .version = NETLBL_PROTO_VERSION,
  733. .maxattr = NLBL_MGMT_A_MAX,
  734. .policy = netlbl_mgmt_genl_policy,
  735. .module = THIS_MODULE,
  736. .small_ops = netlbl_mgmt_genl_ops,
  737. .n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
  738. };
  739. /*
  740. * NetLabel Generic NETLINK Protocol Functions
  741. */
  742. /**
  743. * netlbl_mgmt_genl_init - Register the NetLabel management component
  744. *
  745. * Description:
  746. * Register the NetLabel management component with the Generic NETLINK
  747. * mechanism. Returns zero on success, negative values on failure.
  748. *
  749. */
  750. int __init netlbl_mgmt_genl_init(void)
  751. {
  752. return genl_register_family(&netlbl_mgmt_gnl_family);
  753. }