From: Johannes Berg <johannes.b...@intel.com>

Now that we have a validation_data pointer, and the len field in
the policy is unused for NLA_NESTED, we can allow using them both
to have nested validation. This can be nice in code, although we
still have to use nla_parse_nested() or similar which would also
take a policy; however, it also serves as documentation in the
policy without requiring a look at the code.

Signed-off-by: Johannes Berg <johannes.b...@intel.com>
---
 include/net/netlink.h | 10 ++++++++--
 lib/nlattr.c          | 17 +++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/include/net/netlink.h b/include/net/netlink.h
index b680fe365e91..6efa25a004f5 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -200,8 +200,10 @@ enum {
  *    NLA_NUL_STRING       Maximum length of string (excluding NUL)
  *    NLA_FLAG             Unused
  *    NLA_BINARY           Maximum length of attribute payload
- *    NLA_NESTED           Don't use `len' field -- length verification is
- *                         done by checking len of nested header (or empty)
+ *    NLA_NESTED           Length verification is done by checking len of
+ *                         nested header (or empty); len field is used if
+ *                         validation_data is also used, for the max attr
+ *                         number in the nested policy.
  *    NLA_U8, NLA_U16,
  *    NLA_U32, NLA_U64,
  *    NLA_S8, NLA_S16,
@@ -224,6 +226,10 @@ enum {
  *    NLA_REJECT           This attribute is always rejected and validation 
data
  *                         may point to a string to report as the error instead
  *                         of the generic one in extended ACK.
+ *    NLA_NESTED           Points to a nested policy to validate, must also set
+ *                         `len' to the max attribute number.
+ *                         Note that nla_parse() will validate, but of course 
not
+ *                         parse, the nested sub-policies.
  *    All other            Unused
  *
  * Example:
diff --git a/lib/nlattr.c b/lib/nlattr.c
index fecc7b834706..4c8c4fffb20d 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -68,6 +68,11 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
        return 0;
 }
 
+static int nla_validate_parse(const struct nlattr *head, int len, int maxtype,
+                             const struct nla_policy *policy,
+                             struct netlink_ext_ack *extack, bool *extack_set,
+                             struct nlattr **tb);
+
 static int validate_nla(const struct nlattr *nla, int maxtype,
                        const struct nla_policy *policy,
                        struct netlink_ext_ack *extack, bool *extack_set)
@@ -149,6 +154,18 @@ static int validate_nla(const struct nlattr *nla, int 
maxtype,
                 */
                if (attrlen == 0)
                        break;
+               if (attrlen < NLA_HDRLEN)
+                       return -ERANGE;
+               if (pt->validation_data) {
+                       int err;
+
+                       err = nla_validate_parse(nla_data(nla), nla_len(nla),
+                                                pt->len, pt->validation_data,
+                                                extack, extack_set, NULL);
+                       if (err < 0)
+                               return err;
+               }
+               break;
        default:
                if (pt->len)
                        minlen = pt->len;
-- 
2.14.4

Reply via email to