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