diff options
Diffstat (limited to 'backport/compat')
-rw-r--r-- | backport/compat/Kconfig | 5 | ||||
-rw-r--r-- | backport/compat/Makefile | 4 | ||||
-rw-r--r-- | backport/compat/backport-5.2.c (renamed from backport/compat/backport-4.20.c) | 216 | ||||
-rw-r--r-- | backport/compat/backport-genetlink.c | 26 |
4 files changed, 184 insertions, 67 deletions
diff --git a/backport/compat/Kconfig b/backport/compat/Kconfig index 20f34f1a..1d85a5da 100644 --- a/backport/compat/Kconfig +++ b/backport/compat/Kconfig @@ -62,6 +62,11 @@ config BP_MODULES This symbol is necessary for the newer kconf tool, it looks for the "option modules" to control the 'm' state. +config BPAUTO_BUILD_NLATTR + def_bool y + depends on KERNEL_5_2 + #c-file lib/nlattr.c + config BPAUTO_BUILD_CORDIC tristate depends on !CORDIC diff --git a/backport/compat/Makefile b/backport/compat/Makefile index 99b52faa..e92e3120 100644 --- a/backport/compat/Makefile +++ b/backport/compat/Makefile @@ -37,9 +37,7 @@ compat-$(CPTCFG_KERNEL_4_7) += backport-4.7.o compat-$(CPTCFG_KERNEL_4_8) += backport-4.8.o compat-$(CPTCFG_KERNEL_4_10) += backport-4.10.o compat-$(CPTCFG_KERNEL_4_18) += backport-4.18.o -compat-$(CPTCFG_KERNEL_4_20) += backport-4.20.o - -compat-$(CPTCFG_KERNEL_4_20) += backport-genetlink.o +compat-$(CPTCFG_KERNEL_5_2) += backport-5.2.o backport-genetlink.o compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/verify.o compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/pkcs7.asn1.o diff --git a/backport/compat/backport-4.20.c b/backport/compat/backport-5.2.c index e26f3b52..5624d5fa 100644 --- a/backport/compat/backport-4.20.c +++ b/backport/compat/backport-5.2.c @@ -1,19 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2018 Intel Corporation + * NETLINK Netlink attributes * - * Backport functionality introduced in Linux 4.20. - * This is basically upstream lib/nlattr.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * Authors: Thomas Graf <tgraf@suug.ch> + * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> */ -#include <linux/kernel.h> + #include <linux/export.h> +#include <linux/kernel.h> #include <linux/errno.h> +#include <linux/jiffies.h> +#include <linux/skbuff.h> +#include <linux/string.h> #include <linux/types.h> #include <net/netlink.h> +/* For these data types, attribute length should be exactly the given + * size. However, to maintain compatibility with broken commands, if the + * attribute length does not match the expected size a warning is emitted + * to the user that the command is sending invalid data and needs to be fixed. + */ static const u8 nla_attr_len[NLA_TYPE_MAX+1] = { [NLA_U8] = sizeof(u8), [NLA_U16] = sizeof(u16), @@ -63,7 +69,8 @@ static int validate_nla_bitfield32(const struct nlattr *nla, static int nla_validate_array(const struct nlattr *head, int len, int maxtype, const struct nla_policy *policy, - struct netlink_ext_ack *extack) + struct netlink_ext_ack *extack, + unsigned int validate) { const struct nlattr *entry; int rem; @@ -80,8 +87,8 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype, return -ERANGE; } - ret = nla_validate(nla_data(entry), nla_len(entry), - maxtype, policy, extack); + ret = __nla_validate(nla_data(entry), nla_len(entry), + maxtype, policy, validate, extack); if (ret < 0) return ret; } @@ -148,13 +155,17 @@ static int nla_validate_int_range(const struct nla_policy *pt, } static int validate_nla(const struct nlattr *nla, int maxtype, - const struct nla_policy *policy, + const struct nla_policy *policy, unsigned int validate, struct netlink_ext_ack *extack) { + u16 strict_start_type = policy[0].strict_start_type; const struct nla_policy *pt; int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); int err = -ERANGE; + if (strict_start_type && type >= strict_start_type) + validate |= NL_VALIDATE_STRICT; + if (type <= 0 || type > maxtype) return 0; @@ -166,6 +177,26 @@ static int validate_nla(const struct nlattr *nla, int maxtype, (pt->type == NLA_EXACT_LEN_WARN && attrlen != pt->len)) { pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n", current->comm, type); + if (validate & NL_VALIDATE_STRICT_ATTRS) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "invalid attribute length"); + return -EINVAL; + } + } + + if (validate & NL_VALIDATE_NESTED) { + if ((pt->type == NLA_NESTED || pt->type == NLA_NESTED_ARRAY) && + !(nla->nla_type & NLA_F_NESTED)) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "NLA_F_NESTED is missing"); + return -EINVAL; + } + if (pt->type != NLA_NESTED && pt->type != NLA_NESTED_ARRAY && + pt->type != NLA_UNSPEC && (nla->nla_type & NLA_F_NESTED)) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "NLA_F_NESTED not expected"); + return -EINVAL; + } } switch (pt->type) { @@ -238,8 +269,9 @@ static int validate_nla(const struct nlattr *nla, int maxtype, if (attrlen < NLA_HDRLEN) goto out_err; if (pt->validation_data) { - err = nla_validate(nla_data(nla), nla_len(nla), pt->len, - pt->validation_data, extack); + err = __nla_validate(nla_data(nla), nla_len(nla), pt->len, + pt->validation_data, validate, + extack); if (err < 0) { /* * return directly to preserve the inner @@ -262,7 +294,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype, err = nla_validate_array(nla_data(nla), nla_len(nla), pt->len, pt->validation_data, - extack); + extack, validate); if (err < 0) { /* * return directly to preserve the inner @@ -272,10 +304,23 @@ static int validate_nla(const struct nlattr *nla, int maxtype, } } break; + + case NLA_UNSPEC: + if (validate & NL_VALIDATE_UNSPEC) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "Unsupported attribute"); + return -EINVAL; + } + /* fall through */ + case NLA_MIN_LEN: + if (attrlen < pt->len) + goto out_err; + break; + default: if (pt->len) minlen = pt->len; - else if (pt->type != NLA_UNSPEC) + else minlen = nla_attr_minlen[pt->type]; if (attrlen < minlen) @@ -309,25 +354,90 @@ out_err: return err; } -int backport_nla_validate(const struct nlattr *head, int len, int maxtype, - const struct nla_policy *policy, - struct netlink_ext_ack *extack) +static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, + const struct nla_policy *policy, + unsigned int validate, + struct netlink_ext_ack *extack, + struct nlattr **tb) { const struct nlattr *nla; int rem; + if (tb) + memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); + nla_for_each_attr(nla, head, len, rem) { - int err = validate_nla(nla, maxtype, policy, extack); + u16 type = nla_type(nla); - if (err < 0) - return err; + if (type == 0 || type > maxtype) { + if (validate & NL_VALIDATE_MAXTYPE) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "Unknown attribute type"); + return -EINVAL; + } + continue; + } + if (policy) { + int err = validate_nla(nla, maxtype, policy, + validate, extack); + + if (err < 0) + return err; + } + + if (tb) + tb[type] = (struct nlattr *)nla; + } + + if (unlikely(rem > 0)) { + pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", + rem, current->comm); + NL_SET_ERR_MSG(extack, "bytes leftover after parsing attributes"); + if (validate & NL_VALIDATE_TRAILING) + return -EINVAL; } return 0; } -EXPORT_SYMBOL_GPL(backport_nla_validate); -int backport_nla_policy_len(const struct nla_policy *p, int n) +/** + * __nla_validate - Validate a stream of attributes + * @head: head of attribute stream + * @len: length of attribute stream + * @maxtype: maximum attribute type to be expected + * @policy: validation policy + * @validate: validation strictness + * @extack: extended ACK report struct + * + * Validates all attributes in the specified attribute stream against the + * specified policy. Validation depends on the validate flags passed, see + * &enum netlink_validation for more details on that. + * See documenation of struct nla_policy for more details. + * + * Returns 0 on success or a negative error code. + */ +int __nla_validate(const struct nlattr *head, int len, int maxtype, + const struct nla_policy *policy, unsigned int validate, + struct netlink_ext_ack *extack) +{ + return __nla_validate_parse(head, len, maxtype, policy, validate, + extack, NULL); +} +EXPORT_SYMBOL(__nla_validate); + +/** + * nla_policy_len - Determin the max. length of a policy + * @policy: policy to use + * @n: number of policies + * + * Determines the max. length of the policy. It is currently used + * to allocated Netlink buffers roughly the size of the actual + * message. + * + * Returns 0 on success or a negative error code. + */ +int +nla_policy_len(const struct nla_policy *p, int n) { int i, len = 0; @@ -342,38 +452,30 @@ int backport_nla_policy_len(const struct nla_policy *p, int n) return len; } -EXPORT_SYMBOL_GPL(backport_nla_policy_len); - -int backport_nla_parse(struct nlattr **tb, int maxtype, - const struct nlattr *head, - int len, const struct nla_policy *policy, - struct netlink_ext_ack *extack) +EXPORT_SYMBOL(nla_policy_len); + +/** + * __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 + * @validate: validation strictness + * @extack: extended ACK pointer + * + * Parses a stream of attributes and stores a pointer to each attribute in + * the tb array accessible via the attribute type. + * Validation is controlled by the @validate parameter. + * + * 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, unsigned int validate, + struct netlink_ext_ack *extack) { - const struct nlattr *nla; - int rem; - - memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - u16 type = nla_type(nla); - - if (type > 0 && type <= maxtype) { - if (policy) { - int err = validate_nla(nla, maxtype, policy, - extack); - - if (err < 0) - return err; - } - - tb[type] = (struct nlattr *)nla; - } - } - - if (unlikely(rem > 0)) - pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", - rem, current->comm); - - return 0; + return __nla_validate_parse(head, len, maxtype, policy, validate, + extack, tb); } -EXPORT_SYMBOL(backport_nla_parse); +EXPORT_SYMBOL(__nla_parse); diff --git a/backport/compat/backport-genetlink.c b/backport/compat/backport-genetlink.c index 16971ec3..47078589 100644 --- a/backport/compat/backport-genetlink.c +++ b/backport/compat/backport-genetlink.c @@ -167,8 +167,15 @@ static int backport_pre_doit(__genl_const struct genl_ops *ops, struct netlink_ext_ack *extack = info->extack; #endif - err = nlmsg_validate(info->nlhdr, GENL_HDRLEN + family->hdrsize, - family->maxattr, ops->policy, extack); + if (ops->validate & GENL_DONT_VALIDATE_STRICT) + err = nlmsg_validate_deprecated(info->nlhdr, + GENL_HDRLEN + family->hdrsize, + family->maxattr, family->policy, + extack); + else + err = nlmsg_validate(info->nlhdr, GENL_HDRLEN + family->hdrsize, + family->maxattr, family->policy, extack); + if (!err && family->pre_doit) err = family->pre_doit(ops, skb, info); @@ -230,11 +237,15 @@ int backport_genl_register_family(struct genl_family *family) * memory layout isn't compatible with the old version */ for (i = 0; i < family->n_ops; i++) { - ops[i].policy = NULL; #if LINUX_VERSION_IS_LESS(4,12,0) if (ops[i].doit) ops[i].doit = extack_doit; #endif +/* + * TODO: add dumpit redirect (like extack_doit) that will + * make this code honor !GENL_DONT_VALIDATE_DUMP and + * actually validate in this case ... + */ } /* keep doit/dumpit NULL - that's invalid */ ops[family->n_ops].done = (void *)family; @@ -248,12 +259,13 @@ int backport_genl_register_family(struct genl_family *family) #if LINUX_VERSION_IS_GEQ(3,10,0) COPY(parallel_ops); #endif - family->family.pre_doit = backport_pre_doit; - family->family.post_doit = backport_post_doit; + /* The casts are OK - we checked everything is the same offset in genl_ops */ + family->family.pre_doit = (void *)backport_pre_doit; + family->family.post_doit = (void *)backport_post_doit; /* attrbuf is output only */ - family->copy_ops = ops; + family->copy_ops = (void *)ops; #if LINUX_VERSION_IS_GEQ(3,13,0) - family->family.ops = ops; + family->family.ops = (void *)ops; COPY(mcgrps); COPY(n_ops); COPY(n_mcgrps); |