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