Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * NetLabel Management Support
0004  *
0005  * This file defines the management functions for the NetLabel system.  The
0006  * NetLabel system manages static and dynamic label mappings for network
0007  * protocols such as CIPSO and RIPSO.
0008  *
0009  * Author: Paul Moore <paul@paul-moore.com>
0010  */
0011 
0012 /*
0013  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
0014  */
0015 
0016 #include <linux/types.h>
0017 #include <linux/socket.h>
0018 #include <linux/string.h>
0019 #include <linux/skbuff.h>
0020 #include <linux/in.h>
0021 #include <linux/in6.h>
0022 #include <linux/slab.h>
0023 #include <net/sock.h>
0024 #include <net/netlink.h>
0025 #include <net/genetlink.h>
0026 #include <net/ip.h>
0027 #include <net/ipv6.h>
0028 #include <net/netlabel.h>
0029 #include <net/cipso_ipv4.h>
0030 #include <net/calipso.h>
0031 #include <linux/atomic.h>
0032 
0033 #include "netlabel_calipso.h"
0034 #include "netlabel_domainhash.h"
0035 #include "netlabel_user.h"
0036 #include "netlabel_mgmt.h"
0037 
0038 /* NetLabel configured protocol counter */
0039 atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
0040 
0041 /* Argument struct for netlbl_domhsh_walk() */
0042 struct netlbl_domhsh_walk_arg {
0043     struct netlink_callback *nl_cb;
0044     struct sk_buff *skb;
0045     u32 seq;
0046 };
0047 
0048 /* NetLabel Generic NETLINK CIPSOv4 family */
0049 static struct genl_family netlbl_mgmt_gnl_family;
0050 
0051 /* NetLabel Netlink attribute policy */
0052 static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
0053     [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
0054     [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
0055     [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
0056     [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
0057     [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
0058     [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
0059 };
0060 
0061 /*
0062  * Helper Functions
0063  */
0064 
0065 /**
0066  * netlbl_mgmt_add_common - Handle an ADD message
0067  * @info: the Generic NETLINK info block
0068  * @audit_info: NetLabel audit information
0069  *
0070  * Description:
0071  * Helper function for the ADD and ADDDEF messages to add the domain mappings
0072  * from the message to the hash table.  See netlabel.h for a description of the
0073  * message format.  Returns zero on success, negative values on failure.
0074  *
0075  */
0076 static int netlbl_mgmt_add_common(struct genl_info *info,
0077                   struct netlbl_audit *audit_info)
0078 {
0079     void *pmap = NULL;
0080     int ret_val = -EINVAL;
0081     struct netlbl_domaddr_map *addrmap = NULL;
0082     struct cipso_v4_doi *cipsov4 = NULL;
0083 #if IS_ENABLED(CONFIG_IPV6)
0084     struct calipso_doi *calipso = NULL;
0085 #endif
0086     u32 tmp_val;
0087     struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0088 
0089     if (!entry)
0090         return -ENOMEM;
0091     entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
0092     if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
0093         size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
0094         entry->domain = kmalloc(tmp_size, GFP_KERNEL);
0095         if (entry->domain == NULL) {
0096             ret_val = -ENOMEM;
0097             goto add_free_entry;
0098         }
0099         nla_strscpy(entry->domain,
0100                 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
0101     }
0102 
0103     /* NOTE: internally we allow/use a entry->def.type value of
0104      *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
0105      *       to pass that as a protocol value because we need to know the
0106      *       "real" protocol */
0107 
0108     switch (entry->def.type) {
0109     case NETLBL_NLTYPE_UNLABELED:
0110         if (info->attrs[NLBL_MGMT_A_FAMILY])
0111             entry->family =
0112                 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
0113         else
0114             entry->family = AF_UNSPEC;
0115         break;
0116     case NETLBL_NLTYPE_CIPSOV4:
0117         if (!info->attrs[NLBL_MGMT_A_CV4DOI])
0118             goto add_free_domain;
0119 
0120         tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
0121         cipsov4 = cipso_v4_doi_getdef(tmp_val);
0122         if (cipsov4 == NULL)
0123             goto add_free_domain;
0124         entry->family = AF_INET;
0125         entry->def.cipso = cipsov4;
0126         break;
0127 #if IS_ENABLED(CONFIG_IPV6)
0128     case NETLBL_NLTYPE_CALIPSO:
0129         if (!info->attrs[NLBL_MGMT_A_CLPDOI])
0130             goto add_free_domain;
0131 
0132         tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
0133         calipso = calipso_doi_getdef(tmp_val);
0134         if (calipso == NULL)
0135             goto add_free_domain;
0136         entry->family = AF_INET6;
0137         entry->def.calipso = calipso;
0138         break;
0139 #endif /* IPv6 */
0140     default:
0141         goto add_free_domain;
0142     }
0143 
0144     if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
0145         (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
0146         goto add_doi_put_def;
0147 
0148     if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
0149         struct in_addr *addr;
0150         struct in_addr *mask;
0151         struct netlbl_domaddr4_map *map;
0152 
0153         addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
0154         if (addrmap == NULL) {
0155             ret_val = -ENOMEM;
0156             goto add_doi_put_def;
0157         }
0158         INIT_LIST_HEAD(&addrmap->list4);
0159         INIT_LIST_HEAD(&addrmap->list6);
0160 
0161         if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
0162             sizeof(struct in_addr)) {
0163             ret_val = -EINVAL;
0164             goto add_free_addrmap;
0165         }
0166         if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
0167             sizeof(struct in_addr)) {
0168             ret_val = -EINVAL;
0169             goto add_free_addrmap;
0170         }
0171         addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
0172         mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
0173 
0174         map = kzalloc(sizeof(*map), GFP_KERNEL);
0175         if (map == NULL) {
0176             ret_val = -ENOMEM;
0177             goto add_free_addrmap;
0178         }
0179         pmap = map;
0180         map->list.addr = addr->s_addr & mask->s_addr;
0181         map->list.mask = mask->s_addr;
0182         map->list.valid = 1;
0183         map->def.type = entry->def.type;
0184         if (cipsov4)
0185             map->def.cipso = cipsov4;
0186 
0187         ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
0188         if (ret_val != 0)
0189             goto add_free_map;
0190 
0191         entry->family = AF_INET;
0192         entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
0193         entry->def.addrsel = addrmap;
0194 #if IS_ENABLED(CONFIG_IPV6)
0195     } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
0196         struct in6_addr *addr;
0197         struct in6_addr *mask;
0198         struct netlbl_domaddr6_map *map;
0199 
0200         addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
0201         if (addrmap == NULL) {
0202             ret_val = -ENOMEM;
0203             goto add_doi_put_def;
0204         }
0205         INIT_LIST_HEAD(&addrmap->list4);
0206         INIT_LIST_HEAD(&addrmap->list6);
0207 
0208         if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
0209             sizeof(struct in6_addr)) {
0210             ret_val = -EINVAL;
0211             goto add_free_addrmap;
0212         }
0213         if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
0214             sizeof(struct in6_addr)) {
0215             ret_val = -EINVAL;
0216             goto add_free_addrmap;
0217         }
0218         addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
0219         mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
0220 
0221         map = kzalloc(sizeof(*map), GFP_KERNEL);
0222         if (map == NULL) {
0223             ret_val = -ENOMEM;
0224             goto add_free_addrmap;
0225         }
0226         pmap = map;
0227         map->list.addr = *addr;
0228         map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
0229         map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
0230         map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
0231         map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
0232         map->list.mask = *mask;
0233         map->list.valid = 1;
0234         map->def.type = entry->def.type;
0235         if (calipso)
0236             map->def.calipso = calipso;
0237 
0238         ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
0239         if (ret_val != 0)
0240             goto add_free_map;
0241 
0242         entry->family = AF_INET6;
0243         entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
0244         entry->def.addrsel = addrmap;
0245 #endif /* IPv6 */
0246     }
0247 
0248     ret_val = netlbl_domhsh_add(entry, audit_info);
0249     if (ret_val != 0)
0250         goto add_free_map;
0251 
0252     return 0;
0253 
0254 add_free_map:
0255     kfree(pmap);
0256 add_free_addrmap:
0257     kfree(addrmap);
0258 add_doi_put_def:
0259     cipso_v4_doi_putdef(cipsov4);
0260 #if IS_ENABLED(CONFIG_IPV6)
0261     calipso_doi_putdef(calipso);
0262 #endif
0263 add_free_domain:
0264     kfree(entry->domain);
0265 add_free_entry:
0266     kfree(entry);
0267     return ret_val;
0268 }
0269 
0270 /**
0271  * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
0272  * @skb: the NETLINK buffer
0273  * @entry: the map entry
0274  *
0275  * Description:
0276  * This function is a helper function used by the LISTALL and LISTDEF command
0277  * handlers.  The caller is responsible for ensuring that the RCU read lock
0278  * is held.  Returns zero on success, negative values on failure.
0279  *
0280  */
0281 static int netlbl_mgmt_listentry(struct sk_buff *skb,
0282                  struct netlbl_dom_map *entry)
0283 {
0284     int ret_val = 0;
0285     struct nlattr *nla_a;
0286     struct nlattr *nla_b;
0287     struct netlbl_af4list *iter4;
0288 #if IS_ENABLED(CONFIG_IPV6)
0289     struct netlbl_af6list *iter6;
0290 #endif
0291 
0292     if (entry->domain != NULL) {
0293         ret_val = nla_put_string(skb,
0294                      NLBL_MGMT_A_DOMAIN, entry->domain);
0295         if (ret_val != 0)
0296             return ret_val;
0297     }
0298 
0299     ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
0300     if (ret_val != 0)
0301         return ret_val;
0302 
0303     switch (entry->def.type) {
0304     case NETLBL_NLTYPE_ADDRSELECT:
0305         nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
0306         if (nla_a == NULL)
0307             return -ENOMEM;
0308 
0309         netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
0310             struct netlbl_domaddr4_map *map4;
0311             struct in_addr addr_struct;
0312 
0313             nla_b = nla_nest_start_noflag(skb,
0314                               NLBL_MGMT_A_ADDRSELECTOR);
0315             if (nla_b == NULL)
0316                 return -ENOMEM;
0317 
0318             addr_struct.s_addr = iter4->addr;
0319             ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
0320                           addr_struct.s_addr);
0321             if (ret_val != 0)
0322                 return ret_val;
0323             addr_struct.s_addr = iter4->mask;
0324             ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
0325                           addr_struct.s_addr);
0326             if (ret_val != 0)
0327                 return ret_val;
0328             map4 = netlbl_domhsh_addr4_entry(iter4);
0329             ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0330                           map4->def.type);
0331             if (ret_val != 0)
0332                 return ret_val;
0333             switch (map4->def.type) {
0334             case NETLBL_NLTYPE_CIPSOV4:
0335                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
0336                               map4->def.cipso->doi);
0337                 if (ret_val != 0)
0338                     return ret_val;
0339                 break;
0340             }
0341 
0342             nla_nest_end(skb, nla_b);
0343         }
0344 #if IS_ENABLED(CONFIG_IPV6)
0345         netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
0346             struct netlbl_domaddr6_map *map6;
0347 
0348             nla_b = nla_nest_start_noflag(skb,
0349                               NLBL_MGMT_A_ADDRSELECTOR);
0350             if (nla_b == NULL)
0351                 return -ENOMEM;
0352 
0353             ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
0354                            &iter6->addr);
0355             if (ret_val != 0)
0356                 return ret_val;
0357             ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
0358                            &iter6->mask);
0359             if (ret_val != 0)
0360                 return ret_val;
0361             map6 = netlbl_domhsh_addr6_entry(iter6);
0362             ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0363                           map6->def.type);
0364             if (ret_val != 0)
0365                 return ret_val;
0366 
0367             switch (map6->def.type) {
0368             case NETLBL_NLTYPE_CALIPSO:
0369                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
0370                               map6->def.calipso->doi);
0371                 if (ret_val != 0)
0372                     return ret_val;
0373                 break;
0374             }
0375 
0376             nla_nest_end(skb, nla_b);
0377         }
0378 #endif /* IPv6 */
0379 
0380         nla_nest_end(skb, nla_a);
0381         break;
0382     case NETLBL_NLTYPE_UNLABELED:
0383         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0384                       entry->def.type);
0385         break;
0386     case NETLBL_NLTYPE_CIPSOV4:
0387         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0388                       entry->def.type);
0389         if (ret_val != 0)
0390             return ret_val;
0391         ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
0392                       entry->def.cipso->doi);
0393         break;
0394     case NETLBL_NLTYPE_CALIPSO:
0395         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0396                       entry->def.type);
0397         if (ret_val != 0)
0398             return ret_val;
0399         ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
0400                       entry->def.calipso->doi);
0401         break;
0402     }
0403 
0404     return ret_val;
0405 }
0406 
0407 /*
0408  * NetLabel Command Handlers
0409  */
0410 
0411 /**
0412  * netlbl_mgmt_add - Handle an ADD message
0413  * @skb: the NETLINK buffer
0414  * @info: the Generic NETLINK info block
0415  *
0416  * Description:
0417  * Process a user generated ADD message and add the domains from the message
0418  * to the hash table.  See netlabel.h for a description of the message format.
0419  * Returns zero on success, negative values on failure.
0420  *
0421  */
0422 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
0423 {
0424     struct netlbl_audit audit_info;
0425 
0426     if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
0427         (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
0428         (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
0429          info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
0430         (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
0431          info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
0432         ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
0433          (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
0434         ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
0435          (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
0436         return -EINVAL;
0437 
0438     netlbl_netlink_auditinfo(&audit_info);
0439 
0440     return netlbl_mgmt_add_common(info, &audit_info);
0441 }
0442 
0443 /**
0444  * netlbl_mgmt_remove - Handle a REMOVE message
0445  * @skb: the NETLINK buffer
0446  * @info: the Generic NETLINK info block
0447  *
0448  * Description:
0449  * Process a user generated REMOVE message and remove the specified domain
0450  * mappings.  Returns zero on success, negative values on failure.
0451  *
0452  */
0453 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
0454 {
0455     char *domain;
0456     struct netlbl_audit audit_info;
0457 
0458     if (!info->attrs[NLBL_MGMT_A_DOMAIN])
0459         return -EINVAL;
0460 
0461     netlbl_netlink_auditinfo(&audit_info);
0462 
0463     domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
0464     return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
0465 }
0466 
0467 /**
0468  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
0469  * @entry: the domain mapping hash table entry
0470  * @arg: the netlbl_domhsh_walk_arg structure
0471  *
0472  * Description:
0473  * This function is designed to be used as a callback to the
0474  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
0475  * message.  Returns the size of the message on success, negative values on
0476  * failure.
0477  *
0478  */
0479 static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
0480 {
0481     int ret_val = -ENOMEM;
0482     struct netlbl_domhsh_walk_arg *cb_arg = arg;
0483     void *data;
0484 
0485     data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
0486                cb_arg->seq, &netlbl_mgmt_gnl_family,
0487                NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
0488     if (data == NULL)
0489         goto listall_cb_failure;
0490 
0491     ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
0492     if (ret_val != 0)
0493         goto listall_cb_failure;
0494 
0495     cb_arg->seq++;
0496     genlmsg_end(cb_arg->skb, data);
0497     return 0;
0498 
0499 listall_cb_failure:
0500     genlmsg_cancel(cb_arg->skb, data);
0501     return ret_val;
0502 }
0503 
0504 /**
0505  * netlbl_mgmt_listall - Handle a LISTALL message
0506  * @skb: the NETLINK buffer
0507  * @cb: the NETLINK callback
0508  *
0509  * Description:
0510  * Process a user generated LISTALL message and dumps the domain hash table in
0511  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
0512  * on success, negative values on failure.
0513  *
0514  */
0515 static int netlbl_mgmt_listall(struct sk_buff *skb,
0516                    struct netlink_callback *cb)
0517 {
0518     struct netlbl_domhsh_walk_arg cb_arg;
0519     u32 skip_bkt = cb->args[0];
0520     u32 skip_chain = cb->args[1];
0521 
0522     cb_arg.nl_cb = cb;
0523     cb_arg.skb = skb;
0524     cb_arg.seq = cb->nlh->nlmsg_seq;
0525 
0526     netlbl_domhsh_walk(&skip_bkt,
0527                &skip_chain,
0528                netlbl_mgmt_listall_cb,
0529                &cb_arg);
0530 
0531     cb->args[0] = skip_bkt;
0532     cb->args[1] = skip_chain;
0533     return skb->len;
0534 }
0535 
0536 /**
0537  * netlbl_mgmt_adddef - Handle an ADDDEF message
0538  * @skb: the NETLINK buffer
0539  * @info: the Generic NETLINK info block
0540  *
0541  * Description:
0542  * Process a user generated ADDDEF message and respond accordingly.  Returns
0543  * zero on success, negative values on failure.
0544  *
0545  */
0546 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
0547 {
0548     struct netlbl_audit audit_info;
0549 
0550     if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
0551         (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
0552          info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
0553         (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
0554          info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
0555         ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
0556          (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
0557         ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
0558          (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
0559         return -EINVAL;
0560 
0561     netlbl_netlink_auditinfo(&audit_info);
0562 
0563     return netlbl_mgmt_add_common(info, &audit_info);
0564 }
0565 
0566 /**
0567  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
0568  * @skb: the NETLINK buffer
0569  * @info: the Generic NETLINK info block
0570  *
0571  * Description:
0572  * Process a user generated REMOVEDEF message and remove the default domain
0573  * mapping.  Returns zero on success, negative values on failure.
0574  *
0575  */
0576 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
0577 {
0578     struct netlbl_audit audit_info;
0579 
0580     netlbl_netlink_auditinfo(&audit_info);
0581 
0582     return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
0583 }
0584 
0585 /**
0586  * netlbl_mgmt_listdef - Handle a LISTDEF message
0587  * @skb: the NETLINK buffer
0588  * @info: the Generic NETLINK info block
0589  *
0590  * Description:
0591  * Process a user generated LISTDEF message and dumps the default domain
0592  * mapping in a form suitable for use in a kernel generated LISTDEF message.
0593  * Returns zero on success, negative values on failure.
0594  *
0595  */
0596 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
0597 {
0598     int ret_val = -ENOMEM;
0599     struct sk_buff *ans_skb = NULL;
0600     void *data;
0601     struct netlbl_dom_map *entry;
0602     u16 family;
0603 
0604     if (info->attrs[NLBL_MGMT_A_FAMILY])
0605         family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
0606     else
0607         family = AF_INET;
0608 
0609     ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0610     if (ans_skb == NULL)
0611         return -ENOMEM;
0612     data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
0613                  0, NLBL_MGMT_C_LISTDEF);
0614     if (data == NULL)
0615         goto listdef_failure;
0616 
0617     rcu_read_lock();
0618     entry = netlbl_domhsh_getentry(NULL, family);
0619     if (entry == NULL) {
0620         ret_val = -ENOENT;
0621         goto listdef_failure_lock;
0622     }
0623     ret_val = netlbl_mgmt_listentry(ans_skb, entry);
0624     rcu_read_unlock();
0625     if (ret_val != 0)
0626         goto listdef_failure;
0627 
0628     genlmsg_end(ans_skb, data);
0629     return genlmsg_reply(ans_skb, info);
0630 
0631 listdef_failure_lock:
0632     rcu_read_unlock();
0633 listdef_failure:
0634     kfree_skb(ans_skb);
0635     return ret_val;
0636 }
0637 
0638 /**
0639  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
0640  * @skb: the skb to write to
0641  * @cb: the NETLINK callback
0642  * @protocol: the NetLabel protocol to use in the message
0643  *
0644  * Description:
0645  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
0646  * answer a application's PROTOCOLS message.  Returns the size of the message
0647  * on success, negative values on failure.
0648  *
0649  */
0650 static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
0651                     struct netlink_callback *cb,
0652                     u32 protocol)
0653 {
0654     int ret_val = -ENOMEM;
0655     void *data;
0656 
0657     data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
0658                &netlbl_mgmt_gnl_family, NLM_F_MULTI,
0659                NLBL_MGMT_C_PROTOCOLS);
0660     if (data == NULL)
0661         goto protocols_cb_failure;
0662 
0663     ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
0664     if (ret_val != 0)
0665         goto protocols_cb_failure;
0666 
0667     genlmsg_end(skb, data);
0668     return 0;
0669 
0670 protocols_cb_failure:
0671     genlmsg_cancel(skb, data);
0672     return ret_val;
0673 }
0674 
0675 /**
0676  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
0677  * @skb: the NETLINK buffer
0678  * @cb: the NETLINK callback
0679  *
0680  * Description:
0681  * Process a user generated PROTOCOLS message and respond accordingly.
0682  *
0683  */
0684 static int netlbl_mgmt_protocols(struct sk_buff *skb,
0685                  struct netlink_callback *cb)
0686 {
0687     u32 protos_sent = cb->args[0];
0688 
0689     if (protos_sent == 0) {
0690         if (netlbl_mgmt_protocols_cb(skb,
0691                          cb,
0692                          NETLBL_NLTYPE_UNLABELED) < 0)
0693             goto protocols_return;
0694         protos_sent++;
0695     }
0696     if (protos_sent == 1) {
0697         if (netlbl_mgmt_protocols_cb(skb,
0698                          cb,
0699                          NETLBL_NLTYPE_CIPSOV4) < 0)
0700             goto protocols_return;
0701         protos_sent++;
0702     }
0703 #if IS_ENABLED(CONFIG_IPV6)
0704     if (protos_sent == 2) {
0705         if (netlbl_mgmt_protocols_cb(skb,
0706                          cb,
0707                          NETLBL_NLTYPE_CALIPSO) < 0)
0708             goto protocols_return;
0709         protos_sent++;
0710     }
0711 #endif
0712 
0713 protocols_return:
0714     cb->args[0] = protos_sent;
0715     return skb->len;
0716 }
0717 
0718 /**
0719  * netlbl_mgmt_version - Handle a VERSION message
0720  * @skb: the NETLINK buffer
0721  * @info: the Generic NETLINK info block
0722  *
0723  * Description:
0724  * Process a user generated VERSION message and respond accordingly.  Returns
0725  * zero on success, negative values on failure.
0726  *
0727  */
0728 static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
0729 {
0730     int ret_val = -ENOMEM;
0731     struct sk_buff *ans_skb = NULL;
0732     void *data;
0733 
0734     ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0735     if (ans_skb == NULL)
0736         return -ENOMEM;
0737     data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
0738                  0, NLBL_MGMT_C_VERSION);
0739     if (data == NULL)
0740         goto version_failure;
0741 
0742     ret_val = nla_put_u32(ans_skb,
0743                   NLBL_MGMT_A_VERSION,
0744                   NETLBL_PROTO_VERSION);
0745     if (ret_val != 0)
0746         goto version_failure;
0747 
0748     genlmsg_end(ans_skb, data);
0749     return genlmsg_reply(ans_skb, info);
0750 
0751 version_failure:
0752     kfree_skb(ans_skb);
0753     return ret_val;
0754 }
0755 
0756 
0757 /*
0758  * NetLabel Generic NETLINK Command Definitions
0759  */
0760 
0761 static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
0762     {
0763     .cmd = NLBL_MGMT_C_ADD,
0764     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0765     .flags = GENL_ADMIN_PERM,
0766     .doit = netlbl_mgmt_add,
0767     .dumpit = NULL,
0768     },
0769     {
0770     .cmd = NLBL_MGMT_C_REMOVE,
0771     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0772     .flags = GENL_ADMIN_PERM,
0773     .doit = netlbl_mgmt_remove,
0774     .dumpit = NULL,
0775     },
0776     {
0777     .cmd = NLBL_MGMT_C_LISTALL,
0778     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0779     .flags = 0,
0780     .doit = NULL,
0781     .dumpit = netlbl_mgmt_listall,
0782     },
0783     {
0784     .cmd = NLBL_MGMT_C_ADDDEF,
0785     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0786     .flags = GENL_ADMIN_PERM,
0787     .doit = netlbl_mgmt_adddef,
0788     .dumpit = NULL,
0789     },
0790     {
0791     .cmd = NLBL_MGMT_C_REMOVEDEF,
0792     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0793     .flags = GENL_ADMIN_PERM,
0794     .doit = netlbl_mgmt_removedef,
0795     .dumpit = NULL,
0796     },
0797     {
0798     .cmd = NLBL_MGMT_C_LISTDEF,
0799     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0800     .flags = 0,
0801     .doit = netlbl_mgmt_listdef,
0802     .dumpit = NULL,
0803     },
0804     {
0805     .cmd = NLBL_MGMT_C_PROTOCOLS,
0806     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0807     .flags = 0,
0808     .doit = NULL,
0809     .dumpit = netlbl_mgmt_protocols,
0810     },
0811     {
0812     .cmd = NLBL_MGMT_C_VERSION,
0813     .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0814     .flags = 0,
0815     .doit = netlbl_mgmt_version,
0816     .dumpit = NULL,
0817     },
0818 };
0819 
0820 static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
0821     .hdrsize = 0,
0822     .name = NETLBL_NLTYPE_MGMT_NAME,
0823     .version = NETLBL_PROTO_VERSION,
0824     .maxattr = NLBL_MGMT_A_MAX,
0825     .policy = netlbl_mgmt_genl_policy,
0826     .module = THIS_MODULE,
0827     .small_ops = netlbl_mgmt_genl_ops,
0828     .n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
0829 };
0830 
0831 /*
0832  * NetLabel Generic NETLINK Protocol Functions
0833  */
0834 
0835 /**
0836  * netlbl_mgmt_genl_init - Register the NetLabel management component
0837  *
0838  * Description:
0839  * Register the NetLabel management component with the Generic NETLINK
0840  * mechanism.  Returns zero on success, negative values on failure.
0841  *
0842  */
0843 int __init netlbl_mgmt_genl_init(void)
0844 {
0845     return genl_register_family(&netlbl_mgmt_gnl_family);
0846 }