Enhance the attribute parsing functions to support strict attribute
checking. Keep the semantics of the current nla_parse and nlmsg_parse
functions, it's better then changing hundreds of call sites all around the
kernel.

Signed-off-by: Jiri Benc <jb...@redhat.com>
---
 include/net/netlink.h | 75 ++++++++++++++++++++++++++++++++++++++++++++-------
 lib/nlattr.c          | 20 +++++++++-----
 2 files changed, 80 insertions(+), 15 deletions(-)

diff --git a/include/net/netlink.h b/include/net/netlink.h
index 160e98cea304..dcca6853913d 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -235,8 +235,9 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 
portid,
 
 int nla_validate(const struct nlattr *head, int len, int maxtype,
                 const struct nla_policy *policy);
-int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
-             int len, const struct nla_policy *policy);
+int nla_strict_parse(struct nlattr **tb, int maxtype, bool strict,
+                    const struct nlattr *head, int len,
+                    const struct nla_policy *policy);
 int nla_policy_len(const struct nla_policy *, int);
 struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype);
 size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize);
@@ -356,6 +357,30 @@ nlmsg_next(const struct nlmsghdr *nlh, int *remaining)
 }
 
 /**
+ * nlmsg_strict_parse - parse attributes of a netlink message
+ * @nlh: netlink message header
+ * @hdrlen: length of family specific header
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @strict: whether to perform strict checking
+ * @policy: validation policy
+ *
+ * See nla_strict_parse().
+ */
+static inline int nlmsg_strict_parse(const struct nlmsghdr *nlh, int hdrlen,
+                                    struct nlattr *tb[], int maxtype,
+                                    bool strict,
+                                    const struct nla_policy *policy)
+{
+       if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+               return -EINVAL;
+
+       return nla_strict_parse(tb, maxtype, strict,
+                               nlmsg_attrdata(nlh, hdrlen),
+                               nlmsg_attrlen(nlh, hdrlen), policy);
+}
+
+/**
  * nlmsg_parse - parse attributes of a netlink message
  * @nlh: netlink message header
  * @hdrlen: length of family specific header
@@ -363,17 +388,13 @@ nlmsg_next(const struct nlmsghdr *nlh, int *remaining)
  * @maxtype: maximum attribute type to be expected
  * @policy: validation policy
  *
- * See nla_parse()
+ * See nla_strict_parse(). Strict checking is not performed.
  */
 static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
                              struct nlattr *tb[], int maxtype,
                              const struct nla_policy *policy)
 {
-       if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
-               return -EINVAL;
-
-       return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
-                        nlmsg_attrlen(nlh, hdrlen), policy);
+       return nlmsg_strict_parse(nlh, hdrlen, tb, maxtype, false, policy);
 }
 
 /**
@@ -722,13 +743,49 @@ nla_find_nested(const struct nlattr *nla, int attrtype)
 }
 
 /**
+ * nla_parse - Parse a stream of attributes into a tb buffer
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @policy: validation policy
+ *
+ * See nla_strict_parse(). Strict checking is not performed.
+ */
+static inline int nla_parse(struct nlattr **tb, int maxtype,
+                           const struct nlattr *head, int len,
+                           const struct nla_policy *policy)
+{
+       return nla_strict_parse(tb, maxtype, false, head, len, policy);
+}
+
+/**
+ * nla_strict_parse_nested - parse nested attributes
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @strict: whether to perform strict checking
+ * @nla: attribute containing the nested attributes
+ * @policy: validation policy
+ *
+ * See nla_strict_parse(). Strict checking is not performed.
+ */
+static inline int nla_strict_parse_nested(struct nlattr *tb[], int maxtype,
+                                         bool strict,
+                                         const struct nlattr *nla,
+                                         const struct nla_policy *policy)
+{
+       return nla_strict_parse(tb, maxtype, strict, nla_data(nla),
+                               nla_len(nla), policy);
+}
+
+/**
  * nla_parse_nested - parse nested attributes
  * @tb: destination array with maxtype+1 elements
  * @maxtype: maximum attribute type to be expected
  * @nla: attribute containing the nested attributes
  * @policy: validation policy
  *
- * See nla_parse()
+ * See nla_strict_parse()
  */
 static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
                                   const struct nlattr *nla,
diff --git a/lib/nlattr.c b/lib/nlattr.c
index b35c3e6c8e81..2b36388eb3a9 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -163,9 +163,10 @@ nla_policy_len(const struct nla_policy *p, int n)
 EXPORT_SYMBOL(nla_policy_len);
 
 /**
- * nla_parse - Parse a stream of attributes into a tb buffer
+ * nla_strict_parse - Parse a stream of attributes into a tb buffer
  * @tb: destination array with maxtype+1 elements
  * @maxtype: maximum attribute type to be expected
+ * @strict: whether to perform strict checking
  * @head: head of attribute stream
  * @len: length of attribute stream
  * @policy: validation policy
@@ -173,12 +174,14 @@ EXPORT_SYMBOL(nla_policy_len);
  * Parses a stream of attributes and stores a pointer to each attribute in
  * the tb array accessible via the attribute type. Attributes with a type
  * exceeding maxtype will be silently ignored for backwards compatibility
- * reasons. policy may be set to NULL if no validation is required.
+ * reasons, unless strict is set. policy may be set to NULL if no validation
+ * is required.
  *
  * Returns 0 on success or a negative error code.
  */
-int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
-             int len, const struct nla_policy *policy)
+int nla_strict_parse(struct nlattr **tb, int maxtype, bool strict,
+                    const struct nlattr *head, int len,
+                    const struct nla_policy *policy)
 {
        const struct nlattr *nla;
        int rem, err;
@@ -196,16 +199,21 @@ int nla_parse(struct nlattr **tb, int maxtype, const 
struct nlattr *head,
                        }
 
                        tb[type] = (struct nlattr *)nla;
+               } else if (strict) {
+                       return -EINVAL;
                }
        }
 
-       if (unlikely(rem > 0))
+       if (unlikely(rem > 0)) {
                pr_warn_ratelimited("netlink: %d bytes leftover after parsing 
attributes in process `%s'.\n",
                                    rem, current->comm);
+               if (strict)
+                       return -EINVAL;
+       }
 
        return 0;
 }
-EXPORT_SYMBOL(nla_parse);
+EXPORT_SYMBOL(nla_strict_parse);
 
 /**
  * nla_find - Find a specific attribute in a stream of attributes
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to