diff options
Diffstat (limited to 'net/netlabel/netlabel_cipso_v4.c')
| -rw-r--r-- | net/netlabel/netlabel_cipso_v4.c | 222 |
1 files changed, 114 insertions, 108 deletions
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index fdc14a0d21a..c2f2a53a487 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -5,7 +5,7 @@ * NetLabel system manages static and dynamic label mappings for network * protocols such as CIPSO and RIPSO. * - * Author: Paul Moore <paul.moore@hp.com> + * Author: Paul Moore <paul@paul-moore.com> * */ @@ -23,8 +23,7 @@ * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * */ @@ -33,16 +32,18 @@ #include <linux/string.h> #include <linux/skbuff.h> #include <linux/audit.h> +#include <linux/slab.h> #include <net/sock.h> #include <net/netlink.h> #include <net/genetlink.h> #include <net/netlabel.h> #include <net/cipso_ipv4.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include "netlabel_user.h" #include "netlabel_cipso_v4.h" #include "netlabel_mgmt.h" +#include "netlabel_domainhash.h" /* Argument struct for cipso_v4_doi_walk() */ struct netlbl_cipsov4_doiwalk_arg { @@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg { u32 seq; }; +/* Argument struct for netlbl_domhsh_walk() */ +struct netlbl_domhsh_walk_arg { + struct netlbl_audit *audit_info; + u32 doi; +}; + /* NetLabel Generic NETLINK CIPSOv4 family */ static struct genl_family netlbl_cipsov4_gnl_family = { .id = GENL_ID_GENERATE, @@ -81,32 +88,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1 */ /** - * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition - * @entry: the entry's RCU field - * - * Description: - * This function is designed to be used as a callback to the call_rcu() - * function so that the memory allocated to the DOI definition can be released - * safely. - * - */ -void netlbl_cipsov4_doi_free(struct rcu_head *entry) -{ - struct cipso_v4_doi *ptr; - - ptr = container_of(entry, struct cipso_v4_doi, rcu); - switch (ptr->type) { - case CIPSO_V4_MAP_STD: - kfree(ptr->map.std->lvl.cipso); - kfree(ptr->map.std->lvl.local); - kfree(ptr->map.std->cat.cipso); - kfree(ptr->map.std->cat.local); - break; - } - kfree(ptr); -} - -/** * netlbl_cipsov4_add_common - Parse the common sections of a ADD message * @info: the Generic NETLINK info block * @doi_def: the CIPSO V4 DOI definition @@ -149,14 +130,16 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, /** * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition * @info: the Generic NETLINK info block + * @audit_info: NetLabel audit information * * Description: - * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message - * and add it to the CIPSO V4 engine. Return zero on success and non-zero on - * error. + * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD + * message and add it to the CIPSO V4 engine. Return zero on success and + * non-zero on error. * */ -static int netlbl_cipsov4_add_std(struct genl_info *info) +static int netlbl_cipsov4_add_std(struct genl_info *info, + struct netlbl_audit *audit_info) { int ret_val = -EINVAL; struct cipso_v4_doi *doi_def = NULL; @@ -183,7 +166,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) ret_val = -ENOMEM; goto add_std_failure; } - doi_def->type = CIPSO_V4_MAP_STD; + doi_def->type = CIPSO_V4_MAP_TRANS; ret_val = netlbl_cipsov4_add_common(info, doi_def); if (ret_val != 0) @@ -335,20 +318,21 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) } } - ret_val = cipso_v4_doi_add(doi_def); + ret_val = cipso_v4_doi_add(doi_def, audit_info); if (ret_val != 0) goto add_std_failure; return 0; add_std_failure: if (doi_def) - netlbl_cipsov4_doi_free(&doi_def->rcu); + cipso_v4_doi_free(doi_def); return ret_val; } /** * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition * @info: the Generic NETLINK info block + * @audit_info: NetLabel audit information * * Description: * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message @@ -356,7 +340,8 @@ add_std_failure: * error. * */ -static int netlbl_cipsov4_add_pass(struct genl_info *info) +static int netlbl_cipsov4_add_pass(struct genl_info *info, + struct netlbl_audit *audit_info) { int ret_val; struct cipso_v4_doi *doi_def = NULL; @@ -373,13 +358,52 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info) if (ret_val != 0) goto add_pass_failure; - ret_val = cipso_v4_doi_add(doi_def); + ret_val = cipso_v4_doi_add(doi_def, audit_info); if (ret_val != 0) goto add_pass_failure; return 0; add_pass_failure: - netlbl_cipsov4_doi_free(&doi_def->rcu); + cipso_v4_doi_free(doi_def); + return ret_val; +} + +/** + * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition + * @info: the Generic NETLINK info block + * @audit_info: NetLabel audit information + * + * Description: + * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD + * message and add it to the CIPSO V4 engine. Return zero on success and + * non-zero on error. + * + */ +static int netlbl_cipsov4_add_local(struct genl_info *info, + struct netlbl_audit *audit_info) +{ + int ret_val; + struct cipso_v4_doi *doi_def = NULL; + + if (!info->attrs[NLBL_CIPSOV4_A_TAGLST]) + return -EINVAL; + + doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); + if (doi_def == NULL) + return -ENOMEM; + doi_def->type = CIPSO_V4_MAP_LOCAL; + + ret_val = netlbl_cipsov4_add_common(info, doi_def); + if (ret_val != 0) + goto add_local_failure; + + ret_val = cipso_v4_doi_add(doi_def, audit_info); + if (ret_val != 0) + goto add_local_failure; + return 0; + +add_local_failure: + cipso_v4_doi_free(doi_def); return ret_val; } @@ -397,44 +421,27 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; - u32 type; - u32 doi; - const char *type_str = "(unknown)"; - struct audit_buffer *audit_buf; struct netlbl_audit audit_info; if (!info->attrs[NLBL_CIPSOV4_A_DOI] || !info->attrs[NLBL_CIPSOV4_A_MTYPE]) return -EINVAL; - doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); netlbl_netlink_auditinfo(skb, &audit_info); - - type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); - switch (type) { - case CIPSO_V4_MAP_STD: - type_str = "std"; - ret_val = netlbl_cipsov4_add_std(info); + switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) { + case CIPSO_V4_MAP_TRANS: + ret_val = netlbl_cipsov4_add_std(info, &audit_info); break; case CIPSO_V4_MAP_PASS: - type_str = "pass"; - ret_val = netlbl_cipsov4_add_pass(info); + ret_val = netlbl_cipsov4_add_pass(info, &audit_info); + break; + case CIPSO_V4_MAP_LOCAL: + ret_val = netlbl_cipsov4_add_local(info, &audit_info); break; } if (ret_val == 0) atomic_inc(&netlabel_mgmt_protocount); - audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, - &audit_info); - if (audit_buf != NULL) { - audit_log_format(audit_buf, - " cipso_doi=%u cipso_type=%s res=%u", - doi, - type_str, - ret_val == 0 ? 1 : 0); - audit_log_end(audit_buf); - } - return ret_val; } @@ -491,7 +498,7 @@ list_start: doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { ret_val = -EINVAL; - goto list_failure; + goto list_failure_lock; } ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); @@ -516,7 +523,7 @@ list_start: nla_nest_end(ans_skb, nla_a); switch (doi_def->type) { - case CIPSO_V4_MAP_STD: + case CIPSO_V4_MAP_TRANS: nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); if (nla_a == NULL) { ret_val = -ENOMEM; @@ -584,19 +591,14 @@ list_start: rcu_read_unlock(); genlmsg_end(ans_skb, data); - - ret_val = genlmsg_reply(ans_skb, info); - if (ret_val != 0) - goto list_failure; - - return 0; + return genlmsg_reply(ans_skb, info); list_retry: /* XXX - this limit is a guesstimate */ if (nlsze_mult < 4) { rcu_read_unlock(); kfree_skb(ans_skb); - nlsze_mult++; + nlsze_mult *= 2; goto list_start; } list_failure_lock: @@ -624,7 +626,7 @@ static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg) struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg; void *data; - data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid, + data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, cb_arg->seq, &netlbl_cipsov4_gnl_family, NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL); if (data == NULL) @@ -660,7 +662,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, struct netlink_callback *cb) { struct netlbl_cipsov4_doiwalk_arg cb_arg; - int doi_skip = cb->args[0]; + u32 doi_skip = cb->args[0]; cb_arg.nl_cb = cb; cb_arg.skb = skb; @@ -673,6 +675,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, } /** + * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE + * @entry: LSM domain mapping entry + * @arg: the netlbl_domhsh_walk_arg structure + * + * Description: + * This function is intended for use by netlbl_cipsov4_remove() as the callback + * for the netlbl_domhsh_walk() function; it removes LSM domain map entries + * which are associated with the CIPSO DOI specified in @arg. Returns zero on + * success, negative values on failure. + * + */ +static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg) +{ + struct netlbl_domhsh_walk_arg *cb_arg = arg; + + if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 && + entry->def.cipso->doi == cb_arg->doi) + return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info); + + return 0; +} + +/** * netlbl_cipsov4_remove - Handle a REMOVE message * @skb: the NETLINK buffer * @info: the Generic NETLINK info block @@ -685,30 +710,23 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; - u32 doi = 0; - struct audit_buffer *audit_buf; + struct netlbl_domhsh_walk_arg cb_arg; struct netlbl_audit audit_info; + u32 skip_bkt = 0; + u32 skip_chain = 0; if (!info->attrs[NLBL_CIPSOV4_A_DOI]) return -EINVAL; - doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); netlbl_netlink_auditinfo(skb, &audit_info); - - ret_val = cipso_v4_doi_remove(doi, - &audit_info, - netlbl_cipsov4_doi_free); - if (ret_val == 0) - atomic_dec(&netlabel_mgmt_protocount); - - audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, - &audit_info); - if (audit_buf != NULL) { - audit_log_format(audit_buf, - " cipso_doi=%u res=%u", - doi, - ret_val == 0 ? 1 : 0); - audit_log_end(audit_buf); + cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); + cb_arg.audit_info = &audit_info; + ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, + netlbl_cipsov4_remove_cb, &cb_arg); + if (ret_val == 0 || ret_val == -ENOENT) { + ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info); + if (ret_val == 0) + atomic_dec(&netlabel_mgmt_protocount); } return ret_val; @@ -718,7 +736,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_cipsov4_ops[] = { +static const struct genl_ops netlbl_cipsov4_ops[] = { { .cmd = NLBL_CIPSOV4_C_ADD, .flags = GENL_ADMIN_PERM, @@ -763,18 +781,6 @@ static struct genl_ops netlbl_cipsov4_ops[] = { */ int __init netlbl_cipsov4_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_cipsov4_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_cipsov4_ops); i++) { - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family, + netlbl_cipsov4_ops); } |
