netlink: add validation function to policy
authorJohannes Berg <johannes.berg@intel.com>
Thu, 27 Sep 2018 09:28:36 +0000 (11:28 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Oct 2018 06:05:31 +0000 (23:05 -0700)
Add the ability to have an arbitrary validation function attached
to a netlink policy that doesn't already use the validation_data
pointer in another way.

This can be useful to validate for example the content of a binary
attribute, like in nl80211 the "(information) elements", which must
be valid streams of "u8 type, u8 length, u8 value[length]".

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/netlink.h
lib/nlattr.c

index d34ceeb..6a106ef 100644 (file)
@@ -193,13 +193,14 @@ enum nla_policy_validation {
        NLA_VALIDATE_RANGE,
        NLA_VALIDATE_MIN,
        NLA_VALIDATE_MAX,
+       NLA_VALIDATE_FUNCTION,
 };
 
 /**
  * struct nla_policy - attribute validation policy
  * @type: Type of attribute or NLA_UNSPEC
  * @validation_type: type of attribute validation done in addition to
- *     type-specific validation (e.g. range), see
+ *     type-specific validation (e.g. range, function call), see
  *     &enum nla_policy_validation
  * @len: Type specific length of payload
  *
@@ -269,6 +270,13 @@ enum nla_policy_validation {
  *                         of s16 - do that as usual in the code instead.
  *    All other            Unused - but note that it's a union
  *
+ * Meaning of `validate' field, use via NLA_POLICY_VALIDATE_FN:
+ *    NLA_BINARY           Validation function called for the attribute,
+ *                         not compatible with use of the validation_data
+ *                         as in NLA_BITFIELD32, NLA_REJECT, NLA_NESTED and
+ *                         NLA_NESTED_ARRAY.
+ *    All other            Unused - but note that it's a union
+ *
  * Example:
  * static const struct nla_policy my_policy[ATTR_MAX+1] = {
  *     [ATTR_FOO] = { .type = NLA_U16 },
@@ -286,6 +294,8 @@ struct nla_policy {
                struct {
                        s16 min, max;
                };
+               int (*validate)(const struct nlattr *attr,
+                               struct netlink_ext_ack *extack);
        };
 };
 
@@ -307,6 +317,11 @@ struct nla_policy {
                      tp == NLA_S16 || tp == NLA_U16 || \
                      tp == NLA_S32 || tp == NLA_U32 || \
                      tp == NLA_S64 || tp == NLA_U64) + tp)
+#define NLA_ENSURE_NO_VALIDATION_PTR(tp)               \
+       (__NLA_ENSURE(tp != NLA_BITFIELD32 &&           \
+                     tp != NLA_REJECT &&               \
+                     tp != NLA_NESTED &&               \
+                     tp != NLA_NESTED_ARRAY) + tp)
 
 #define NLA_POLICY_RANGE(tp, _min, _max) {             \
        .type = NLA_ENSURE_INT_TYPE(tp),                \
@@ -327,6 +342,13 @@ struct nla_policy {
        .max = _max,                                    \
 }
 
+#define NLA_POLICY_VALIDATE_FN(tp, fn, ...) {          \
+       .type = NLA_ENSURE_NO_VALIDATION_PTR(tp),       \
+       .validation_type = NLA_VALIDATE_FUNCTION,       \
+       .validate = fn,                                 \
+       .len = __VA_ARGS__ + 0,                         \
+}
+
 /**
  * struct nl_info - netlink source information
  * @nlh: Netlink message header of original request
index 5670e4b..1e900bb 100644 (file)
@@ -300,6 +300,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
                if (err)
                        return err;
                break;
+       case NLA_VALIDATE_FUNCTION:
+               if (pt->validate) {
+                       err = pt->validate(nla, extack);
+                       if (err)
+                               return err;
+               }
+               break;
        }
 
        return 0;