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