OSDN Git Service

netlink: introduce NLA_POLICY_MAX_BE
authorFlorian Westphal <fw@strlen.de>
Mon, 5 Sep 2022 10:09:36 +0000 (12:09 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 7 Sep 2022 11:33:43 +0000 (12:33 +0100)
netlink allows to specify allowed ranges for integer types.
Unfortunately, nfnetlink passes integers in big endian, so the existing
NLA_POLICY_MAX() cannot be used.

At the moment, nfnetlink users, such as nf_tables, need to resort to
programmatic checking via helpers such as nft_parse_u32_check().

This is both cumbersome and error prone.  This adds NLA_POLICY_MAX_BE
which adds range check support for BE16, BE32 and BE64 integers.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/netlink.h
lib/nlattr.c

index e658d18..4418b19 100644 (file)
@@ -325,6 +325,7 @@ struct nla_policy {
                struct netlink_range_validation_signed *range_signed;
                struct {
                        s16 min, max;
+                       u8 network_byte_order:1;
                };
                int (*validate)(const struct nlattr *attr,
                                struct netlink_ext_ack *extack);
@@ -418,6 +419,14 @@ struct nla_policy {
        .type = NLA_ENSURE_INT_OR_BINARY_TYPE(tp),      \
        .validation_type = NLA_VALIDATE_MAX,            \
        .max = _max,                                    \
+       .network_byte_order = 0,                        \
+}
+
+#define NLA_POLICY_MAX_BE(tp, _max) {                  \
+       .type = NLA_ENSURE_UINT_TYPE(tp),               \
+       .validation_type = NLA_VALIDATE_MAX,            \
+       .max = _max,                                    \
+       .network_byte_order = 1,                        \
 }
 
 #define NLA_POLICY_MASK(tp, _mask) {                   \
index 86029ad..40f22b1 100644 (file)
@@ -159,6 +159,31 @@ void nla_get_range_unsigned(const struct nla_policy *pt,
        }
 }
 
+static u64 nla_get_attr_bo(const struct nla_policy *pt,
+                          const struct nlattr *nla)
+{
+       switch (pt->type) {
+       case NLA_U16:
+               if (pt->network_byte_order)
+                       return ntohs(nla_get_be16(nla));
+
+               return nla_get_u16(nla);
+       case NLA_U32:
+               if (pt->network_byte_order)
+                       return ntohl(nla_get_be32(nla));
+
+               return nla_get_u32(nla);
+       case NLA_U64:
+               if (pt->network_byte_order)
+                       return be64_to_cpu(nla_get_be64(nla));
+
+               return nla_get_u64(nla);
+       }
+
+       WARN_ON_ONCE(1);
+       return 0;
+}
+
 static int nla_validate_range_unsigned(const struct nla_policy *pt,
                                       const struct nlattr *nla,
                                       struct netlink_ext_ack *extack,
@@ -172,12 +197,10 @@ static int nla_validate_range_unsigned(const struct nla_policy *pt,
                value = nla_get_u8(nla);
                break;
        case NLA_U16:
-               value = nla_get_u16(nla);
-               break;
        case NLA_U32:
-               value = nla_get_u32(nla);
-               break;
        case NLA_U64:
+               value = nla_get_attr_bo(pt, nla);
+               break;
        case NLA_MSECS:
                value = nla_get_u64(nla);
                break;