LCOV - code coverage report
Current view: top level - net/netlink - policy.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 179 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 10 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * NETLINK      Policy advertisement to userspace
       4             :  *
       5             :  *              Authors:        Johannes Berg <johannes@sipsolutions.net>
       6             :  *
       7             :  * Copyright 2019 Intel Corporation
       8             :  */
       9             : 
      10             : #include <linux/kernel.h>
      11             : #include <linux/errno.h>
      12             : #include <linux/types.h>
      13             : #include <net/netlink.h>
      14             : 
      15             : #define INITIAL_POLICIES_ALLOC  10
      16             : 
      17             : struct netlink_policy_dump_state {
      18             :         unsigned int policy_idx;
      19             :         unsigned int attr_idx;
      20             :         unsigned int n_alloc;
      21             :         struct {
      22             :                 const struct nla_policy *policy;
      23             :                 unsigned int maxtype;
      24             :         } policies[];
      25             : };
      26             : 
      27           0 : static int add_policy(struct netlink_policy_dump_state **statep,
      28             :                       const struct nla_policy *policy,
      29             :                       unsigned int maxtype)
      30             : {
      31           0 :         struct netlink_policy_dump_state *state = *statep;
      32           0 :         unsigned int n_alloc, i;
      33             : 
      34           0 :         if (!policy || !maxtype)
      35             :                 return 0;
      36             : 
      37           0 :         for (i = 0; i < state->n_alloc; i++) {
      38           0 :                 if (state->policies[i].policy == policy &&
      39           0 :                     state->policies[i].maxtype == maxtype)
      40             :                         return 0;
      41             : 
      42           0 :                 if (!state->policies[i].policy) {
      43           0 :                         state->policies[i].policy = policy;
      44           0 :                         state->policies[i].maxtype = maxtype;
      45           0 :                         return 0;
      46             :                 }
      47             :         }
      48             : 
      49           0 :         n_alloc = state->n_alloc + INITIAL_POLICIES_ALLOC;
      50           0 :         state = krealloc(state, struct_size(state, policies, n_alloc),
      51             :                          GFP_KERNEL);
      52           0 :         if (!state)
      53             :                 return -ENOMEM;
      54             : 
      55           0 :         memset(&state->policies[state->n_alloc], 0,
      56           0 :                flex_array_size(state, policies, n_alloc - state->n_alloc));
      57             : 
      58           0 :         state->policies[state->n_alloc].policy = policy;
      59           0 :         state->policies[state->n_alloc].maxtype = maxtype;
      60           0 :         state->n_alloc = n_alloc;
      61           0 :         *statep = state;
      62             : 
      63           0 :         return 0;
      64             : }
      65             : 
      66             : /**
      67             :  * netlink_policy_dump_get_policy_idx - retrieve policy index
      68             :  * @state: the policy dump state
      69             :  * @policy: the policy to find
      70             :  * @maxtype: the policy's maxattr
      71             :  *
      72             :  * Returns: the index of the given policy in the dump state
      73             :  *
      74             :  * Call this to find a policy index when you've added multiple and e.g.
      75             :  * need to tell userspace which command has which policy (by index).
      76             :  *
      77             :  * Note: this will WARN and return 0 if the policy isn't found, which
      78             :  *       means it wasn't added in the first place, which would be an
      79             :  *       internal consistency bug.
      80             :  */
      81           0 : int netlink_policy_dump_get_policy_idx(struct netlink_policy_dump_state *state,
      82             :                                        const struct nla_policy *policy,
      83             :                                        unsigned int maxtype)
      84             : {
      85           0 :         unsigned int i;
      86             : 
      87           0 :         if (WARN_ON(!policy || !maxtype))
      88             :                 return 0;
      89             : 
      90           0 :         for (i = 0; i < state->n_alloc; i++) {
      91           0 :                 if (state->policies[i].policy == policy &&
      92           0 :                     state->policies[i].maxtype == maxtype)
      93           0 :                         return i;
      94             :         }
      95             : 
      96           0 :         WARN_ON(1);
      97           0 :         return 0;
      98             : }
      99             : 
     100           0 : static struct netlink_policy_dump_state *alloc_state(void)
     101             : {
     102           0 :         struct netlink_policy_dump_state *state;
     103             : 
     104           0 :         state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC),
     105             :                         GFP_KERNEL);
     106           0 :         if (!state)
     107           0 :                 return ERR_PTR(-ENOMEM);
     108           0 :         state->n_alloc = INITIAL_POLICIES_ALLOC;
     109             : 
     110           0 :         return state;
     111             : }
     112             : 
     113             : /**
     114             :  * netlink_policy_dump_add_policy - add a policy to the dump
     115             :  * @pstate: state to add to, may be reallocated, must be %NULL the first time
     116             :  * @policy: the new policy to add to the dump
     117             :  * @maxtype: the new policy's max attr type
     118             :  *
     119             :  * Returns: 0 on success, a negative error code otherwise.
     120             :  *
     121             :  * Call this to allocate a policy dump state, and to add policies to it. This
     122             :  * should be called from the dump start() callback.
     123             :  *
     124             :  * Note: on failures, any previously allocated state is freed.
     125             :  */
     126           0 : int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate,
     127             :                                    const struct nla_policy *policy,
     128             :                                    unsigned int maxtype)
     129             : {
     130           0 :         struct netlink_policy_dump_state *state = *pstate;
     131           0 :         unsigned int policy_idx;
     132           0 :         int err;
     133             : 
     134           0 :         if (!state) {
     135           0 :                 state = alloc_state();
     136           0 :                 if (IS_ERR(state))
     137           0 :                         return PTR_ERR(state);
     138             :         }
     139             : 
     140             :         /*
     141             :          * walk the policies and nested ones first, and build
     142             :          * a linear list of them.
     143             :          */
     144             : 
     145           0 :         err = add_policy(&state, policy, maxtype);
     146           0 :         if (err)
     147             :                 return err;
     148             : 
     149           0 :         for (policy_idx = 0;
     150           0 :              policy_idx < state->n_alloc && state->policies[policy_idx].policy;
     151           0 :              policy_idx++) {
     152             :                 const struct nla_policy *policy;
     153             :                 unsigned int type;
     154             : 
     155           0 :                 policy = state->policies[policy_idx].policy;
     156             : 
     157           0 :                 for (type = 0;
     158           0 :                      type <= state->policies[policy_idx].maxtype;
     159           0 :                      type++) {
     160           0 :                         switch (policy[type].type) {
     161           0 :                         case NLA_NESTED:
     162             :                         case NLA_NESTED_ARRAY:
     163           0 :                                 err = add_policy(&state,
     164             :                                                  policy[type].nested_policy,
     165           0 :                                                  policy[type].len);
     166           0 :                                 if (err)
     167           0 :                                         return err;
     168             :                                 break;
     169             :                         default:
     170             :                                 break;
     171             :                         }
     172             :                 }
     173             :         }
     174             : 
     175           0 :         *pstate = state;
     176           0 :         return 0;
     177             : }
     178             : 
     179             : static bool
     180           0 : netlink_policy_dump_finished(struct netlink_policy_dump_state *state)
     181             : {
     182           0 :         return state->policy_idx >= state->n_alloc ||
     183           0 :                !state->policies[state->policy_idx].policy;
     184             : }
     185             : 
     186             : /**
     187             :  * netlink_policy_dump_loop - dumping loop indicator
     188             :  * @state: the policy dump state
     189             :  *
     190             :  * Returns: %true if the dump continues, %false otherwise
     191             :  *
     192             :  * Note: this frees the dump state when finishing
     193             :  */
     194           0 : bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state)
     195             : {
     196           0 :         return !netlink_policy_dump_finished(state);
     197             : }
     198             : 
     199           0 : int netlink_policy_dump_attr_size_estimate(const struct nla_policy *pt)
     200             : {
     201             :         /* nested + type */
     202           0 :         int common = 2 * nla_attr_size(sizeof(u32));
     203             : 
     204           0 :         switch (pt->type) {
     205             :         case NLA_UNSPEC:
     206             :         case NLA_REJECT:
     207             :                 /* these actually don't need any space */
     208             :                 return 0;
     209             :         case NLA_NESTED:
     210             :         case NLA_NESTED_ARRAY:
     211             :                 /* common, policy idx, policy maxattr */
     212             :                 return common + 2 * nla_attr_size(sizeof(u32));
     213             :         case NLA_U8:
     214             :         case NLA_U16:
     215             :         case NLA_U32:
     216             :         case NLA_U64:
     217             :         case NLA_MSECS:
     218             :         case NLA_S8:
     219             :         case NLA_S16:
     220             :         case NLA_S32:
     221             :         case NLA_S64:
     222             :                 /* maximum is common, u64 min/max with padding */
     223             :                 return common +
     224             :                        2 * (nla_attr_size(0) + nla_attr_size(sizeof(u64)));
     225             :         case NLA_BITFIELD32:
     226             :                 return common + nla_attr_size(sizeof(u32));
     227             :         case NLA_STRING:
     228             :         case NLA_NUL_STRING:
     229             :         case NLA_BINARY:
     230             :                 /* maximum is common, u32 min-length/max-length */
     231             :                 return common + 2 * nla_attr_size(sizeof(u32));
     232             :         case NLA_FLAG:
     233             :                 return common;
     234             :         }
     235             : 
     236             :         /* this should then cause a warning later */
     237             :         return 0;
     238             : }
     239             : 
     240             : static int
     241           0 : __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state,
     242             :                                  struct sk_buff *skb,
     243             :                                  const struct nla_policy *pt,
     244             :                                  int nestattr)
     245             : {
     246           0 :         int estimate = netlink_policy_dump_attr_size_estimate(pt);
     247           0 :         enum netlink_attribute_type type;
     248           0 :         struct nlattr *attr;
     249             : 
     250           0 :         attr = nla_nest_start(skb, nestattr);
     251           0 :         if (!attr)
     252             :                 return -ENOBUFS;
     253             : 
     254           0 :         switch (pt->type) {
     255             :         default:
     256             :         case NLA_UNSPEC:
     257             :         case NLA_REJECT:
     258             :                 /* skip - use NLA_MIN_LEN to advertise such */
     259           0 :                 nla_nest_cancel(skb, attr);
     260           0 :                 return -ENODATA;
     261             :         case NLA_NESTED:
     262             :                 type = NL_ATTR_TYPE_NESTED;
     263           0 :                 fallthrough;
     264           0 :         case NLA_NESTED_ARRAY:
     265           0 :                 if (pt->type == NLA_NESTED_ARRAY)
     266           0 :                         type = NL_ATTR_TYPE_NESTED_ARRAY;
     267           0 :                 if (state && pt->nested_policy && pt->len &&
     268           0 :                     (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
     269           0 :                                  netlink_policy_dump_get_policy_idx(state,
     270             :                                                                     pt->nested_policy,
     271           0 :                                                                     pt->len)) ||
     272           0 :                      nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
     273           0 :                                  pt->len)))
     274           0 :                         goto nla_put_failure;
     275             :                 break;
     276           0 :         case NLA_U8:
     277             :         case NLA_U16:
     278             :         case NLA_U32:
     279             :         case NLA_U64:
     280             :         case NLA_MSECS: {
     281           0 :                 struct netlink_range_validation range;
     282             : 
     283           0 :                 if (pt->type == NLA_U8)
     284             :                         type = NL_ATTR_TYPE_U8;
     285           0 :                 else if (pt->type == NLA_U16)
     286             :                         type = NL_ATTR_TYPE_U16;
     287           0 :                 else if (pt->type == NLA_U32)
     288             :                         type = NL_ATTR_TYPE_U32;
     289             :                 else
     290           0 :                         type = NL_ATTR_TYPE_U64;
     291             : 
     292           0 :                 if (pt->validation_type == NLA_VALIDATE_MASK) {
     293           0 :                         if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK,
     294           0 :                                               pt->mask,
     295             :                                               NL_POLICY_TYPE_ATTR_PAD))
     296           0 :                                 goto nla_put_failure;
     297           0 :                         break;
     298             :                 }
     299             : 
     300           0 :                 nla_get_range_unsigned(pt, &range);
     301             : 
     302           0 :                 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
     303           0 :                                       range.min, NL_POLICY_TYPE_ATTR_PAD) ||
     304           0 :                     nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
     305             :                                       range.max, NL_POLICY_TYPE_ATTR_PAD))
     306           0 :                         goto nla_put_failure;
     307             :                 break;
     308             :         }
     309           0 :         case NLA_S8:
     310             :         case NLA_S16:
     311             :         case NLA_S32:
     312             :         case NLA_S64: {
     313           0 :                 struct netlink_range_validation_signed range;
     314             : 
     315           0 :                 if (pt->type == NLA_S8)
     316             :                         type = NL_ATTR_TYPE_S8;
     317           0 :                 else if (pt->type == NLA_S16)
     318             :                         type = NL_ATTR_TYPE_S16;
     319           0 :                 else if (pt->type == NLA_S32)
     320             :                         type = NL_ATTR_TYPE_S32;
     321             :                 else
     322           0 :                         type = NL_ATTR_TYPE_S64;
     323             : 
     324           0 :                 nla_get_range_signed(pt, &range);
     325             : 
     326           0 :                 if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
     327           0 :                                 range.min, NL_POLICY_TYPE_ATTR_PAD) ||
     328           0 :                     nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
     329             :                                 range.max, NL_POLICY_TYPE_ATTR_PAD))
     330           0 :                         goto nla_put_failure;
     331           0 :                 break;
     332             :         }
     333           0 :         case NLA_BITFIELD32:
     334           0 :                 type = NL_ATTR_TYPE_BITFIELD32;
     335           0 :                 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
     336             :                                 pt->bitfield32_valid))
     337           0 :                         goto nla_put_failure;
     338             :                 break;
     339           0 :         case NLA_STRING:
     340             :         case NLA_NUL_STRING:
     341             :         case NLA_BINARY:
     342           0 :                 if (pt->type == NLA_STRING)
     343             :                         type = NL_ATTR_TYPE_STRING;
     344           0 :                 else if (pt->type == NLA_NUL_STRING)
     345             :                         type = NL_ATTR_TYPE_NUL_STRING;
     346             :                 else
     347           0 :                         type = NL_ATTR_TYPE_BINARY;
     348             : 
     349           0 :                 if (pt->validation_type == NLA_VALIDATE_RANGE ||
     350             :                     pt->validation_type == NLA_VALIDATE_RANGE_WARN_TOO_LONG) {
     351           0 :                         struct netlink_range_validation range;
     352             : 
     353           0 :                         nla_get_range_unsigned(pt, &range);
     354             : 
     355           0 :                         if (range.min &&
     356           0 :                             nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH,
     357             :                                         range.min))
     358           0 :                                 goto nla_put_failure;
     359             : 
     360           0 :                         if (range.max < U16_MAX &&
     361           0 :                             nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
     362             :                                         range.max))
     363           0 :                                 goto nla_put_failure;
     364           0 :                 } else if (pt->len &&
     365           0 :                            nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
     366             :                                        pt->len)) {
     367           0 :                         goto nla_put_failure;
     368             :                 }
     369             :                 break;
     370             :         case NLA_FLAG:
     371             :                 type = NL_ATTR_TYPE_FLAG;
     372             :                 break;
     373             :         }
     374             : 
     375           0 :         if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_TYPE, type))
     376           0 :                 goto nla_put_failure;
     377             : 
     378           0 :         nla_nest_end(skb, attr);
     379           0 :         WARN_ON(attr->nla_len > estimate);
     380             : 
     381             :         return 0;
     382           0 : nla_put_failure:
     383           0 :         nla_nest_cancel(skb, attr);
     384           0 :         return -ENOBUFS;
     385             : }
     386             : 
     387             : /**
     388             :  * netlink_policy_dump_write_attr - write a given attribute policy
     389             :  * @skb: the message skb to write to
     390             :  * @pt: the attribute's policy
     391             :  * @nestattr: the nested attribute ID to use
     392             :  *
     393             :  * Returns: 0 on success, an error code otherwise; -%ENODATA is
     394             :  *          special, indicating that there's no policy data and
     395             :  *          the attribute is generally rejected.
     396             :  */
     397           0 : int netlink_policy_dump_write_attr(struct sk_buff *skb,
     398             :                                    const struct nla_policy *pt,
     399             :                                    int nestattr)
     400             : {
     401           0 :         return __netlink_policy_dump_write_attr(NULL, skb, pt, nestattr);
     402             : }
     403             : 
     404             : /**
     405             :  * netlink_policy_dump_write - write current policy dump attributes
     406             :  * @skb: the message skb to write to
     407             :  * @state: the policy dump state
     408             :  *
     409             :  * Returns: 0 on success, an error code otherwise
     410             :  */
     411           0 : int netlink_policy_dump_write(struct sk_buff *skb,
     412             :                               struct netlink_policy_dump_state *state)
     413             : {
     414           0 :         const struct nla_policy *pt;
     415           0 :         struct nlattr *policy;
     416           0 :         bool again;
     417           0 :         int err;
     418             : 
     419           0 : send_attribute:
     420           0 :         again = false;
     421             : 
     422           0 :         pt = &state->policies[state->policy_idx].policy[state->attr_idx];
     423             : 
     424           0 :         policy = nla_nest_start(skb, state->policy_idx);
     425           0 :         if (!policy)
     426             :                 return -ENOBUFS;
     427             : 
     428           0 :         err = __netlink_policy_dump_write_attr(state, skb, pt, state->attr_idx);
     429           0 :         if (err == -ENODATA) {
     430           0 :                 nla_nest_cancel(skb, policy);
     431           0 :                 again = true;
     432           0 :                 goto next;
     433           0 :         } else if (err) {
     434           0 :                 goto nla_put_failure;
     435             :         }
     436             : 
     437             :         /* finish and move state to next attribute */
     438           0 :         nla_nest_end(skb, policy);
     439             : 
     440           0 : next:
     441           0 :         state->attr_idx += 1;
     442           0 :         if (state->attr_idx > state->policies[state->policy_idx].maxtype) {
     443           0 :                 state->attr_idx = 0;
     444           0 :                 state->policy_idx++;
     445             :         }
     446             : 
     447           0 :         if (again) {
     448           0 :                 if (netlink_policy_dump_finished(state))
     449             :                         return -ENODATA;
     450           0 :                 goto send_attribute;
     451             :         }
     452             : 
     453             :         return 0;
     454             : 
     455           0 : nla_put_failure:
     456           0 :         nla_nest_cancel(skb, policy);
     457           0 :         return -ENOBUFS;
     458             : }
     459             : 
     460             : /**
     461             :  * netlink_policy_dump_free - free policy dump state
     462             :  * @state: the policy dump state to free
     463             :  *
     464             :  * Call this from the done() method to ensure dump state is freed.
     465             :  */
     466           0 : void netlink_policy_dump_free(struct netlink_policy_dump_state *state)
     467             : {
     468           0 :         kfree(state);
     469           0 : }

Generated by: LCOV version 1.14