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