diff options
author | Johannes Berg <johannes.berg@intel.com> | 2018-10-02 17:22:45 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2018-10-02 21:25:49 +0200 |
commit | b49a73b91de67fda787669b0c889fa2c5a24b0a6 (patch) | |
tree | e02472583133b4f00b17b9bd425e164d1c496a33 /backport/backport-include/net | |
parent | d285fc4bc91fe23500bd78fa8b7bae22e21bddd8 (diff) |
backports: backport most of improved netlink policy validation
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'backport/backport-include/net')
-rw-r--r-- | backport/backport-include/net/netlink.h | 185 |
1 files changed, 173 insertions, 12 deletions
diff --git a/backport/backport-include/net/netlink.h b/backport/backport-include/net/netlink.h index 7775bc82..4af73631 100644 --- a/backport/backport-include/net/netlink.h +++ b/backport/backport-include/net/netlink.h @@ -4,6 +4,162 @@ #include <linux/version.h> #include <linux/in6.h> +#if LINUX_VERSION_IS_LESS(4,20,0) +/* can't backport using the enum - need to override */ +#define NLA_UNSPEC 0 +#define NLA_U8 1 +#define NLA_U16 2 +#define NLA_U32 3 +#define NLA_U64 4 +#define NLA_STRING 5 +#define NLA_FLAG 6 +#define NLA_MSECS 7 +#define NLA_NESTED 8 +#define NLA_NESTED_ARRAY 9 +#define NLA_NUL_STRING 10 +#define NLA_BINARY 11 +#define NLA_S8 12 +#define NLA_S16 13 +#define NLA_S32 14 +#define NLA_S64 15 +#define NLA_BITFIELD32 16 +#define NLA_REJECT 17 +#define NLA_EXACT_LEN 18 +#define NLA_EXACT_LEN_WARN 19 +#define __NLA_TYPE_MAX 20 +#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) + +enum nla_policy_validation { + NLA_VALIDATE_NONE, + NLA_VALIDATE_RANGE, + NLA_VALIDATE_MIN, + NLA_VALIDATE_MAX, + NLA_VALIDATE_FUNCTION, +}; + +struct backport_nla_policy { + u8 type; + u8 validation_type; + u16 len; + union { + const void *validation_data; + struct { + s16 min, max; + }; + int (*validate)(const struct nlattr *attr, + struct netlink_ext_ack *extack); + }; +}; +#define nla_policy backport_nla_policy + +#define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len } +#define NLA_POLICY_EXACT_LEN_WARN(_len) { .type = NLA_EXACT_LEN_WARN, \ + .len = _len } + +#define NLA_POLICY_ETH_ADDR NLA_POLICY_EXACT_LEN(ETH_ALEN) +#define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN) + +#define NLA_POLICY_NESTED(maxattr, policy) \ + { .type = NLA_NESTED, .validation_data = policy, .len = maxattr } +#define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \ + { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr } + +#define __NLA_ENSURE(condition) (sizeof(char[1 - 2*!(condition)]) - 1) +#define NLA_ENSURE_INT_TYPE(tp) \ + (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \ + 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), \ + .validation_type = NLA_VALIDATE_RANGE, \ + .min = _min, \ + .max = _max \ +} + +#define NLA_POLICY_MIN(tp, _min) { \ + .type = NLA_ENSURE_INT_TYPE(tp), \ + .validation_type = NLA_VALIDATE_MIN, \ + .min = _min, \ +} + +#define NLA_POLICY_MAX(tp, _max) { \ + .type = NLA_ENSURE_INT_TYPE(tp), \ + .validation_type = NLA_VALIDATE_MAX, \ + .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, \ +} + +#define nla_validate LINUX_BACKPORT(nla_validate) +int nla_validate(const struct nlattr *head, int len, int maxtype, + const struct nla_policy *policy, + struct netlink_ext_ack *extack); +#define nla_parse LINUX_BACKPORT(nla_parse) +int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, + int len, const struct nla_policy *policy, + struct netlink_ext_ack *extack); +#define nla_policy_len LINUX_BACKPORT(nla_policy_len) +int nla_policy_len(const struct nla_policy *, int); + +#define nlmsg_parse LINUX_BACKPORT(nlmsg_parse) +static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, + struct nlattr *tb[], int maxtype, + const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + return -EINVAL; + + return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), policy, extack); +} + +#define nlmsg_validate LINUX_BACKPORT(nlmsg_validate) +static inline int nlmsg_validate(const struct nlmsghdr *nlh, + int hdrlen, int maxtype, + const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + return -EINVAL; + + return nla_validate(nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), maxtype, policy, + extack); +} + +#define nla_parse_nested LINUX_BACKPORT(nla_parse_nested) +static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, + const struct nlattr *nla, + const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy, + extack); +} + +#define nla_validate_nested LINUX_BACKPORT(nla_validate_nested) +static inline int nla_validate_nested(const struct nlattr *start, int maxtype, + const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + return nla_validate(nla_data(start), nla_len(start), maxtype, policy, + extack); +} +#endif /* < 4.20 */ + #if LINUX_VERSION_IS_LESS(4,12,0) #include <backport/magic.h> @@ -12,13 +168,13 @@ static inline int _nla_validate5(const struct nlattr *head, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - return nla_validate(head, len, maxtype, policy); + return nla_validate(head, len, maxtype, policy, extack); } static inline int _nla_validate4(const struct nlattr *head, int len, int maxtype, const struct nla_policy *policy) { - return nla_validate(head, len, maxtype, policy); + return nla_validate(head, len, maxtype, policy, NULL); } #undef nla_validate #define nla_validate(...) \ @@ -29,14 +185,15 @@ static inline int _nla_parse6(struct nlattr **tb, int maxtype, int len, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - return nla_parse(tb, maxtype, head, len, policy); + return nla_parse(tb, maxtype, head, len, policy, extack); } static inline int _nla_parse5(struct nlattr **tb, int maxtype, const struct nlattr *head, int len, const struct nla_policy *policy) { - return nla_parse(tb, maxtype, head, len, policy); + return nla_parse(tb, maxtype, head, len, policy, NULL); } +#undef nla_parse #define nla_parse(...) \ macro_dispatcher(_nla_parse, __VA_ARGS__)(__VA_ARGS__) @@ -45,14 +202,15 @@ static inline int _nlmsg_parse6(const struct nlmsghdr *nlh, int hdrlen, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - return nlmsg_parse(nlh, hdrlen, tb, maxtype, policy); + return nlmsg_parse(nlh, hdrlen, tb, maxtype, policy, extack); } static inline int _nlmsg_parse5(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { - return nlmsg_parse(nlh, hdrlen, tb, maxtype, policy); + return nlmsg_parse(nlh, hdrlen, tb, maxtype, policy, NULL); } +#undef nlmsg_parse #define nlmsg_parse(...) \ macro_dispatcher(_nlmsg_parse, __VA_ARGS__)(__VA_ARGS__) @@ -61,14 +219,15 @@ static inline int _nlmsg_validate5(const struct nlmsghdr *nlh, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - return nlmsg_validate(nlh, hdrlen, maxtype, policy); + return nlmsg_validate(nlh, hdrlen, maxtype, policy, extack); } static inline int _nlmsg_validate4(const struct nlmsghdr *nlh, int hdrlen, int maxtype, const struct nla_policy *policy) { - return nlmsg_validate(nlh, hdrlen, maxtype, policy); + return nlmsg_validate(nlh, hdrlen, maxtype, policy, NULL); } +#undef nlmsg_validate #define nlmsg_validate(...) \ macro_dispatcher(_nlmsg_validate, __VA_ARGS__)(__VA_ARGS__) @@ -77,14 +236,15 @@ static inline int _nla_parse_nested5(struct nlattr *tb[], int maxtype, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - return nla_parse_nested(tb, maxtype, nla, policy); + return nla_parse_nested(tb, maxtype, nla, policy, extack); } static inline int _nla_parse_nested4(struct nlattr *tb[], int maxtype, const struct nlattr *nla, const struct nla_policy *policy) { - return nla_parse_nested(tb, maxtype, nla, policy); + return nla_parse_nested(tb, maxtype, nla, policy, NULL); } +#undef nla_parse_nested #define nla_parse_nested(...) \ macro_dispatcher(_nla_parse_nested, __VA_ARGS__)(__VA_ARGS__) @@ -92,13 +252,14 @@ static inline int _nla_validate_nested4(const struct nlattr *start, int maxtype, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - return nla_validate_nested(start, maxtype, policy); + return nla_validate_nested(start, maxtype, policy, extack); } static inline int _nla_validate_nested3(const struct nlattr *start, int maxtype, const struct nla_policy *policy) { - return nla_validate_nested(start, maxtype, policy); + return nla_validate_nested(start, maxtype, policy, NULL); } +#undef nla_validate_nested #define nla_validate_nested(...) \ macro_dispatcher(_nla_validate_nested, __VA_ARGS__)(__VA_ARGS__) #endif /* LINUX_VERSION_IS_LESS(4,12,0) */ |