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