summaryrefslogtreecommitdiff
path: root/backport/compat
diff options
context:
space:
mode:
Diffstat (limited to 'backport/compat')
-rw-r--r--backport/compat/Kconfig5
-rw-r--r--backport/compat/Makefile4
-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.c26
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);