diff options
author | Michal Kubecek <mkubecek@suse.cz> | 2019-05-02 10:15:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-04 01:27:11 -0400 |
commit | b424e432e770d6dd572765459d5b6a96a19c5286 (patch) | |
tree | f2aad0917c7a2e619bca6eefa82eb6b3355fb537 | |
parent | d54a16b20157ce300298eb4a1169bf9acfda3d08 (diff) |
netlink: add validation of NLA_F_NESTED flag
Add new validation flag NL_VALIDATE_NESTED which adds three consistency
checks of NLA_F_NESTED_FLAG:
- the flag is set on attributes with NLA_NESTED{,_ARRAY} policy
- the flag is not set on attributes with other policies except NLA_UNSPEC
- the flag is set on attribute passed to nla_parse_nested()
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
v2: change error messages to mention NLA_F_NESTED explicitly
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Reviewed-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netlink.h | 11 | ||||
-rw-r--r-- | lib/nlattr.c | 15 |
2 files changed, 25 insertions, 1 deletions
diff --git a/include/net/netlink.h b/include/net/netlink.h index 679f649748d4..395b4406f4b0 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h | |||
@@ -401,6 +401,8 @@ struct nl_info { | |||
401 | * are enforced going forward. | 401 | * are enforced going forward. |
402 | * @NL_VALIDATE_STRICT_ATTRS: strict attribute policy parsing (e.g. | 402 | * @NL_VALIDATE_STRICT_ATTRS: strict attribute policy parsing (e.g. |
403 | * U8, U16, U32 must have exact size, etc.) | 403 | * U8, U16, U32 must have exact size, etc.) |
404 | * @NL_VALIDATE_NESTED: Check that NLA_F_NESTED is set for NLA_NESTED(_ARRAY) | ||
405 | * and unset for other policies. | ||
404 | */ | 406 | */ |
405 | enum netlink_validation { | 407 | enum netlink_validation { |
406 | NL_VALIDATE_LIBERAL = 0, | 408 | NL_VALIDATE_LIBERAL = 0, |
@@ -408,6 +410,7 @@ enum netlink_validation { | |||
408 | NL_VALIDATE_MAXTYPE = BIT(1), | 410 | NL_VALIDATE_MAXTYPE = BIT(1), |
409 | NL_VALIDATE_UNSPEC = BIT(2), | 411 | NL_VALIDATE_UNSPEC = BIT(2), |
410 | NL_VALIDATE_STRICT_ATTRS = BIT(3), | 412 | NL_VALIDATE_STRICT_ATTRS = BIT(3), |
413 | NL_VALIDATE_NESTED = BIT(4), | ||
411 | }; | 414 | }; |
412 | 415 | ||
413 | #define NL_VALIDATE_DEPRECATED_STRICT (NL_VALIDATE_TRAILING |\ | 416 | #define NL_VALIDATE_DEPRECATED_STRICT (NL_VALIDATE_TRAILING |\ |
@@ -415,7 +418,8 @@ enum netlink_validation { | |||
415 | #define NL_VALIDATE_STRICT (NL_VALIDATE_TRAILING |\ | 418 | #define NL_VALIDATE_STRICT (NL_VALIDATE_TRAILING |\ |
416 | NL_VALIDATE_MAXTYPE |\ | 419 | NL_VALIDATE_MAXTYPE |\ |
417 | NL_VALIDATE_UNSPEC |\ | 420 | NL_VALIDATE_UNSPEC |\ |
418 | NL_VALIDATE_STRICT_ATTRS) | 421 | NL_VALIDATE_STRICT_ATTRS |\ |
422 | NL_VALIDATE_NESTED) | ||
419 | 423 | ||
420 | int netlink_rcv_skb(struct sk_buff *skb, | 424 | int netlink_rcv_skb(struct sk_buff *skb, |
421 | int (*cb)(struct sk_buff *, struct nlmsghdr *, | 425 | int (*cb)(struct sk_buff *, struct nlmsghdr *, |
@@ -1132,6 +1136,11 @@ static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, | |||
1132 | const struct nla_policy *policy, | 1136 | const struct nla_policy *policy, |
1133 | struct netlink_ext_ack *extack) | 1137 | struct netlink_ext_ack *extack) |
1134 | { | 1138 | { |
1139 | if (!(nla->nla_type & NLA_F_NESTED)) { | ||
1140 | NL_SET_ERR_MSG_ATTR(extack, nla, "NLA_F_NESTED is missing"); | ||
1141 | return -EINVAL; | ||
1142 | } | ||
1143 | |||
1135 | return __nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy, | 1144 | return __nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy, |
1136 | NL_VALIDATE_STRICT, extack); | 1145 | NL_VALIDATE_STRICT, extack); |
1137 | } | 1146 | } |
diff --git a/lib/nlattr.c b/lib/nlattr.c index adc919b32bf9..cace9b307781 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c | |||
@@ -184,6 +184,21 @@ static int validate_nla(const struct nlattr *nla, int maxtype, | |||
184 | } | 184 | } |
185 | } | 185 | } |
186 | 186 | ||
187 | if (validate & NL_VALIDATE_NESTED) { | ||
188 | if ((pt->type == NLA_NESTED || pt->type == NLA_NESTED_ARRAY) && | ||
189 | !(nla->nla_type & NLA_F_NESTED)) { | ||
190 | NL_SET_ERR_MSG_ATTR(extack, nla, | ||
191 | "NLA_F_NESTED is missing"); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | if (pt->type != NLA_NESTED && pt->type != NLA_NESTED_ARRAY && | ||
195 | pt->type != NLA_UNSPEC && (nla->nla_type & NLA_F_NESTED)) { | ||
196 | NL_SET_ERR_MSG_ATTR(extack, nla, | ||
197 | "NLA_F_NESTED not expected"); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | } | ||
201 | |||
187 | switch (pt->type) { | 202 | switch (pt->type) { |
188 | case NLA_EXACT_LEN: | 203 | case NLA_EXACT_LEN: |
189 | if (attrlen != pt->len) | 204 | if (attrlen != pt->len) |