LCOV - code coverage report
Current view: top level - net/netlabel - netlabel_mgmt.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 2 200 1.0 %
Date: 2022-03-28 15:32:58 Functions: 1 11 9.1 %
Branches: 0 111 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * NetLabel Management Support
       4                 :            :  *
       5                 :            :  * This file defines the management functions for the NetLabel system.  The
       6                 :            :  * NetLabel system manages static and dynamic label mappings for network
       7                 :            :  * protocols such as CIPSO and RIPSO.
       8                 :            :  *
       9                 :            :  * Author: Paul Moore <paul@paul-moore.com>
      10                 :            :  */
      11                 :            : 
      12                 :            : /*
      13                 :            :  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <linux/types.h>
      17                 :            : #include <linux/socket.h>
      18                 :            : #include <linux/string.h>
      19                 :            : #include <linux/skbuff.h>
      20                 :            : #include <linux/in.h>
      21                 :            : #include <linux/in6.h>
      22                 :            : #include <linux/slab.h>
      23                 :            : #include <net/sock.h>
      24                 :            : #include <net/netlink.h>
      25                 :            : #include <net/genetlink.h>
      26                 :            : #include <net/ip.h>
      27                 :            : #include <net/ipv6.h>
      28                 :            : #include <net/netlabel.h>
      29                 :            : #include <net/cipso_ipv4.h>
      30                 :            : #include <net/calipso.h>
      31                 :            : #include <linux/atomic.h>
      32                 :            : 
      33                 :            : #include "netlabel_calipso.h"
      34                 :            : #include "netlabel_domainhash.h"
      35                 :            : #include "netlabel_user.h"
      36                 :            : #include "netlabel_mgmt.h"
      37                 :            : 
      38                 :            : /* NetLabel configured protocol counter */
      39                 :            : atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
      40                 :            : 
      41                 :            : /* Argument struct for netlbl_domhsh_walk() */
      42                 :            : struct netlbl_domhsh_walk_arg {
      43                 :            :         struct netlink_callback *nl_cb;
      44                 :            :         struct sk_buff *skb;
      45                 :            :         u32 seq;
      46                 :            : };
      47                 :            : 
      48                 :            : /* NetLabel Generic NETLINK CIPSOv4 family */
      49                 :            : static struct genl_family netlbl_mgmt_gnl_family;
      50                 :            : 
      51                 :            : /* NetLabel Netlink attribute policy */
      52                 :            : static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
      53                 :            :         [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
      54                 :            :         [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
      55                 :            :         [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
      56                 :            :         [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
      57                 :            :         [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
      58                 :            :         [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
      59                 :            : };
      60                 :            : 
      61                 :            : /*
      62                 :            :  * Helper Functions
      63                 :            :  */
      64                 :            : 
      65                 :            : /**
      66                 :            :  * netlbl_mgmt_add - Handle an ADD message
      67                 :            :  * @info: the Generic NETLINK info block
      68                 :            :  * @audit_info: NetLabel audit information
      69                 :            :  *
      70                 :            :  * Description:
      71                 :            :  * Helper function for the ADD and ADDDEF messages to add the domain mappings
      72                 :            :  * from the message to the hash table.  See netlabel.h for a description of the
      73                 :            :  * message format.  Returns zero on success, negative values on failure.
      74                 :            :  *
      75                 :            :  */
      76                 :            : static int netlbl_mgmt_add_common(struct genl_info *info,
      77                 :            :                                   struct netlbl_audit *audit_info)
      78                 :            : {
      79                 :            :         int ret_val = -EINVAL;
      80                 :            :         struct netlbl_domaddr_map *addrmap = NULL;
      81                 :            :         struct cipso_v4_doi *cipsov4 = NULL;
      82                 :            : #if IS_ENABLED(CONFIG_IPV6)
      83                 :            :         struct calipso_doi *calipso = NULL;
      84                 :            : #endif
      85                 :            :         u32 tmp_val;
      86                 :            :         struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
      87                 :            : 
      88                 :            :         if (!entry)
      89                 :            :                 return -ENOMEM;
      90                 :            :         entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
      91                 :            :         if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
      92                 :            :                 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
      93                 :            :                 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
      94                 :            :                 if (entry->domain == NULL) {
      95                 :            :                         ret_val = -ENOMEM;
      96                 :            :                         goto add_free_entry;
      97                 :            :                 }
      98                 :            :                 nla_strlcpy(entry->domain,
      99                 :            :                             info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
     100                 :            :         }
     101                 :            : 
     102                 :            :         /* NOTE: internally we allow/use a entry->def.type value of
     103                 :            :          *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
     104                 :            :          *       to pass that as a protocol value because we need to know the
     105                 :            :          *       "real" protocol */
     106                 :            : 
     107                 :            :         switch (entry->def.type) {
     108                 :            :         case NETLBL_NLTYPE_UNLABELED:
     109                 :            :                 if (info->attrs[NLBL_MGMT_A_FAMILY])
     110                 :            :                         entry->family =
     111                 :            :                                 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
     112                 :            :                 else
     113                 :            :                         entry->family = AF_UNSPEC;
     114                 :            :                 break;
     115                 :            :         case NETLBL_NLTYPE_CIPSOV4:
     116                 :            :                 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
     117                 :            :                         goto add_free_domain;
     118                 :            : 
     119                 :            :                 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
     120                 :            :                 cipsov4 = cipso_v4_doi_getdef(tmp_val);
     121                 :            :                 if (cipsov4 == NULL)
     122                 :            :                         goto add_free_domain;
     123                 :            :                 entry->family = AF_INET;
     124                 :            :                 entry->def.cipso = cipsov4;
     125                 :            :                 break;
     126                 :            : #if IS_ENABLED(CONFIG_IPV6)
     127                 :            :         case NETLBL_NLTYPE_CALIPSO:
     128                 :            :                 if (!info->attrs[NLBL_MGMT_A_CLPDOI])
     129                 :            :                         goto add_free_domain;
     130                 :            : 
     131                 :            :                 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
     132                 :            :                 calipso = calipso_doi_getdef(tmp_val);
     133                 :            :                 if (calipso == NULL)
     134                 :            :                         goto add_free_domain;
     135                 :            :                 entry->family = AF_INET6;
     136                 :            :                 entry->def.calipso = calipso;
     137                 :            :                 break;
     138                 :            : #endif /* IPv6 */
     139                 :            :         default:
     140                 :            :                 goto add_free_domain;
     141                 :            :         }
     142                 :            : 
     143                 :            :         if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
     144                 :            :             (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
     145                 :            :                 goto add_doi_put_def;
     146                 :            : 
     147                 :            :         if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
     148                 :            :                 struct in_addr *addr;
     149                 :            :                 struct in_addr *mask;
     150                 :            :                 struct netlbl_domaddr4_map *map;
     151                 :            : 
     152                 :            :                 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
     153                 :            :                 if (addrmap == NULL) {
     154                 :            :                         ret_val = -ENOMEM;
     155                 :            :                         goto add_doi_put_def;
     156                 :            :                 }
     157                 :            :                 INIT_LIST_HEAD(&addrmap->list4);
     158                 :            :                 INIT_LIST_HEAD(&addrmap->list6);
     159                 :            : 
     160                 :            :                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
     161                 :            :                     sizeof(struct in_addr)) {
     162                 :            :                         ret_val = -EINVAL;
     163                 :            :                         goto add_free_addrmap;
     164                 :            :                 }
     165                 :            :                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
     166                 :            :                     sizeof(struct in_addr)) {
     167                 :            :                         ret_val = -EINVAL;
     168                 :            :                         goto add_free_addrmap;
     169                 :            :                 }
     170                 :            :                 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
     171                 :            :                 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
     172                 :            : 
     173                 :            :                 map = kzalloc(sizeof(*map), GFP_KERNEL);
     174                 :            :                 if (map == NULL) {
     175                 :            :                         ret_val = -ENOMEM;
     176                 :            :                         goto add_free_addrmap;
     177                 :            :                 }
     178                 :            :                 map->list.addr = addr->s_addr & mask->s_addr;
     179                 :            :                 map->list.mask = mask->s_addr;
     180                 :            :                 map->list.valid = 1;
     181                 :            :                 map->def.type = entry->def.type;
     182                 :            :                 if (cipsov4)
     183                 :            :                         map->def.cipso = cipsov4;
     184                 :            : 
     185                 :            :                 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
     186                 :            :                 if (ret_val != 0) {
     187                 :            :                         kfree(map);
     188                 :            :                         goto add_free_addrmap;
     189                 :            :                 }
     190                 :            : 
     191                 :            :                 entry->family = AF_INET;
     192                 :            :                 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
     193                 :            :                 entry->def.addrsel = addrmap;
     194                 :            : #if IS_ENABLED(CONFIG_IPV6)
     195                 :            :         } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
     196                 :            :                 struct in6_addr *addr;
     197                 :            :                 struct in6_addr *mask;
     198                 :            :                 struct netlbl_domaddr6_map *map;
     199                 :            : 
     200                 :            :                 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
     201                 :            :                 if (addrmap == NULL) {
     202                 :            :                         ret_val = -ENOMEM;
     203                 :            :                         goto add_doi_put_def;
     204                 :            :                 }
     205                 :            :                 INIT_LIST_HEAD(&addrmap->list4);
     206                 :            :                 INIT_LIST_HEAD(&addrmap->list6);
     207                 :            : 
     208                 :            :                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
     209                 :            :                     sizeof(struct in6_addr)) {
     210                 :            :                         ret_val = -EINVAL;
     211                 :            :                         goto add_free_addrmap;
     212                 :            :                 }
     213                 :            :                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
     214                 :            :                     sizeof(struct in6_addr)) {
     215                 :            :                         ret_val = -EINVAL;
     216                 :            :                         goto add_free_addrmap;
     217                 :            :                 }
     218                 :            :                 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
     219                 :            :                 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
     220                 :            : 
     221                 :            :                 map = kzalloc(sizeof(*map), GFP_KERNEL);
     222                 :            :                 if (map == NULL) {
     223                 :            :                         ret_val = -ENOMEM;
     224                 :            :                         goto add_free_addrmap;
     225                 :            :                 }
     226                 :            :                 map->list.addr = *addr;
     227                 :            :                 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
     228                 :            :                 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
     229                 :            :                 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
     230                 :            :                 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
     231                 :            :                 map->list.mask = *mask;
     232                 :            :                 map->list.valid = 1;
     233                 :            :                 map->def.type = entry->def.type;
     234                 :            :                 if (calipso)
     235                 :            :                         map->def.calipso = calipso;
     236                 :            : 
     237                 :            :                 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
     238                 :            :                 if (ret_val != 0) {
     239                 :            :                         kfree(map);
     240                 :            :                         goto add_free_addrmap;
     241                 :            :                 }
     242                 :            : 
     243                 :            :                 entry->family = AF_INET6;
     244                 :            :                 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
     245                 :            :                 entry->def.addrsel = addrmap;
     246                 :            : #endif /* IPv6 */
     247                 :            :         }
     248                 :            : 
     249                 :            :         ret_val = netlbl_domhsh_add(entry, audit_info);
     250                 :            :         if (ret_val != 0)
     251                 :            :                 goto add_free_addrmap;
     252                 :            : 
     253                 :            :         return 0;
     254                 :            : 
     255                 :            : add_free_addrmap:
     256                 :            :         kfree(addrmap);
     257                 :            : add_doi_put_def:
     258                 :            :         cipso_v4_doi_putdef(cipsov4);
     259                 :            : #if IS_ENABLED(CONFIG_IPV6)
     260                 :            :         calipso_doi_putdef(calipso);
     261                 :            : #endif
     262                 :            : add_free_domain:
     263                 :            :         kfree(entry->domain);
     264                 :            : add_free_entry:
     265                 :            :         kfree(entry);
     266                 :            :         return ret_val;
     267                 :            : }
     268                 :            : 
     269                 :            : /**
     270                 :            :  * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
     271                 :            :  * @skb: the NETLINK buffer
     272                 :            :  * @entry: the map entry
     273                 :            :  *
     274                 :            :  * Description:
     275                 :            :  * This function is a helper function used by the LISTALL and LISTDEF command
     276                 :            :  * handlers.  The caller is responsible for ensuring that the RCU read lock
     277                 :            :  * is held.  Returns zero on success, negative values on failure.
     278                 :            :  *
     279                 :            :  */
     280                 :          0 : static int netlbl_mgmt_listentry(struct sk_buff *skb,
     281                 :            :                                  struct netlbl_dom_map *entry)
     282                 :            : {
     283                 :          0 :         int ret_val = 0;
     284                 :          0 :         struct nlattr *nla_a;
     285                 :          0 :         struct nlattr *nla_b;
     286                 :          0 :         struct netlbl_af4list *iter4;
     287                 :            : #if IS_ENABLED(CONFIG_IPV6)
     288                 :          0 :         struct netlbl_af6list *iter6;
     289                 :            : #endif
     290                 :            : 
     291         [ #  # ]:          0 :         if (entry->domain != NULL) {
     292                 :          0 :                 ret_val = nla_put_string(skb,
     293                 :            :                                          NLBL_MGMT_A_DOMAIN, entry->domain);
     294         [ #  # ]:          0 :                 if (ret_val != 0)
     295                 :            :                         return ret_val;
     296                 :            :         }
     297                 :            : 
     298                 :          0 :         ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
     299         [ #  # ]:          0 :         if (ret_val != 0)
     300                 :            :                 return ret_val;
     301                 :            : 
     302   [ #  #  #  #  :          0 :         switch (entry->def.type) {
                      # ]
     303                 :            :         case NETLBL_NLTYPE_ADDRSELECT:
     304                 :          0 :                 nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
     305         [ #  # ]:          0 :                 if (nla_a == NULL)
     306                 :            :                         return -ENOMEM;
     307                 :            : 
     308         [ #  # ]:          0 :                 netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
     309                 :          0 :                         struct netlbl_domaddr4_map *map4;
     310                 :          0 :                         struct in_addr addr_struct;
     311                 :            : 
     312                 :          0 :                         nla_b = nla_nest_start_noflag(skb,
     313                 :            :                                                       NLBL_MGMT_A_ADDRSELECTOR);
     314         [ #  # ]:          0 :                         if (nla_b == NULL)
     315                 :            :                                 return -ENOMEM;
     316                 :            : 
     317                 :          0 :                         addr_struct.s_addr = iter4->addr;
     318                 :          0 :                         ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
     319                 :            :                                                   addr_struct.s_addr);
     320         [ #  # ]:          0 :                         if (ret_val != 0)
     321                 :          0 :                                 return ret_val;
     322                 :          0 :                         addr_struct.s_addr = iter4->mask;
     323                 :          0 :                         ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
     324                 :            :                                                   addr_struct.s_addr);
     325         [ #  # ]:          0 :                         if (ret_val != 0)
     326                 :          0 :                                 return ret_val;
     327                 :          0 :                         map4 = netlbl_domhsh_addr4_entry(iter4);
     328                 :          0 :                         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
     329                 :            :                                               map4->def.type);
     330         [ #  # ]:          0 :                         if (ret_val != 0)
     331                 :          0 :                                 return ret_val;
     332         [ #  # ]:          0 :                         switch (map4->def.type) {
     333                 :          0 :                         case NETLBL_NLTYPE_CIPSOV4:
     334                 :          0 :                                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
     335                 :          0 :                                                       map4->def.cipso->doi);
     336         [ #  # ]:          0 :                                 if (ret_val != 0)
     337                 :          0 :                                         return ret_val;
     338                 :            :                                 break;
     339                 :            :                         }
     340                 :            : 
     341                 :          0 :                         nla_nest_end(skb, nla_b);
     342                 :            :                 }
     343                 :            : #if IS_ENABLED(CONFIG_IPV6)
     344         [ #  # ]:          0 :                 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
     345                 :          0 :                         struct netlbl_domaddr6_map *map6;
     346                 :            : 
     347                 :          0 :                         nla_b = nla_nest_start_noflag(skb,
     348                 :            :                                                       NLBL_MGMT_A_ADDRSELECTOR);
     349         [ #  # ]:          0 :                         if (nla_b == NULL)
     350                 :            :                                 return -ENOMEM;
     351                 :            : 
     352                 :          0 :                         ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
     353                 :          0 :                                                    &iter6->addr);
     354         [ #  # ]:          0 :                         if (ret_val != 0)
     355                 :          0 :                                 return ret_val;
     356                 :          0 :                         ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
     357                 :          0 :                                                    &iter6->mask);
     358         [ #  # ]:          0 :                         if (ret_val != 0)
     359                 :          0 :                                 return ret_val;
     360                 :          0 :                         map6 = netlbl_domhsh_addr6_entry(iter6);
     361                 :          0 :                         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
     362                 :            :                                               map6->def.type);
     363         [ #  # ]:          0 :                         if (ret_val != 0)
     364                 :          0 :                                 return ret_val;
     365                 :            : 
     366         [ #  # ]:          0 :                         switch (map6->def.type) {
     367                 :          0 :                         case NETLBL_NLTYPE_CALIPSO:
     368                 :          0 :                                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
     369                 :          0 :                                                       map6->def.calipso->doi);
     370         [ #  # ]:          0 :                                 if (ret_val != 0)
     371                 :          0 :                                         return ret_val;
     372                 :            :                                 break;
     373                 :            :                         }
     374                 :            : 
     375                 :          0 :                         nla_nest_end(skb, nla_b);
     376                 :            :                 }
     377                 :            : #endif /* IPv6 */
     378                 :            : 
     379                 :          0 :                 nla_nest_end(skb, nla_a);
     380                 :            :                 break;
     381                 :          0 :         case NETLBL_NLTYPE_UNLABELED:
     382                 :          0 :                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
     383                 :            :                                       entry->def.type);
     384                 :          0 :                 break;
     385                 :          0 :         case NETLBL_NLTYPE_CIPSOV4:
     386                 :          0 :                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
     387                 :            :                                       entry->def.type);
     388         [ #  # ]:          0 :                 if (ret_val != 0)
     389                 :            :                         return ret_val;
     390                 :          0 :                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
     391                 :          0 :                                       entry->def.cipso->doi);
     392                 :          0 :                 break;
     393                 :          0 :         case NETLBL_NLTYPE_CALIPSO:
     394                 :          0 :                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
     395                 :            :                                       entry->def.type);
     396         [ #  # ]:          0 :                 if (ret_val != 0)
     397                 :            :                         return ret_val;
     398                 :          0 :                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
     399                 :          0 :                                       entry->def.calipso->doi);
     400                 :          0 :                 break;
     401                 :            :         }
     402                 :            : 
     403                 :            :         return ret_val;
     404                 :            : }
     405                 :            : 
     406                 :            : /*
     407                 :            :  * NetLabel Command Handlers
     408                 :            :  */
     409                 :            : 
     410                 :            : /**
     411                 :            :  * netlbl_mgmt_add - Handle an ADD message
     412                 :            :  * @skb: the NETLINK buffer
     413                 :            :  * @info: the Generic NETLINK info block
     414                 :            :  *
     415                 :            :  * Description:
     416                 :            :  * Process a user generated ADD message and add the domains from the message
     417                 :            :  * to the hash table.  See netlabel.h for a description of the message format.
     418                 :            :  * Returns zero on success, negative values on failure.
     419                 :            :  *
     420                 :            :  */
     421                 :          0 : static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
     422                 :            : {
     423                 :          0 :         struct netlbl_audit audit_info;
     424                 :            : 
     425         [ #  # ]:          0 :         if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
     426         [ #  # ]:          0 :             (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
     427         [ #  # ]:          0 :             (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
     428         [ #  # ]:          0 :              info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
     429         [ #  # ]:          0 :             (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
     430   [ #  #  #  # ]:          0 :              info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
     431                 :            :             ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
     432                 :          0 :              (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
     433                 :          0 :             ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
     434         [ #  # ]:          0 :              (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
     435                 :            :                 return -EINVAL;
     436                 :            : 
     437                 :          0 :         netlbl_netlink_auditinfo(skb, &audit_info);
     438                 :            : 
     439                 :          0 :         return netlbl_mgmt_add_common(info, &audit_info);
     440                 :            : }
     441                 :            : 
     442                 :            : /**
     443                 :            :  * netlbl_mgmt_remove - Handle a REMOVE message
     444                 :            :  * @skb: the NETLINK buffer
     445                 :            :  * @info: the Generic NETLINK info block
     446                 :            :  *
     447                 :            :  * Description:
     448                 :            :  * Process a user generated REMOVE message and remove the specified domain
     449                 :            :  * mappings.  Returns zero on success, negative values on failure.
     450                 :            :  *
     451                 :            :  */
     452                 :          0 : static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
     453                 :            : {
     454                 :          0 :         char *domain;
     455                 :          0 :         struct netlbl_audit audit_info;
     456                 :            : 
     457         [ #  # ]:          0 :         if (!info->attrs[NLBL_MGMT_A_DOMAIN])
     458                 :            :                 return -EINVAL;
     459                 :            : 
     460                 :          0 :         netlbl_netlink_auditinfo(skb, &audit_info);
     461                 :            : 
     462                 :          0 :         domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
     463                 :          0 :         return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
     464                 :            : }
     465                 :            : 
     466                 :            : /**
     467                 :            :  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
     468                 :            :  * @entry: the domain mapping hash table entry
     469                 :            :  * @arg: the netlbl_domhsh_walk_arg structure
     470                 :            :  *
     471                 :            :  * Description:
     472                 :            :  * This function is designed to be used as a callback to the
     473                 :            :  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
     474                 :            :  * message.  Returns the size of the message on success, negative values on
     475                 :            :  * failure.
     476                 :            :  *
     477                 :            :  */
     478                 :          0 : static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
     479                 :            : {
     480                 :          0 :         int ret_val = -ENOMEM;
     481                 :          0 :         struct netlbl_domhsh_walk_arg *cb_arg = arg;
     482                 :          0 :         void *data;
     483                 :            : 
     484                 :          0 :         data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
     485                 :            :                            cb_arg->seq, &netlbl_mgmt_gnl_family,
     486                 :            :                            NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
     487         [ #  # ]:          0 :         if (data == NULL)
     488                 :          0 :                 goto listall_cb_failure;
     489                 :            : 
     490                 :          0 :         ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
     491         [ #  # ]:          0 :         if (ret_val != 0)
     492                 :          0 :                 goto listall_cb_failure;
     493                 :            : 
     494                 :          0 :         cb_arg->seq++;
     495                 :          0 :         genlmsg_end(cb_arg->skb, data);
     496                 :          0 :         return 0;
     497                 :            : 
     498                 :          0 : listall_cb_failure:
     499         [ #  # ]:          0 :         genlmsg_cancel(cb_arg->skb, data);
     500                 :            :         return ret_val;
     501                 :            : }
     502                 :            : 
     503                 :            : /**
     504                 :            :  * netlbl_mgmt_listall - Handle a LISTALL message
     505                 :            :  * @skb: the NETLINK buffer
     506                 :            :  * @cb: the NETLINK callback
     507                 :            :  *
     508                 :            :  * Description:
     509                 :            :  * Process a user generated LISTALL message and dumps the domain hash table in
     510                 :            :  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
     511                 :            :  * on success, negative values on failure.
     512                 :            :  *
     513                 :            :  */
     514                 :          0 : static int netlbl_mgmt_listall(struct sk_buff *skb,
     515                 :            :                                struct netlink_callback *cb)
     516                 :            : {
     517                 :          0 :         struct netlbl_domhsh_walk_arg cb_arg;
     518                 :          0 :         u32 skip_bkt = cb->args[0];
     519                 :          0 :         u32 skip_chain = cb->args[1];
     520                 :            : 
     521                 :          0 :         cb_arg.nl_cb = cb;
     522                 :          0 :         cb_arg.skb = skb;
     523                 :          0 :         cb_arg.seq = cb->nlh->nlmsg_seq;
     524                 :            : 
     525                 :          0 :         netlbl_domhsh_walk(&skip_bkt,
     526                 :            :                            &skip_chain,
     527                 :            :                            netlbl_mgmt_listall_cb,
     528                 :            :                            &cb_arg);
     529                 :            : 
     530                 :          0 :         cb->args[0] = skip_bkt;
     531                 :          0 :         cb->args[1] = skip_chain;
     532                 :          0 :         return skb->len;
     533                 :            : }
     534                 :            : 
     535                 :            : /**
     536                 :            :  * netlbl_mgmt_adddef - Handle an ADDDEF message
     537                 :            :  * @skb: the NETLINK buffer
     538                 :            :  * @info: the Generic NETLINK info block
     539                 :            :  *
     540                 :            :  * Description:
     541                 :            :  * Process a user generated ADDDEF message and respond accordingly.  Returns
     542                 :            :  * zero on success, negative values on failure.
     543                 :            :  *
     544                 :            :  */
     545                 :          0 : static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
     546                 :            : {
     547                 :          0 :         struct netlbl_audit audit_info;
     548                 :            : 
     549         [ #  # ]:          0 :         if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
     550         [ #  # ]:          0 :             (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
     551         [ #  # ]:          0 :              info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
     552         [ #  # ]:          0 :             (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
     553   [ #  #  #  # ]:          0 :              info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
     554                 :            :             ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
     555                 :          0 :              (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
     556                 :          0 :             ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
     557         [ #  # ]:          0 :              (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
     558                 :            :                 return -EINVAL;
     559                 :            : 
     560                 :          0 :         netlbl_netlink_auditinfo(skb, &audit_info);
     561                 :            : 
     562                 :          0 :         return netlbl_mgmt_add_common(info, &audit_info);
     563                 :            : }
     564                 :            : 
     565                 :            : /**
     566                 :            :  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
     567                 :            :  * @skb: the NETLINK buffer
     568                 :            :  * @info: the Generic NETLINK info block
     569                 :            :  *
     570                 :            :  * Description:
     571                 :            :  * Process a user generated REMOVEDEF message and remove the default domain
     572                 :            :  * mapping.  Returns zero on success, negative values on failure.
     573                 :            :  *
     574                 :            :  */
     575                 :          0 : static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
     576                 :            : {
     577                 :          0 :         struct netlbl_audit audit_info;
     578                 :            : 
     579                 :          0 :         netlbl_netlink_auditinfo(skb, &audit_info);
     580                 :            : 
     581                 :          0 :         return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
     582                 :            : }
     583                 :            : 
     584                 :            : /**
     585                 :            :  * netlbl_mgmt_listdef - Handle a LISTDEF message
     586                 :            :  * @skb: the NETLINK buffer
     587                 :            :  * @info: the Generic NETLINK info block
     588                 :            :  *
     589                 :            :  * Description:
     590                 :            :  * Process a user generated LISTDEF message and dumps the default domain
     591                 :            :  * mapping in a form suitable for use in a kernel generated LISTDEF message.
     592                 :            :  * Returns zero on success, negative values on failure.
     593                 :            :  *
     594                 :            :  */
     595                 :          0 : static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
     596                 :            : {
     597                 :          0 :         int ret_val = -ENOMEM;
     598                 :          0 :         struct sk_buff *ans_skb = NULL;
     599                 :          0 :         void *data;
     600                 :          0 :         struct netlbl_dom_map *entry;
     601                 :          0 :         u16 family;
     602                 :            : 
     603         [ #  # ]:          0 :         if (info->attrs[NLBL_MGMT_A_FAMILY])
     604                 :          0 :                 family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
     605                 :            :         else
     606                 :            :                 family = AF_INET;
     607                 :            : 
     608                 :          0 :         ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
     609         [ #  # ]:          0 :         if (ans_skb == NULL)
     610                 :            :                 return -ENOMEM;
     611                 :          0 :         data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
     612                 :            :                                  0, NLBL_MGMT_C_LISTDEF);
     613         [ #  # ]:          0 :         if (data == NULL)
     614                 :          0 :                 goto listdef_failure;
     615                 :            : 
     616                 :          0 :         rcu_read_lock();
     617                 :          0 :         entry = netlbl_domhsh_getentry(NULL, family);
     618         [ #  # ]:          0 :         if (entry == NULL) {
     619                 :          0 :                 ret_val = -ENOENT;
     620                 :          0 :                 goto listdef_failure_lock;
     621                 :            :         }
     622                 :          0 :         ret_val = netlbl_mgmt_listentry(ans_skb, entry);
     623                 :          0 :         rcu_read_unlock();
     624         [ #  # ]:          0 :         if (ret_val != 0)
     625                 :          0 :                 goto listdef_failure;
     626                 :            : 
     627                 :          0 :         genlmsg_end(ans_skb, data);
     628                 :          0 :         return genlmsg_reply(ans_skb, info);
     629                 :            : 
     630                 :            : listdef_failure_lock:
     631                 :          0 :         rcu_read_unlock();
     632                 :          0 : listdef_failure:
     633                 :          0 :         kfree_skb(ans_skb);
     634                 :          0 :         return ret_val;
     635                 :            : }
     636                 :            : 
     637                 :            : /**
     638                 :            :  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
     639                 :            :  * @skb: the skb to write to
     640                 :            :  * @cb: the NETLINK callback
     641                 :            :  * @protocol: the NetLabel protocol to use in the message
     642                 :            :  *
     643                 :            :  * Description:
     644                 :            :  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
     645                 :            :  * answer a application's PROTOCOLS message.  Returns the size of the message
     646                 :            :  * on success, negative values on failure.
     647                 :            :  *
     648                 :            :  */
     649                 :            : static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
     650                 :            :                                     struct netlink_callback *cb,
     651                 :            :                                     u32 protocol)
     652                 :            : {
     653                 :            :         int ret_val = -ENOMEM;
     654                 :            :         void *data;
     655                 :            : 
     656                 :            :         data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
     657                 :            :                            &netlbl_mgmt_gnl_family, NLM_F_MULTI,
     658                 :            :                            NLBL_MGMT_C_PROTOCOLS);
     659                 :            :         if (data == NULL)
     660                 :            :                 goto protocols_cb_failure;
     661                 :            : 
     662                 :            :         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
     663                 :            :         if (ret_val != 0)
     664                 :            :                 goto protocols_cb_failure;
     665                 :            : 
     666                 :            :         genlmsg_end(skb, data);
     667                 :            :         return 0;
     668                 :            : 
     669                 :            : protocols_cb_failure:
     670                 :            :         genlmsg_cancel(skb, data);
     671                 :            :         return ret_val;
     672                 :            : }
     673                 :            : 
     674                 :            : /**
     675                 :            :  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
     676                 :            :  * @skb: the NETLINK buffer
     677                 :            :  * @cb: the NETLINK callback
     678                 :            :  *
     679                 :            :  * Description:
     680                 :            :  * Process a user generated PROTOCOLS message and respond accordingly.
     681                 :            :  *
     682                 :            :  */
     683                 :          0 : static int netlbl_mgmt_protocols(struct sk_buff *skb,
     684                 :            :                                  struct netlink_callback *cb)
     685                 :            : {
     686                 :          0 :         u32 protos_sent = cb->args[0];
     687                 :            : 
     688         [ #  # ]:          0 :         if (protos_sent == 0) {
     689         [ #  # ]:          0 :                 if (netlbl_mgmt_protocols_cb(skb,
     690                 :            :                                              cb,
     691                 :            :                                              NETLBL_NLTYPE_UNLABELED) < 0)
     692                 :          0 :                         goto protocols_return;
     693                 :            :                 protos_sent++;
     694                 :            :         }
     695         [ #  # ]:          0 :         if (protos_sent == 1) {
     696         [ #  # ]:          0 :                 if (netlbl_mgmt_protocols_cb(skb,
     697                 :            :                                              cb,
     698                 :            :                                              NETLBL_NLTYPE_CIPSOV4) < 0)
     699                 :          0 :                         goto protocols_return;
     700                 :            :                 protos_sent++;
     701                 :            :         }
     702                 :            : #if IS_ENABLED(CONFIG_IPV6)
     703         [ #  # ]:          0 :         if (protos_sent == 2) {
     704         [ #  # ]:          0 :                 if (netlbl_mgmt_protocols_cb(skb,
     705                 :            :                                              cb,
     706                 :            :                                              NETLBL_NLTYPE_CALIPSO) < 0)
     707                 :          0 :                         goto protocols_return;
     708                 :            :                 protos_sent++;
     709                 :            :         }
     710                 :            : #endif
     711                 :            : 
     712                 :          0 : protocols_return:
     713                 :          0 :         cb->args[0] = protos_sent;
     714                 :          0 :         return skb->len;
     715                 :            : }
     716                 :            : 
     717                 :            : /**
     718                 :            :  * netlbl_mgmt_version - Handle a VERSION message
     719                 :            :  * @skb: the NETLINK buffer
     720                 :            :  * @info: the Generic NETLINK info block
     721                 :            :  *
     722                 :            :  * Description:
     723                 :            :  * Process a user generated VERSION message and respond accordingly.  Returns
     724                 :            :  * zero on success, negative values on failure.
     725                 :            :  *
     726                 :            :  */
     727                 :          0 : static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
     728                 :            : {
     729                 :          0 :         int ret_val = -ENOMEM;
     730                 :          0 :         struct sk_buff *ans_skb = NULL;
     731                 :          0 :         void *data;
     732                 :            : 
     733                 :          0 :         ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
     734         [ #  # ]:          0 :         if (ans_skb == NULL)
     735                 :            :                 return -ENOMEM;
     736                 :          0 :         data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
     737                 :            :                                  0, NLBL_MGMT_C_VERSION);
     738         [ #  # ]:          0 :         if (data == NULL)
     739                 :          0 :                 goto version_failure;
     740                 :            : 
     741                 :          0 :         ret_val = nla_put_u32(ans_skb,
     742                 :            :                               NLBL_MGMT_A_VERSION,
     743                 :            :                               NETLBL_PROTO_VERSION);
     744         [ #  # ]:          0 :         if (ret_val != 0)
     745                 :          0 :                 goto version_failure;
     746                 :            : 
     747                 :          0 :         genlmsg_end(ans_skb, data);
     748                 :          0 :         return genlmsg_reply(ans_skb, info);
     749                 :            : 
     750                 :          0 : version_failure:
     751                 :          0 :         kfree_skb(ans_skb);
     752                 :          0 :         return ret_val;
     753                 :            : }
     754                 :            : 
     755                 :            : 
     756                 :            : /*
     757                 :            :  * NetLabel Generic NETLINK Command Definitions
     758                 :            :  */
     759                 :            : 
     760                 :            : static const struct genl_ops netlbl_mgmt_genl_ops[] = {
     761                 :            :         {
     762                 :            :         .cmd = NLBL_MGMT_C_ADD,
     763                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     764                 :            :         .flags = GENL_ADMIN_PERM,
     765                 :            :         .doit = netlbl_mgmt_add,
     766                 :            :         .dumpit = NULL,
     767                 :            :         },
     768                 :            :         {
     769                 :            :         .cmd = NLBL_MGMT_C_REMOVE,
     770                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     771                 :            :         .flags = GENL_ADMIN_PERM,
     772                 :            :         .doit = netlbl_mgmt_remove,
     773                 :            :         .dumpit = NULL,
     774                 :            :         },
     775                 :            :         {
     776                 :            :         .cmd = NLBL_MGMT_C_LISTALL,
     777                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     778                 :            :         .flags = 0,
     779                 :            :         .doit = NULL,
     780                 :            :         .dumpit = netlbl_mgmt_listall,
     781                 :            :         },
     782                 :            :         {
     783                 :            :         .cmd = NLBL_MGMT_C_ADDDEF,
     784                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     785                 :            :         .flags = GENL_ADMIN_PERM,
     786                 :            :         .doit = netlbl_mgmt_adddef,
     787                 :            :         .dumpit = NULL,
     788                 :            :         },
     789                 :            :         {
     790                 :            :         .cmd = NLBL_MGMT_C_REMOVEDEF,
     791                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     792                 :            :         .flags = GENL_ADMIN_PERM,
     793                 :            :         .doit = netlbl_mgmt_removedef,
     794                 :            :         .dumpit = NULL,
     795                 :            :         },
     796                 :            :         {
     797                 :            :         .cmd = NLBL_MGMT_C_LISTDEF,
     798                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     799                 :            :         .flags = 0,
     800                 :            :         .doit = netlbl_mgmt_listdef,
     801                 :            :         .dumpit = NULL,
     802                 :            :         },
     803                 :            :         {
     804                 :            :         .cmd = NLBL_MGMT_C_PROTOCOLS,
     805                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     806                 :            :         .flags = 0,
     807                 :            :         .doit = NULL,
     808                 :            :         .dumpit = netlbl_mgmt_protocols,
     809                 :            :         },
     810                 :            :         {
     811                 :            :         .cmd = NLBL_MGMT_C_VERSION,
     812                 :            :         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
     813                 :            :         .flags = 0,
     814                 :            :         .doit = netlbl_mgmt_version,
     815                 :            :         .dumpit = NULL,
     816                 :            :         },
     817                 :            : };
     818                 :            : 
     819                 :            : static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
     820                 :            :         .hdrsize = 0,
     821                 :            :         .name = NETLBL_NLTYPE_MGMT_NAME,
     822                 :            :         .version = NETLBL_PROTO_VERSION,
     823                 :            :         .maxattr = NLBL_MGMT_A_MAX,
     824                 :            :         .policy = netlbl_mgmt_genl_policy,
     825                 :            :         .module = THIS_MODULE,
     826                 :            :         .ops = netlbl_mgmt_genl_ops,
     827                 :            :         .n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
     828                 :            : };
     829                 :            : 
     830                 :            : /*
     831                 :            :  * NetLabel Generic NETLINK Protocol Functions
     832                 :            :  */
     833                 :            : 
     834                 :            : /**
     835                 :            :  * netlbl_mgmt_genl_init - Register the NetLabel management component
     836                 :            :  *
     837                 :            :  * Description:
     838                 :            :  * Register the NetLabel management component with the Generic NETLINK
     839                 :            :  * mechanism.  Returns zero on success, negative values on failure.
     840                 :            :  *
     841                 :            :  */
     842                 :         28 : int __init netlbl_mgmt_genl_init(void)
     843                 :            : {
     844                 :         28 :         return genl_register_family(&netlbl_mgmt_gnl_family);
     845                 :            : }

Generated by: LCOV version 1.14