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