diff options
Diffstat (limited to 'net/netlabel/netlabel_cipso_v4.c')
-rw-r--r-- | net/netlabel/netlabel_cipso_v4.c | 136 |
1 files changed, 94 insertions, 42 deletions
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 0aec318bf0ef..fff32b70efa9 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include "netlabel_user.h" | 43 | #include "netlabel_user.h" |
44 | #include "netlabel_cipso_v4.h" | 44 | #include "netlabel_cipso_v4.h" |
45 | #include "netlabel_mgmt.h" | 45 | #include "netlabel_mgmt.h" |
46 | #include "netlabel_domainhash.h" | ||
46 | 47 | ||
47 | /* Argument struct for cipso_v4_doi_walk() */ | 48 | /* Argument struct for cipso_v4_doi_walk() */ |
48 | struct netlbl_cipsov4_doiwalk_arg { | 49 | struct netlbl_cipsov4_doiwalk_arg { |
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg { | |||
51 | u32 seq; | 52 | u32 seq; |
52 | }; | 53 | }; |
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 | |||
54 | /* NetLabel Generic NETLINK CIPSOv4 family */ | 61 | /* NetLabel Generic NETLINK CIPSOv4 family */ |
55 | static struct genl_family netlbl_cipsov4_gnl_family = { | 62 | static struct genl_family netlbl_cipsov4_gnl_family = { |
56 | .id = GENL_ID_GENERATE, | 63 | .id = GENL_ID_GENERATE, |
@@ -81,32 +88,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1 | |||
81 | */ | 88 | */ |
82 | 89 | ||
83 | /** | 90 | /** |
84 | * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition | ||
85 | * @entry: the entry's RCU field | ||
86 | * | ||
87 | * Description: | ||
88 | * This function is designed to be used as a callback to the call_rcu() | ||
89 | * function so that the memory allocated to the DOI definition can be released | ||
90 | * safely. | ||
91 | * | ||
92 | */ | ||
93 | void netlbl_cipsov4_doi_free(struct rcu_head *entry) | ||
94 | { | ||
95 | struct cipso_v4_doi *ptr; | ||
96 | |||
97 | ptr = container_of(entry, struct cipso_v4_doi, rcu); | ||
98 | switch (ptr->type) { | ||
99 | case CIPSO_V4_MAP_STD: | ||
100 | kfree(ptr->map.std->lvl.cipso); | ||
101 | kfree(ptr->map.std->lvl.local); | ||
102 | kfree(ptr->map.std->cat.cipso); | ||
103 | kfree(ptr->map.std->cat.local); | ||
104 | break; | ||
105 | } | ||
106 | kfree(ptr); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * netlbl_cipsov4_add_common - Parse the common sections of a ADD message | 91 | * netlbl_cipsov4_add_common - Parse the common sections of a ADD message |
111 | * @info: the Generic NETLINK info block | 92 | * @info: the Generic NETLINK info block |
112 | * @doi_def: the CIPSO V4 DOI definition | 93 | * @doi_def: the CIPSO V4 DOI definition |
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, | |||
151 | * @info: the Generic NETLINK info block | 132 | * @info: the Generic NETLINK info block |
152 | * | 133 | * |
153 | * Description: | 134 | * Description: |
154 | * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message | 135 | * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD |
155 | * and add it to the CIPSO V4 engine. Return zero on success and non-zero on | 136 | * message and add it to the CIPSO V4 engine. Return zero on success and |
156 | * error. | 137 | * non-zero on error. |
157 | * | 138 | * |
158 | */ | 139 | */ |
159 | static int netlbl_cipsov4_add_std(struct genl_info *info) | 140 | static int netlbl_cipsov4_add_std(struct genl_info *info) |
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) | |||
183 | ret_val = -ENOMEM; | 164 | ret_val = -ENOMEM; |
184 | goto add_std_failure; | 165 | goto add_std_failure; |
185 | } | 166 | } |
186 | doi_def->type = CIPSO_V4_MAP_STD; | 167 | doi_def->type = CIPSO_V4_MAP_TRANS; |
187 | 168 | ||
188 | ret_val = netlbl_cipsov4_add_common(info, doi_def); | 169 | ret_val = netlbl_cipsov4_add_common(info, doi_def); |
189 | if (ret_val != 0) | 170 | if (ret_val != 0) |
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) | |||
342 | 323 | ||
343 | add_std_failure: | 324 | add_std_failure: |
344 | if (doi_def) | 325 | if (doi_def) |
345 | netlbl_cipsov4_doi_free(&doi_def->rcu); | 326 | cipso_v4_doi_free(doi_def); |
346 | return ret_val; | 327 | return ret_val; |
347 | } | 328 | } |
348 | 329 | ||
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info) | |||
379 | return 0; | 360 | return 0; |
380 | 361 | ||
381 | add_pass_failure: | 362 | add_pass_failure: |
382 | netlbl_cipsov4_doi_free(&doi_def->rcu); | 363 | cipso_v4_doi_free(doi_def); |
364 | return ret_val; | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition | ||
369 | * @info: the Generic NETLINK info block | ||
370 | * | ||
371 | * Description: | ||
372 | * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD | ||
373 | * message and add it to the CIPSO V4 engine. Return zero on success and | ||
374 | * non-zero on error. | ||
375 | * | ||
376 | */ | ||
377 | static int netlbl_cipsov4_add_local(struct genl_info *info) | ||
378 | { | ||
379 | int ret_val; | ||
380 | struct cipso_v4_doi *doi_def = NULL; | ||
381 | |||
382 | if (!info->attrs[NLBL_CIPSOV4_A_TAGLST]) | ||
383 | return -EINVAL; | ||
384 | |||
385 | doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); | ||
386 | if (doi_def == NULL) | ||
387 | return -ENOMEM; | ||
388 | doi_def->type = CIPSO_V4_MAP_LOCAL; | ||
389 | |||
390 | ret_val = netlbl_cipsov4_add_common(info, doi_def); | ||
391 | if (ret_val != 0) | ||
392 | goto add_local_failure; | ||
393 | |||
394 | ret_val = cipso_v4_doi_add(doi_def); | ||
395 | if (ret_val != 0) | ||
396 | goto add_local_failure; | ||
397 | return 0; | ||
398 | |||
399 | add_local_failure: | ||
400 | cipso_v4_doi_free(doi_def); | ||
383 | return ret_val; | 401 | return ret_val; |
384 | } | 402 | } |
385 | 403 | ||
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) | |||
412 | 430 | ||
413 | type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); | 431 | type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); |
414 | switch (type) { | 432 | switch (type) { |
415 | case CIPSO_V4_MAP_STD: | 433 | case CIPSO_V4_MAP_TRANS: |
416 | type_str = "std"; | 434 | type_str = "trans"; |
417 | ret_val = netlbl_cipsov4_add_std(info); | 435 | ret_val = netlbl_cipsov4_add_std(info); |
418 | break; | 436 | break; |
419 | case CIPSO_V4_MAP_PASS: | 437 | case CIPSO_V4_MAP_PASS: |
420 | type_str = "pass"; | 438 | type_str = "pass"; |
421 | ret_val = netlbl_cipsov4_add_pass(info); | 439 | ret_val = netlbl_cipsov4_add_pass(info); |
422 | break; | 440 | break; |
441 | case CIPSO_V4_MAP_LOCAL: | ||
442 | type_str = "local"; | ||
443 | ret_val = netlbl_cipsov4_add_local(info); | ||
444 | break; | ||
423 | } | 445 | } |
424 | if (ret_val == 0) | 446 | if (ret_val == 0) |
425 | atomic_inc(&netlabel_mgmt_protocount); | 447 | atomic_inc(&netlabel_mgmt_protocount); |
@@ -491,7 +513,7 @@ list_start: | |||
491 | doi_def = cipso_v4_doi_getdef(doi); | 513 | doi_def = cipso_v4_doi_getdef(doi); |
492 | if (doi_def == NULL) { | 514 | if (doi_def == NULL) { |
493 | ret_val = -EINVAL; | 515 | ret_val = -EINVAL; |
494 | goto list_failure; | 516 | goto list_failure_lock; |
495 | } | 517 | } |
496 | 518 | ||
497 | ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); | 519 | ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); |
@@ -516,7 +538,7 @@ list_start: | |||
516 | nla_nest_end(ans_skb, nla_a); | 538 | nla_nest_end(ans_skb, nla_a); |
517 | 539 | ||
518 | switch (doi_def->type) { | 540 | switch (doi_def->type) { |
519 | case CIPSO_V4_MAP_STD: | 541 | case CIPSO_V4_MAP_TRANS: |
520 | nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); | 542 | nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); |
521 | if (nla_a == NULL) { | 543 | if (nla_a == NULL) { |
522 | ret_val = -ENOMEM; | 544 | ret_val = -ENOMEM; |
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, | |||
655 | struct netlink_callback *cb) | 677 | struct netlink_callback *cb) |
656 | { | 678 | { |
657 | struct netlbl_cipsov4_doiwalk_arg cb_arg; | 679 | struct netlbl_cipsov4_doiwalk_arg cb_arg; |
658 | int doi_skip = cb->args[0]; | 680 | u32 doi_skip = cb->args[0]; |
659 | 681 | ||
660 | cb_arg.nl_cb = cb; | 682 | cb_arg.nl_cb = cb; |
661 | cb_arg.skb = skb; | 683 | cb_arg.skb = skb; |
@@ -668,6 +690,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, | |||
668 | } | 690 | } |
669 | 691 | ||
670 | /** | 692 | /** |
693 | * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE | ||
694 | * @entry: LSM domain mapping entry | ||
695 | * @arg: the netlbl_domhsh_walk_arg structure | ||
696 | * | ||
697 | * Description: | ||
698 | * This function is intended for use by netlbl_cipsov4_remove() as the callback | ||
699 | * for the netlbl_domhsh_walk() function; it removes LSM domain map entries | ||
700 | * which are associated with the CIPSO DOI specified in @arg. Returns zero on | ||
701 | * success, negative values on failure. | ||
702 | * | ||
703 | */ | ||
704 | static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg) | ||
705 | { | ||
706 | struct netlbl_domhsh_walk_arg *cb_arg = arg; | ||
707 | |||
708 | if (entry->type == NETLBL_NLTYPE_CIPSOV4 && | ||
709 | entry->type_def.cipsov4->doi == cb_arg->doi) | ||
710 | return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info); | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | /** | ||
671 | * netlbl_cipsov4_remove - Handle a REMOVE message | 716 | * netlbl_cipsov4_remove - Handle a REMOVE message |
672 | * @skb: the NETLINK buffer | 717 | * @skb: the NETLINK buffer |
673 | * @info: the Generic NETLINK info block | 718 | * @info: the Generic NETLINK info block |
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | |||
681 | { | 726 | { |
682 | int ret_val = -EINVAL; | 727 | int ret_val = -EINVAL; |
683 | u32 doi = 0; | 728 | u32 doi = 0; |
729 | struct netlbl_domhsh_walk_arg cb_arg; | ||
684 | struct audit_buffer *audit_buf; | 730 | struct audit_buffer *audit_buf; |
685 | struct netlbl_audit audit_info; | 731 | struct netlbl_audit audit_info; |
732 | u32 skip_bkt = 0; | ||
733 | u32 skip_chain = 0; | ||
686 | 734 | ||
687 | if (!info->attrs[NLBL_CIPSOV4_A_DOI]) | 735 | if (!info->attrs[NLBL_CIPSOV4_A_DOI]) |
688 | return -EINVAL; | 736 | return -EINVAL; |
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | |||
690 | doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); | 738 | doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); |
691 | netlbl_netlink_auditinfo(skb, &audit_info); | 739 | netlbl_netlink_auditinfo(skb, &audit_info); |
692 | 740 | ||
693 | ret_val = cipso_v4_doi_remove(doi, | 741 | cb_arg.doi = doi; |
694 | &audit_info, | 742 | cb_arg.audit_info = &audit_info; |
695 | netlbl_cipsov4_doi_free); | 743 | ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, |
696 | if (ret_val == 0) | 744 | netlbl_cipsov4_remove_cb, &cb_arg); |
697 | atomic_dec(&netlabel_mgmt_protocount); | 745 | if (ret_val == 0 || ret_val == -ENOENT) { |
746 | ret_val = cipso_v4_doi_remove(doi, &audit_info); | ||
747 | if (ret_val == 0) | ||
748 | atomic_dec(&netlabel_mgmt_protocount); | ||
749 | } | ||
698 | 750 | ||
699 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, | 751 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, |
700 | &audit_info); | 752 | &audit_info); |