All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/6] backports: rename magic functions for netlink parsing
@ 2018-10-02 17:51 Johannes Berg
  2018-10-02 17:51 ` [PATCH 2/6] backports: fix genlmsg_nlhdr() backport Johannes Berg
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 17:51 UTC (permalink / raw)
  To: backports; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Make all the magic variable argument calls inlines and
rename them so we can override them more easily later.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 backport/backport-include/net/netlink.h | 100 +++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 35 deletions(-)

diff --git a/backport/backport-include/net/netlink.h b/backport/backport-include/net/netlink.h
index 37c899b07b1d..7775bc8295c3 100644
--- a/backport/backport-include/net/netlink.h
+++ b/backport/backport-include/net/netlink.h
@@ -7,70 +7,100 @@
 #if LINUX_VERSION_IS_LESS(4,12,0)
 #include <backport/magic.h>
 
-static inline int nla_validate5(const struct nlattr *head,
-				int len, int maxtype,
-				const struct nla_policy *policy,
-				struct netlink_ext_ack *extack)
+static inline int _nla_validate5(const struct nlattr *head,
+				 int len, int maxtype,
+				 const struct nla_policy *policy,
+				 struct netlink_ext_ack *extack)
 {
 	return nla_validate(head, len, maxtype, policy);
 }
-#define nla_validate4 nla_validate
+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);
+}
+#undef nla_validate
 #define nla_validate(...) \
-	macro_dispatcher(nla_validate, __VA_ARGS__)(__VA_ARGS__)
+	macro_dispatcher(_nla_validate, __VA_ARGS__)(__VA_ARGS__)
 
-static inline int nla_parse6(struct nlattr **tb, int maxtype,
-			     const struct nlattr *head,
-			     int len, const struct nla_policy *policy,
-			     struct netlink_ext_ack *extack)
+static inline int _nla_parse6(struct nlattr **tb, int maxtype,
+			      const struct nlattr *head,
+			      int len, const struct nla_policy *policy,
+			      struct netlink_ext_ack *extack)
+{
+	return nla_parse(tb, maxtype, head, len, policy);
+}
+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);
 }
-#define nla_parse5(...) nla_parse(__VA_ARGS__)
 #define nla_parse(...) \
-	macro_dispatcher(nla_parse, __VA_ARGS__)(__VA_ARGS__)
+	macro_dispatcher(_nla_parse, __VA_ARGS__)(__VA_ARGS__)
 
-static inline int nlmsg_parse6(const struct nlmsghdr *nlh, int hdrlen,
-			       struct nlattr *tb[], int maxtype,
-			       const struct nla_policy *policy,
-			       struct netlink_ext_ack *extack)
+static inline int _nlmsg_parse6(const struct nlmsghdr *nlh, int hdrlen,
+			        struct nlattr *tb[], int maxtype,
+			        const struct nla_policy *policy,
+			        struct netlink_ext_ack *extack)
+{
+	return nlmsg_parse(nlh, hdrlen, tb, maxtype, policy);
+}
+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);
 }
-#define nlmsg_parse5 nlmsg_parse
 #define nlmsg_parse(...) \
-	macro_dispatcher(nlmsg_parse, __VA_ARGS__)(__VA_ARGS__)
+	macro_dispatcher(_nlmsg_parse, __VA_ARGS__)(__VA_ARGS__)
 
-static inline int nlmsg_validate5(const struct nlmsghdr *nlh,
-				  int hdrlen, int maxtype,
-				  const struct nla_policy *policy,
-				  struct netlink_ext_ack *extack)
+static inline int _nlmsg_validate5(const struct nlmsghdr *nlh,
+				   int hdrlen, int maxtype,
+				   const struct nla_policy *policy,
+				   struct netlink_ext_ack *extack)
+{
+	return nlmsg_validate(nlh, hdrlen, maxtype, policy);
+}
+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);
 }
-#define nlmsg_validate4 nlmsg_validate
 #define nlmsg_validate(...) \
-	macro_dispatcher(nlmsg_validate, __VA_ARGS__)(__VA_ARGS__)
+	macro_dispatcher(_nlmsg_validate, __VA_ARGS__)(__VA_ARGS__)
 
-static inline int nla_parse_nested5(struct nlattr *tb[], int maxtype,
-				    const struct nlattr *nla,
-				    const struct nla_policy *policy,
-				    struct netlink_ext_ack *extack)
+static inline int _nla_parse_nested5(struct nlattr *tb[], int maxtype,
+				     const struct nlattr *nla,
+				     const struct nla_policy *policy,
+				     struct netlink_ext_ack *extack)
+{
+	return nla_parse_nested(tb, maxtype, nla, policy);
+}
+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);
 }
-#define nla_parse_nested4 nla_parse_nested
 #define nla_parse_nested(...) \
-	macro_dispatcher(nla_parse_nested, __VA_ARGS__)(__VA_ARGS__)
+	macro_dispatcher(_nla_parse_nested, __VA_ARGS__)(__VA_ARGS__)
 
-static inline int nla_validate_nested4(const struct nlattr *start, int maxtype,
-				       const struct nla_policy *policy,
-				       struct netlink_ext_ack *extack)
+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);
+}
+static inline int _nla_validate_nested3(const struct nlattr *start, int maxtype,
+					const struct nla_policy *policy)
 {
 	return nla_validate_nested(start, maxtype, policy);
 }
-#define nla_validate_nested3 nla_validate_nested
 #define nla_validate_nested(...) \
-	macro_dispatcher(nla_validate_nested, __VA_ARGS__)(__VA_ARGS__)
+	macro_dispatcher(_nla_validate_nested, __VA_ARGS__)(__VA_ARGS__)
 #endif /* LINUX_VERSION_IS_LESS(4,12,0) */
 
 #if LINUX_VERSION_IS_LESS(3,7,0)
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/6] backports: fix genlmsg_nlhdr() backport
  2018-10-02 17:51 [PATCH 1/6] backports: rename magic functions for netlink parsing Johannes Berg
@ 2018-10-02 17:51 ` Johannes Berg
  2018-10-02 17:51 ` [PATCH 3/6] backports: add copy-list.hwsim Johannes Berg
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 17:51 UTC (permalink / raw)
  To: backports; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Since 4.15 this no longer takes a family argument, so add that
to the backports instead of trying to work around the family
argument having changed type.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 backport/backport-include/net/genetlink.h | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/backport/backport-include/net/genetlink.h b/backport/backport-include/net/genetlink.h
index dfbacbf40723..d80d979ac423 100644
--- a/backport/backport-include/net/genetlink.h
+++ b/backport/backport-include/net/genetlink.h
@@ -60,6 +60,14 @@ static inline void *genl_info_userhdr(struct genl_info *info)
 #endif
 
 #if LINUX_VERSION_IS_LESS(4,15,0)
+#define genlmsg_nlhdr LINUX_BACKPORT(genlmsg_nlhdr)
+static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr)
+{
+	return (struct nlmsghdr *)((char *)user_hdr -
+				   GENL_HDRLEN -
+				   NLMSG_HDRLEN);
+}
+
 #ifndef genl_dump_check_consistent
 static inline
 void backport_genl_dump_check_consistent(struct netlink_callback *cb,
@@ -153,8 +161,6 @@ extern void genl_notify(struct sk_buff *skb, struct net *net, u32 pid,
 		    (_fam)->mcgrps[_group].id, _info->nlhdr, _flags)
 #define genlmsg_put(_skb, _pid, _seq, _fam, _flags, _cmd)		\
 	genlmsg_put(_skb, _pid, _seq, &(_fam)->family, _flags, _cmd)
-#define genlmsg_nlhdr(_hdr, _fam)					\
-	genlmsg_nlhdr(_hdr, &(_fam)->family)
 
 #ifndef genlmsg_put_reply /* might already be there from _info override above */
 #define genlmsg_put_reply(_skb, _info, _fam, _flags, _cmd)		\
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/6] backports: add copy-list.hwsim
  2018-10-02 17:51 [PATCH 1/6] backports: rename magic functions for netlink parsing Johannes Berg
  2018-10-02 17:51 ` [PATCH 2/6] backports: fix genlmsg_nlhdr() backport Johannes Berg
@ 2018-10-02 17:51 ` Johannes Berg
  2018-10-02 17:51 ` [PATCH 4/6] backports: backport most of improved netlink policy validation Johannes Berg
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 17:51 UTC (permalink / raw)
  To: backports; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

This is can be useful for minimal testing.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 copy-list.hwsim | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 copy-list.hwsim

diff --git a/copy-list.hwsim b/copy-list.hwsim
new file mode 100644
index 000000000000..c56f0bcb915c
--- /dev/null
+++ b/copy-list.hwsim
@@ -0,0 +1,91 @@
+#
+# This file specifies which sources are copied from the kernel
+# into the backports package.
+#
+# Directories must end with a slash (e.g. "net/wireless/") and
+# are then copied with all their contents.
+#
+# It is also possible to rename while copying, to do so list
+# old name -> new name
+# Note that in this case the spaces are needed: " -> "
+#
+
+COPYING
+MAINTAINERS
+include/linux/unaligned/
+include/linux/hashtable.h
+include/linux/fixp-arith.h
+include/linux/crc32poly.h
+
+# This just defines some macros, simply take it
+include/linux/bitfield.h
+include/linux/average.h
+include/linux/overflow.h
+
+# crypto_memneq
+crypto/memneq.c -> compat/memneq.c
+
+# 802.11
+drivers/net/wireless/Kconfig
+drivers/net/wireless/Makefile
+
+include/linux/wireless.h
+include/uapi/linux/wireless.h
+include/linux/ieee80211.h
+include/linux/pci_ids.h
+include/uapi/linux/pci_regs.h
+include/linux/mmc/sdio_ids.h
+include/linux/ath9k_platform.h
+include/linux/wl12xx.h
+include/linux/rndis.h
+include/linux/bcm47xx_wdt.h
+include/linux/usb/usbnet.h
+include/linux/usb/cdc.h
+include/uapi/linux/usb/cdc.h
+include/uapi/linux/usb/cdc-wdm.h
+include/linux/usb/cdc_ncm.h
+include/linux/usb/cdc-wdm.h
+include/linux/usb/rndis_host.h
+include/linux/spi/libertas_spi.h
+include/linux/platform_data/brcmfmac.h
+include/linux/platform_data/net-cw1200.h
+include/uapi/linux/nl80211.h
+include/net/rsi_91x.h
+
+include/net/cfg80211.h
+include/net/cfg80211-wext.h
+include/net/ieee80211_radiotap.h
+include/net/lib80211.h
+include/net/mac80211.h
+include/net/regulatory.h
+include/net/codel.h
+include/net/codel_impl.h
+include/net/codel_qdisc.h
+include/net/fq.h
+include/net/fq_impl.h
+
+# signature verification code
+include/linux/asn1.h
+include/linux/asn1_ber_bytecode.h
+include/linux/oid_registry.h
+lib/build_OID_registry -> compat/build_OID_registry
+crypto/asymmetric_keys/pkcs7_parser.c -> compat/verification/pkcs7_parser.c
+crypto/asymmetric_keys/pkcs7_parser.h -> compat/verification/pkcs7_parser.h
+crypto/asymmetric_keys/pkcs7_trust.c -> compat/verification/pkcs7_trust.c
+crypto/asymmetric_keys/pkcs7_verify.c -> compat/verification/pkcs7_verify.c
+crypto/asymmetric_keys/x509_cert_parser.c -> compat/verification/x509_cert_parser.c
+crypto/asymmetric_keys/x509_parser.h -> compat/verification/x509_parser.h
+crypto/asymmetric_keys/x509_public_key.c -> compat/verification/x509_public_key.c
+
+net/Makefile
+net/Kconfig
+net/wireless/
+net/mac80211/
+# MPLS labels, checked on skb->protocol on the
+# respective 802 family, only ethernet seems to use
+# this right now, see 960d97f95
+include/linux/mpls.h
+include/uapi/linux/mpls.h
+
+drivers/net/wireless/mac80211_hwsim.c
+drivers/net/wireless/mac80211_hwsim.h
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/6] backports: backport most of improved netlink policy validation
  2018-10-02 17:51 [PATCH 1/6] backports: rename magic functions for netlink parsing Johannes Berg
  2018-10-02 17:51 ` [PATCH 2/6] backports: fix genlmsg_nlhdr() backport Johannes Berg
  2018-10-02 17:51 ` [PATCH 3/6] backports: add copy-list.hwsim Johannes Berg
@ 2018-10-02 17:51 ` Johannes Berg
  2018-10-02 17:51 ` [PATCH 5/6] backports: add __skb_peek() Johannes Berg
  2018-10-02 17:51 ` [PATCH 6/6] backports: genetlink: update completely Johannes Berg
  4 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 17:51 UTC (permalink / raw)
  To: backports; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 backport/backport-include/linux/netlink.h |  19 ++
 backport/backport-include/net/netlink.h   | 185 ++++++++++++++-
 backport/compat/Makefile                  |   1 +
 backport/compat/backport-4.20.c           | 379 ++++++++++++++++++++++++++++++
 4 files changed, 572 insertions(+), 12 deletions(-)
 create mode 100644 backport/compat/backport-4.20.c

diff --git a/backport/backport-include/linux/netlink.h b/backport/backport-include/linux/netlink.h
index 468a12d15dbe..366c9e27e8c2 100644
--- a/backport/backport-include/linux/netlink.h
+++ b/backport/backport-include/linux/netlink.h
@@ -3,6 +3,13 @@
 #include_next <linux/netlink.h>
 #include <linux/version.h>
 
+#if LINUX_VERSION_IS_LESS(4,14,0)
+struct nla_bitfield32 {
+	__u32 value;
+	__u32 selector;
+};
+#endif
+
 #if LINUX_VERSION_IS_LESS(4,12,0)
 #define NETLINK_MAX_COOKIE_LEN  20
 
@@ -23,6 +30,18 @@ struct netlink_ext_ack {
 } while (0)
 #endif
 
+#ifndef NL_SET_ERR_MSG_ATTR
+#define NL_SET_ERR_MSG_ATTR(extack, attr, msg) do {	\
+	static const char __msg[] = msg;		\
+	struct netlink_ext_ack *__extack = (extack);	\
+							\
+	if (__extack) {					\
+		__extack->_msg = __msg;			\
+		__extack->bad_attr = (attr);		\
+	}						\
+} while (0)
+#endif
+
 /* this is for patches we apply */
 #if LINUX_VERSION_IS_LESS(3,7,0)
 #define netlink_notify_portid(__notify) (__notify->pid)
diff --git a/backport/backport-include/net/netlink.h b/backport/backport-include/net/netlink.h
index 7775bc8295c3..4af73631115e 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) */
diff --git a/backport/compat/Makefile b/backport/compat/Makefile
index f5b1886e2d8e..ff6c7e658380 100644
--- a/backport/compat/Makefile
+++ b/backport/compat/Makefile
@@ -38,6 +38,7 @@ compat-$(CPTCFG_KERNEL_4_8) += backport-4.8.o
 compat-$(CPTCFG_KERNEL_4_10) += backport-4.10.o
 compat-$(CPTCFG_KERNEL_4_12) += backport-4.12.o
 compat-$(CPTCFG_KERNEL_4_18) += backport-4.18.o
+compat-$(CPTCFG_KERNEL_4_20) += backport-4.20.o
 
 compat-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
 
diff --git a/backport/compat/backport-4.20.c b/backport/compat/backport-4.20.c
new file mode 100644
index 000000000000..e26f3b52fbbe
--- /dev/null
+++ b/backport/compat/backport-4.20.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <net/netlink.h>
+
+static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
+	[NLA_U8]	= sizeof(u8),
+	[NLA_U16]	= sizeof(u16),
+	[NLA_U32]	= sizeof(u32),
+	[NLA_U64]	= sizeof(u64),
+	[NLA_S8]	= sizeof(s8),
+	[NLA_S16]	= sizeof(s16),
+	[NLA_S32]	= sizeof(s32),
+	[NLA_S64]	= sizeof(s64),
+};
+
+static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
+	[NLA_U8]	= sizeof(u8),
+	[NLA_U16]	= sizeof(u16),
+	[NLA_U32]	= sizeof(u32),
+	[NLA_U64]	= sizeof(u64),
+	[NLA_MSECS]	= sizeof(u64),
+	[NLA_NESTED]	= NLA_HDRLEN,
+	[NLA_S8]	= sizeof(s8),
+	[NLA_S16]	= sizeof(s16),
+	[NLA_S32]	= sizeof(s32),
+	[NLA_S64]	= sizeof(s64),
+};
+
+static int validate_nla_bitfield32(const struct nlattr *nla,
+				   const u32 *valid_flags_mask)
+{
+	const struct nla_bitfield32 *bf = nla_data(nla);
+
+	if (!valid_flags_mask)
+		return -EINVAL;
+
+	/*disallow invalid bit selector */
+	if (bf->selector & ~*valid_flags_mask)
+		return -EINVAL;
+
+	/*disallow invalid bit values */
+	if (bf->value & ~*valid_flags_mask)
+		return -EINVAL;
+
+	/*disallow valid bit values that are not selected*/
+	if (bf->value & ~bf->selector)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
+			      const struct nla_policy *policy,
+			      struct netlink_ext_ack *extack)
+{
+	const struct nlattr *entry;
+	int rem;
+
+	nla_for_each_attr(entry, head, len, rem) {
+		int ret;
+
+		if (nla_len(entry) == 0)
+			continue;
+
+		if (nla_len(entry) < NLA_HDRLEN) {
+			NL_SET_ERR_MSG_ATTR(extack, entry,
+					    "Array element too short");
+			return -ERANGE;
+		}
+
+		ret = nla_validate(nla_data(entry), nla_len(entry),
+				   maxtype, policy, extack);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int nla_validate_int_range(const struct nla_policy *pt,
+				  const struct nlattr *nla,
+				  struct netlink_ext_ack *extack)
+{
+	bool validate_min, validate_max;
+	s64 value;
+
+	validate_min = pt->validation_type == NLA_VALIDATE_RANGE ||
+		       pt->validation_type == NLA_VALIDATE_MIN;
+	validate_max = pt->validation_type == NLA_VALIDATE_RANGE ||
+		       pt->validation_type == NLA_VALIDATE_MAX;
+
+	switch (pt->type) {
+	case NLA_U8:
+		value = nla_get_u8(nla);
+		break;
+	case NLA_U16:
+		value = nla_get_u16(nla);
+		break;
+	case NLA_U32:
+		value = nla_get_u32(nla);
+		break;
+	case NLA_S8:
+		value = nla_get_s8(nla);
+		break;
+	case NLA_S16:
+		value = nla_get_s16(nla);
+		break;
+	case NLA_S32:
+		value = nla_get_s32(nla);
+		break;
+	case NLA_S64:
+		value = nla_get_s64(nla);
+		break;
+	case NLA_U64:
+		/* treat this one specially, since it may not fit into s64 */
+		if ((validate_min && nla_get_u64(nla) < pt->min) ||
+		    (validate_max && nla_get_u64(nla) > pt->max)) {
+			NL_SET_ERR_MSG_ATTR(extack, nla,
+					    "integer out of range");
+			return -ERANGE;
+		}
+		return 0;
+	default:
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if ((validate_min && value < pt->min) ||
+	    (validate_max && value > pt->max)) {
+		NL_SET_ERR_MSG_ATTR(extack, nla,
+				    "integer out of range");
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+static int validate_nla(const struct nlattr *nla, int maxtype,
+			const struct nla_policy *policy,
+			struct netlink_ext_ack *extack)
+{
+	const struct nla_policy *pt;
+	int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
+	int err = -ERANGE;
+
+	if (type <= 0 || type > maxtype)
+		return 0;
+
+	pt = &policy[type];
+
+	BUG_ON(pt->type > NLA_TYPE_MAX);
+
+	if ((nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) ||
+	    (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);
+	}
+
+	switch (pt->type) {
+	case NLA_EXACT_LEN:
+		if (attrlen != pt->len)
+			goto out_err;
+		break;
+
+	case NLA_REJECT:
+		if (extack && pt->validation_data) {
+			NL_SET_BAD_ATTR(extack, nla);
+			extack->_msg = pt->validation_data;
+			return -EINVAL;
+		}
+		err = -EINVAL;
+		goto out_err;
+
+	case NLA_FLAG:
+		if (attrlen > 0)
+			goto out_err;
+		break;
+
+	case NLA_BITFIELD32:
+		if (attrlen != sizeof(struct nla_bitfield32))
+			goto out_err;
+
+		err = validate_nla_bitfield32(nla, pt->validation_data);
+		if (err)
+			goto out_err;
+		break;
+
+	case NLA_NUL_STRING:
+		if (pt->len)
+			minlen = min_t(int, attrlen, pt->len + 1);
+		else
+			minlen = attrlen;
+
+		if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) {
+			err = -EINVAL;
+			goto out_err;
+		}
+		/* fall through */
+
+	case NLA_STRING:
+		if (attrlen < 1)
+			goto out_err;
+
+		if (pt->len) {
+			char *buf = nla_data(nla);
+
+			if (buf[attrlen - 1] == '\0')
+				attrlen--;
+
+			if (attrlen > pt->len)
+				goto out_err;
+		}
+		break;
+
+	case NLA_BINARY:
+		if (pt->len && attrlen > pt->len)
+			goto out_err;
+		break;
+
+	case NLA_NESTED:
+		/* a nested attributes is allowed to be empty; if its not,
+		 * it must have a size of at least NLA_HDRLEN.
+		 */
+		if (attrlen == 0)
+			break;
+		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);
+			if (err < 0) {
+				/*
+				 * return directly to preserve the inner
+				 * error message/attribute pointer
+				 */
+				return err;
+			}
+		}
+		break;
+	case NLA_NESTED_ARRAY:
+		/* a nested array attribute is allowed to be empty; if its not,
+		 * it must have a size of at least NLA_HDRLEN.
+		 */
+		if (attrlen == 0)
+			break;
+		if (attrlen < NLA_HDRLEN)
+			goto out_err;
+		if (pt->validation_data) {
+			int err;
+
+			err = nla_validate_array(nla_data(nla), nla_len(nla),
+						 pt->len, pt->validation_data,
+						 extack);
+			if (err < 0) {
+				/*
+				 * return directly to preserve the inner
+				 * error message/attribute pointer
+				 */
+				return err;
+			}
+		}
+		break;
+	default:
+		if (pt->len)
+			minlen = pt->len;
+		else if (pt->type != NLA_UNSPEC)
+			minlen = nla_attr_minlen[pt->type];
+
+		if (attrlen < minlen)
+			goto out_err;
+	}
+
+	/* further validation */
+	switch (pt->validation_type) {
+	case NLA_VALIDATE_NONE:
+		/* nothing to do */
+		break;
+	case NLA_VALIDATE_RANGE:
+	case NLA_VALIDATE_MIN:
+	case NLA_VALIDATE_MAX:
+		err = nla_validate_int_range(pt, nla, extack);
+		if (err)
+			return err;
+		break;
+	case NLA_VALIDATE_FUNCTION:
+		if (pt->validate) {
+			err = pt->validate(nla, extack);
+			if (err)
+				return err;
+		}
+		break;
+	}
+
+	return 0;
+out_err:
+	NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");
+	return err;
+}
+
+int backport_nla_validate(const struct nlattr *head, int len, int maxtype,
+			  const struct nla_policy *policy,
+			  struct netlink_ext_ack *extack)
+{
+	const struct nlattr *nla;
+	int rem;
+
+	nla_for_each_attr(nla, head, len, rem) {
+		int err = validate_nla(nla, maxtype, policy, extack);
+
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(backport_nla_validate);
+
+int backport_nla_policy_len(const struct nla_policy *p, int n)
+{
+	int i, len = 0;
+
+	for (i = 0; i < n; i++, p++) {
+		if (p->len)
+			len += nla_total_size(p->len);
+		else if (nla_attr_len[p->type])
+			len += nla_total_size(nla_attr_len[p->type]);
+		else if (nla_attr_minlen[p->type])
+			len += nla_total_size(nla_attr_minlen[p->type]);
+	}
+
+	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)
+{
+	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;
+}
+EXPORT_SYMBOL(backport_nla_parse);
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/6] backports: add __skb_peek()
  2018-10-02 17:51 [PATCH 1/6] backports: rename magic functions for netlink parsing Johannes Berg
                   ` (2 preceding siblings ...)
  2018-10-02 17:51 ` [PATCH 4/6] backports: backport most of improved netlink policy validation Johannes Berg
@ 2018-10-02 17:51 ` Johannes Berg
  2018-10-02 17:51 ` [PATCH 6/6] backports: genetlink: update completely Johannes Berg
  4 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 17:51 UTC (permalink / raw)
  To: backports; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

New API slated to show up in 4.20.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 backport/backport-include/linux/skbuff.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/backport/backport-include/linux/skbuff.h b/backport/backport-include/linux/skbuff.h
index 61133c4277cc..44b2a5de0478 100644
--- a/backport/backport-include/linux/skbuff.h
+++ b/backport/backport-include/linux/skbuff.h
@@ -382,4 +382,11 @@ static inline void skb_put_u8(struct sk_buff *skb, u8 val)
 }
 #endif
 
+#if LINUX_VERSION_IS_LESS(4,20,0)
+static inline struct sk_buff *__skb_peek(const struct sk_buff_head *list_)
+{
+	return list_->next;
+}
+#endif
+
 #endif /* __BACKPORT_SKBUFF_H */
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/6] backports: genetlink: update completely
  2018-10-02 17:51 [PATCH 1/6] backports: rename magic functions for netlink parsing Johannes Berg
                   ` (3 preceding siblings ...)
  2018-10-02 17:51 ` [PATCH 5/6] backports: add __skb_peek() Johannes Berg
@ 2018-10-02 17:51 ` Johannes Berg
  2018-10-02 18:38   ` Johannes Berg
  4 siblings, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 17:51 UTC (permalink / raw)
  To: backports; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Replace all the different nested versions of generic netlink
backport with a single one, covering from < 3.13 all the way
to the upcoming netlink policy improvements in 4.20.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 backport/backport-include/linux/netlink.h |   2 +-
 backport/backport-include/net/genetlink.h | 238 ++++++-----------
 backport/compat/Makefile                  |   3 +-
 backport/compat/backport-3.13.c           |  66 -----
 backport/compat/backport-4.12.c           | 274 --------------------
 backport/compat/backport-genetlink.c      | 418 ++++++++++++++++++++++++++++++
 backport/compat/compat-3.3.c              |  13 -
 7 files changed, 502 insertions(+), 512 deletions(-)
 delete mode 100644 backport/compat/backport-4.12.c
 create mode 100644 backport/compat/backport-genetlink.c

diff --git a/backport/backport-include/linux/netlink.h b/backport/backport-include/linux/netlink.h
index 366c9e27e8c2..f956a76966f3 100644
--- a/backport/backport-include/linux/netlink.h
+++ b/backport/backport-include/linux/netlink.h
@@ -20,7 +20,7 @@ struct netlink_ext_ack {
 	u8 cookie_len;
 
 	/* backport only field */
-	void *__bp_genl_real_ops;
+	void *__bp_doit;
 };
 
 #define NL_SET_ERR_MSG(extack, msg) do {	\
diff --git a/backport/backport-include/net/genetlink.h b/backport/backport-include/net/genetlink.h
index d80d979ac423..84011e72644e 100644
--- a/backport/backport-include/net/genetlink.h
+++ b/backport/backport-include/net/genetlink.h
@@ -15,18 +15,14 @@ static inline void *__bp_genl_info_userhdr(struct genl_info *info)
 }
 
 #if LINUX_VERSION_IS_LESS(4,12,0)
-#define GENL_SET_ERR_MSG(info, msg) do { } while (0)
+#define GENL_SET_ERR_MSG(info, msg) NL_SET_ERR_MSG(genl_info_extack(info), msg)
 
 static inline int genl_err_attr(struct genl_info *info, int err,
 				struct nlattr *attr)
 {
-#if LINUX_VERSION_IS_GEQ(4,12,0)
-	info->extack->bad_attr = attr;
-#endif
-
 	return err;
 }
-#endif
+#endif /* < 4.12 */
 
 /* this is for patches we apply */
 static inline struct netlink_ext_ack *genl_info_extack(struct genl_info *info)
@@ -51,12 +47,24 @@ static inline void *genl_info_userhdr(struct genl_info *info)
 #define genl_info_snd_portid(__genl_info) (__genl_info->snd_portid)
 #endif
 
+#if LINUX_VERSION_IS_LESS(3,13,0)
+#define __genl_const
+#else /* < 3.13 */
+#define __genl_const const
+#endif /* < 3.13 */
+
 #ifndef GENLMSG_DEFAULT_SIZE
 #define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN)
 #endif
 
 #if LINUX_VERSION_IS_LESS(3,1,0)
-#define genl_dump_check_consistent(cb, user_hdr)
+#define genl_dump_check_consistent(cb, user_hdr) do { } while (0)
+#endif
+
+#if LINUX_VERSION_IS_LESS(4,10,0)
+#define __genl_ro_after_init
+#else
+#define __genl_ro_after_init __ro_after_init
 #endif
 
 #if LINUX_VERSION_IS_LESS(4,15,0)
@@ -83,148 +91,87 @@ void backport_genl_dump_check_consistent(struct netlink_callback *cb,
 #endif
 #endif /* LINUX_VERSION_IS_LESS(4,15,0) */
 
-#if LINUX_VERSION_IS_LESS(3,13,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)
-static inline int __real_genl_register_family(struct genl_family *family)
+#if LINUX_VERSION_IS_LESS(4,20,0)
+static inline int
+__real_backport_genl_register_family(struct genl_family *family)
 {
 	return genl_register_family(family);
 }
-
-/* Needed for the mcgrps pointer */
-struct backport_genl_family {
-	struct genl_family family;
-
-	unsigned int id, hdrsize, version, maxattr;
-	char name[GENL_NAMSIZ];
-	bool netnsok;
-	bool parallel_ops;
-
-	struct nlattr **attrbuf;
-
-	int (*pre_doit)(struct genl_ops *ops, struct sk_buff *skb,
-			struct genl_info *info);
-
-	void (*post_doit)(struct genl_ops *ops, struct sk_buff *skb,
-			  struct genl_info *info);
-
-	struct genl_multicast_group *mcgrps;
-	struct genl_ops *ops;
-	unsigned int n_mcgrps, n_ops;
-
-	struct module *module;
-};
-#define genl_family LINUX_BACKPORT(genl_family)
-
-int __backport_genl_register_family(struct genl_family *family);
-
-#define genl_register_family LINUX_BACKPORT(genl_register_family)
 static inline int
-genl_register_family(struct genl_family *family)
+__real_backport_genl_unregister_family(struct genl_family *family)
 {
-	family->module = THIS_MODULE;
-	return __backport_genl_register_family(family);
+	return genl_unregister_family(family);
 }
 
-#define _genl_register_family_with_ops_grps \
-	_backport_genl_register_family_with_ops_grps
-static inline int
-_genl_register_family_with_ops_grps(struct genl_family *family,
-				    struct genl_ops *ops, size_t n_ops,
-				    struct genl_multicast_group *mcgrps,
-				    size_t n_mcgrps)
-{
-	family->ops = ops;
-	family->n_ops = n_ops;
-	family->mcgrps = mcgrps;
-	family->n_mcgrps = n_mcgrps;
-	return genl_register_family(family);
-}
+struct backport_genl_family {
+	struct genl_family	family;
+	const struct genl_ops *	copy_ops;
+
+	/* copied */
+	int			id;		/* private */
+	unsigned int		hdrsize;
+	char			name[GENL_NAMSIZ];
+	unsigned int		version;
+	unsigned int		maxattr;
+	bool			netnsok;
+	bool			parallel_ops;
+	int			(*pre_doit)(__genl_const struct genl_ops *ops,
+					    struct sk_buff *skb,
+					    struct genl_info *info);
+	void			(*post_doit)(__genl_const struct genl_ops *ops,
+					     struct sk_buff *skb,
+					     struct genl_info *info);
+/*
+ * unsupported!
+	int			(*mcast_bind)(struct net *net, int group);
+	void			(*mcast_unbind)(struct net *net, int group);
+ */
+	struct nlattr **	attrbuf;	/* private */
+	__genl_const struct genl_ops *	ops;
+	__genl_const struct genl_multicast_group *mcgrps;
+	unsigned int		n_ops;
+	unsigned int		n_mcgrps;
+	struct module		*module;
+};
+#undef genl_family
+#define genl_family backport_genl_family
 
-#define genl_register_family_with_ops(family, ops)			\
-	_genl_register_family_with_ops_grps((family),			\
-					    (ops), ARRAY_SIZE(ops),	\
-					    NULL, 0)
-#define genl_register_family_with_ops_groups(family, ops, grps)		\
-	_genl_register_family_with_ops_grps((family),			\
-					    (ops), ARRAY_SIZE(ops),	\
-					    (grps), ARRAY_SIZE(grps))
+#define genl_register_family backport_genl_register_family
+int genl_register_family(struct genl_family *family);
 
 #define genl_unregister_family backport_genl_unregister_family
-int genl_unregister_family(struct genl_family *family);
+int backport_genl_unregister_family(struct genl_family *family);
 
-#if LINUX_VERSION_IS_LESS(3,3,0)
-extern void genl_notify(struct sk_buff *skb, struct net *net, u32 pid,
-			u32 group, struct nlmsghdr *nlh, gfp_t flags);
-#endif
-#define genl_notify(_fam, _skb, _info, _group, _flags)			\
-	genl_notify(_skb, genl_info_net(_info),				\
-		    genl_info_snd_portid(_info),			\
-		    (_fam)->mcgrps[_group].id, _info->nlhdr, _flags)
-#define genlmsg_put(_skb, _pid, _seq, _fam, _flags, _cmd)		\
-	genlmsg_put(_skb, _pid, _seq, &(_fam)->family, _flags, _cmd)
+#define genl_notify LINUX_BACKPORT(genl_notify)
+void genl_notify(const struct genl_family *family, struct sk_buff *skb,
+		 struct genl_info *info, u32 group, gfp_t flags);
+
+#define genlmsg_put LINUX_BACKPORT(genlmsg_put)
+void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
+		  const struct genl_family *family, int flags, u8 cmd);
+
+#define genlmsg_put_reply LINUX_BACKPORT(genlmsg_put_reply)
+void *genlmsg_put_reply(struct sk_buff *skb,
+			struct genl_info *info,
+			const struct genl_family *family,
+			int flags, u8 cmd);
 
-#ifndef genlmsg_put_reply /* might already be there from _info override above */
-#define genlmsg_put_reply(_skb, _info, _fam, _flags, _cmd)		\
-	genlmsg_put_reply(_skb, _info, &(_fam)->family, _flags, _cmd)
-#endif
 #define genlmsg_multicast_netns LINUX_BACKPORT(genlmsg_multicast_netns)
-static inline int genlmsg_multicast_netns(struct genl_family *family,
-					  struct net *net, struct sk_buff *skb,
-					  u32 portid, unsigned int group,
-					  gfp_t flags)
-{
-	if (WARN_ON_ONCE(group >= family->n_mcgrps))
-		return -EINVAL;
-	group = family->mcgrps[group].id;
-	return nlmsg_multicast(
-		net->genl_sock,
-		skb, portid, group, flags);
-}
+int genlmsg_multicast_netns(const struct genl_family *family,
+			    struct net *net, struct sk_buff *skb,
+			    u32 portid, unsigned int group,
+			    gfp_t flags);
+
 #define genlmsg_multicast LINUX_BACKPORT(genlmsg_multicast)
-static inline int genlmsg_multicast(struct genl_family *family,
-				    struct sk_buff *skb, u32 portid,
-				    unsigned int group, gfp_t flags)
-{
-	if (WARN_ON_ONCE(group >= family->n_mcgrps))
-		return -EINVAL;
-	group = family->mcgrps[group].id;
-	return nlmsg_multicast(
-		init_net.genl_sock,
-		skb, portid, group, flags);
-}
-static inline int
-backport_genlmsg_multicast_allns(struct genl_family *family,
-				 struct sk_buff *skb, u32 portid,
-				 unsigned int group, gfp_t flags)
-{
-	if (WARN_ON_ONCE(group >= family->n_mcgrps))
-		return -EINVAL;
-	group = family->mcgrps[group].id;
-	return genlmsg_multicast_allns(skb, portid, group, flags);
-}
-#define genlmsg_multicast_allns LINUX_BACKPORT(genlmsg_multicast_allns)
+int genlmsg_multicast(const struct genl_family *family,
+		      struct sk_buff *skb, u32 portid,
+		      unsigned int group, gfp_t flags);
 
-#define __genl_const
-#else /* < 3.13 */
-#define __genl_const const
-#if LINUX_VERSION_IS_LESS(4,4,0)
-#define genl_notify(_fam, _skb, _info, _group, _flags)			\
-	genl_notify(_fam, _skb, genl_info_net(_info),			\
-		    genl_info_snd_portid(_info),			\
-		    _group, _info->nlhdr, _flags)
-#endif /* < 4.4 */
-#endif /* < 3.13 */
+#define genlmsg_multicast_allns LINUX_BACKPORT(genlmsg_multicast_allns)
+int backport_genlmsg_multicast_allns(const struct genl_family *family,
+				     struct sk_buff *skb, u32 portid,
+				     unsigned int group, gfp_t flags);
 
-#if LINUX_VERSION_IS_LESS(4,10,0)
-/**
- * genl_family_attrbuf - return family's attrbuf
- * @family: the family
- *
- * Return the family's attrbuf, while validating that it's
- * actually valid to access it.
- *
- * You cannot use this function with a family that has parallel_ops
- * and you can only use it within (pre/post) doit/dumpit callbacks.
- */
 #define genl_family_attrbuf LINUX_BACKPORT(genl_family_attrbuf)
 static inline struct nlattr **genl_family_attrbuf(struct genl_family *family)
 {
@@ -232,29 +179,6 @@ static inline struct nlattr **genl_family_attrbuf(struct genl_family *family)
 
 	return family->attrbuf;
 }
-
-#define __genl_ro_after_init
-#else
-#define __genl_ro_after_init __ro_after_init
-#endif
-
-#if LINUX_VERSION_IS_LESS(4,12,0)
-static inline int
-__real_bp_extack_genl_register_family(struct genl_family *family)
-{
-	return genl_register_family(family);
-}
-static inline int
-__real_bp_extack_genl_unregister_family(struct genl_family *family)
-{
-	return genl_unregister_family(family);
-}
-int bp_extack_genl_register_family(struct genl_family *family);
-int bp_extack_genl_unregister_family(struct genl_family *family);
-#undef genl_register_family
-#define genl_register_family bp_extack_genl_register_family
-#undef genl_unregister_family
-#define genl_unregister_family bp_extack_genl_unregister_family
-#endif
+#endif /* LINUX_VERSION_IS_LESS(4,20,0) */
 
 #endif /* __BACKPORT_NET_GENETLINK_H */
diff --git a/backport/compat/Makefile b/backport/compat/Makefile
index ff6c7e658380..fdc68c8b4600 100644
--- a/backport/compat/Makefile
+++ b/backport/compat/Makefile
@@ -36,10 +36,11 @@ compat-$(CPTCFG_KERNEL_4_6) += backport-4.6.o
 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_12) += backport-4.12.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_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
 
 compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/verify.o
diff --git a/backport/compat/backport-3.13.c b/backport/compat/backport-3.13.c
index 9e5076fbcb9b..23c759ef2388 100644
--- a/backport/compat/backport-3.13.c
+++ b/backport/compat/backport-3.13.c
@@ -11,77 +11,11 @@
  */
 #include <linux/version.h>
 #include <linux/kernel.h>
-#include <net/genetlink.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/device.h>
 #include <linux/hwmon.h>
 
-/************* generic netlink backport *****************/
-#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)
-
-#undef genl_register_family
-#undef genl_unregister_family
-
-int __backport_genl_register_family(struct genl_family *family)
-{
-	int i, ret;
-
-#define __copy(_field) family->family._field = family->_field
-	__copy(id);
-	__copy(hdrsize);
-	__copy(version);
-	__copy(maxattr);
-	strncpy(family->family.name, family->name, sizeof(family->family.name));
-	__copy(netnsok);
-	__copy(pre_doit);
-	__copy(post_doit);
-#if LINUX_VERSION_IS_GEQ(3,10,0)
-	__copy(parallel_ops);
-#endif
-#if LINUX_VERSION_IS_GEQ(3,11,0)
-	__copy(module);
-#endif
-#undef __copy
-
-	ret = genl_register_family(&family->family);
-	if (ret < 0)
-		return ret;
-
-	family->attrbuf = family->family.attrbuf;
-	family->id = family->family.id;
-
-	for (i = 0; i < family->n_ops; i++) {
-		ret = genl_register_ops(&family->family, &family->ops[i]);
-		if (ret < 0)
-			goto error;
-	}
-
-	for (i = 0; i < family->n_mcgrps; i++) {
-		ret = genl_register_mc_group(&family->family,
-					     &family->mcgrps[i]);
-		if (ret)
-			goto error;
-	}
-
-	return 0;
-
- error:
-	backport_genl_unregister_family(family);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(__backport_genl_register_family);
-
-int backport_genl_unregister_family(struct genl_family *family)
-{
-	int err;
-	err = genl_unregister_family(&family->family);
-	return err;
-}
-EXPORT_SYMBOL_GPL(backport_genl_unregister_family);
-
-#endif /* RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0) */
-
 #ifdef __BACKPORT_NET_GET_RANDOM_ONCE
 struct __net_random_once_work {
 	struct work_struct work;
diff --git a/backport/compat/backport-4.12.c b/backport/compat/backport-4.12.c
deleted file mode 100644
index 5fc8c10cb8d8..000000000000
--- a/backport/compat/backport-4.12.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright 2017 Intel Deutschland GmbH
- */
-#include <net/genetlink.h>
-#include <net/sock.h>
-
-enum nlmsgerr_attrs {
-	NLMSGERR_ATTR_UNUSED,
-	NLMSGERR_ATTR_MSG,
-	NLMSGERR_ATTR_OFFS,
-	NLMSGERR_ATTR_COOKIE,
-	__NLMSGERR_ATTR_MAX,
-	NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
-};
-
-#define NLM_F_CAPPED	0x100	/* request was capped */
-#define NLM_F_ACK_TLVS	0x200	/* extended ACK TVLs were included */
-
-struct bp_extack_genl_family {
-	struct genl_family family;
-	struct genl_family *real_family;
-	struct list_head list;
-
-	struct genl_ops ops[];
-};
-
-static LIST_HEAD(copies_list);
-static DEFINE_MUTEX(copies_mutex);
-
-static const struct nla_policy extack_dummy_policy[1] = {};
-
-static struct bp_extack_genl_family *get_copy(__genl_const struct genl_ops *op)
-{
-	do {
-		op--;
-	} while (op->policy != extack_dummy_policy);
-
-	return container_of(op, struct bp_extack_genl_family, ops[0]);
-}
-
-static int extack_pre_doit(__genl_const struct genl_ops *ops,
-			   struct sk_buff *skb,
-			   struct genl_info *info)
-{
-	struct netlink_ext_ack *extack = kzalloc(sizeof(*extack), GFP_KERNEL);
-	struct bp_extack_genl_family *copy = get_copy(ops);
-	struct genl_ops *real_ops;
-	int err;
-
-	__bp_genl_info_userhdr_set(info, extack);
-
-	if (!extack) {
-		__bp_genl_info_userhdr_set(info, ERR_PTR(-ENOMEM));
-		return -ENOMEM;
-	}
-
-	real_ops = (void *)&copy->real_family->ops[ops - &copy->ops[1]];
-	extack->__bp_genl_real_ops = real_ops;
-
-	if (copy->real_family->pre_doit)
-		err = copy->real_family->pre_doit(real_ops, skb, info);
-	else
-		err = 0;
-
-	if (err) {
-		__bp_genl_info_userhdr_set(info, ERR_PTR(err));
-		kfree(extack);
-	}
-
-	return err;
-}
-
-static void extack_netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh,
-			       int err, const struct netlink_ext_ack *extack)
-{
-	struct sk_buff *skb;
-	struct nlmsghdr *rep;
-	struct nlmsgerr *errmsg;
-	size_t payload = sizeof(*errmsg);
-	size_t tlvlen = 0;
-	unsigned int flags = 0;
-	/* backports assumes everyone supports this - libnl does so it's true */
-	bool nlk_has_extack = true;
-
-	/* Error messages get the original request appened, unless the user
-	 * requests to cap the error message, and get extra error data if
-	 * requested.
-	 * (ignored in backports)
-	 */
-	if (nlk_has_extack && extack && extack->_msg)
-		tlvlen += nla_total_size(strlen(extack->_msg) + 1);
-
-	if (err) {
-		if (1)
-			payload += nlmsg_len(nlh);
-		else
-			flags |= NLM_F_CAPPED;
-		if (nlk_has_extack && extack && extack->bad_attr)
-			tlvlen += nla_total_size(sizeof(u32));
-	} else {
-		flags |= NLM_F_CAPPED;
-
-		if (nlk_has_extack && extack && extack->cookie_len)
-			tlvlen += nla_total_size(extack->cookie_len);
-	}
-
-	if (tlvlen)
-		flags |= NLM_F_ACK_TLVS;
-
-	skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
-	if (!skb) {
-		NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
-		NETLINK_CB(in_skb).sk->sk_error_report(NETLINK_CB(in_skb).sk);
-		return;
-	}
-
-	rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
-			  NLMSG_ERROR, payload, flags);
-	errmsg = nlmsg_data(rep);
-	errmsg->error = err;
-	memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
-
-	if (nlk_has_extack && extack) {
-		if (extack->_msg) {
-			WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
-					       extack->_msg));
-		}
-		if (err) {
-			if (extack->bad_attr &&
-			    !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
-				     (u8 *)extack->bad_attr >= in_skb->data +
-							       in_skb->len))
-				WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
-						    (u8 *)extack->bad_attr -
-						    in_skb->data));
-		} else {
-			if (extack->cookie_len)
-				WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
-						extack->cookie_len,
-						extack->cookie));
-		}
-	}
-
-	nlmsg_end(skb, rep);
-
-	netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);
-}
-
-static int extack_doit(struct sk_buff *skb, struct genl_info *info)
-{
-	struct genl_ops *real_ops;
-	int err;
-
-	/* older kernels have a bug here */
-	if (IS_ERR(__bp_genl_info_userhdr(info))) {
-		extack_netlink_ack(skb, info->nlhdr,
-				   PTR_ERR(__bp_genl_info_userhdr(info)),
-				   genl_info_extack(info));
-		goto out;
-	}
-
-	real_ops = genl_info_extack(info)->__bp_genl_real_ops;
-	err = real_ops->doit(skb, info);
-
-	if (err == -EINTR)
-		return err;
-
-	if (info->nlhdr->nlmsg_flags & NLM_F_ACK || err)
-		extack_netlink_ack(skb, info->nlhdr, err,
-				   genl_info_extack(info));
-
-out:
-	/* suppress sending ACK from normal netlink code */
-	info->nlhdr->nlmsg_flags &= ~NLM_F_ACK;
-	return 0;
-}
-
-static void extack_post_doit(__genl_const struct genl_ops *ops,
-			     struct sk_buff *skb,
-			     struct genl_info *info)
-{
-	void (*post_doit)(__genl_const struct genl_ops *ops,
-			  struct sk_buff *skb,
-			  struct genl_info *info);
-
-	post_doit = get_copy(ops)->real_family->post_doit;
-
-	if (post_doit)
-		post_doit(ops, skb, info);
-	kfree(__bp_genl_info_userhdr(info));
-}
-
-int bp_extack_genl_register_family(struct genl_family *family)
-{
-	unsigned int size = sizeof(struct bp_extack_genl_family) +
-			    sizeof(family->ops[0]) * (family->n_ops + 1);
-	struct bp_extack_genl_family *copy;
-	int i, err;
-
-	copy = kzalloc(size, GFP_KERNEL);
-	if (!copy)
-		return -ENOMEM;
-
-	copy->family = *family;
-	copy->real_family = family;
-	copy->family.ops = &copy->ops[1];
-
-	for (i = 0; i < family->n_ops; i++) {
-		copy->ops[i + 1] = family->ops[i];
-		if (family->ops[i].doit)
-			copy->ops[i + 1].doit = extack_doit;
-	}
-
-	copy->ops[0].policy = extack_dummy_policy;
-
-	copy->family.pre_doit = extack_pre_doit;
-	copy->family.post_doit = extack_post_doit;
-
-	err = __real_bp_extack_genl_register_family(&copy->family);
-	if (err) {
-		kfree(copy);
-		return err;
-	}
-
-	/* copy this since the family might access it directly */
-	family->id = copy->family.id;
-	family->attrbuf = copy->family.attrbuf;
-
-#if LINUX_VERSION_IS_LESS(3,13,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)
-	/* family ID from the original family struct will be used when building
-	 * genl messages (sent as nlmsg_type), so the new id should be updated
-	 * in the original (older kernel format) family struct too
-	 */
-	family->family.id = copy->family.id;
-#endif
-
-#if LINUX_VERSION_IS_GEQ(3,13,0)
-	family->mcgrp_offset = copy->family.mcgrp_offset;
-#endif
-
-	mutex_lock(&copies_mutex);
-	list_add_tail(&copy->list, &copies_list);
-	mutex_unlock(&copies_mutex);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(bp_extack_genl_register_family);
-
-int bp_extack_genl_unregister_family(struct genl_family *family)
-{
-	struct bp_extack_genl_family *tmp, *copy = NULL;
-	int err;
-
-	mutex_lock(&copies_mutex);
-	list_for_each_entry(tmp, &copies_list, list) {
-		if (tmp->real_family == family) {
-			copy = tmp;
-			break;
-		}
-	}
-	if (copy)
-		list_del(&copy->list);
-	mutex_unlock(&copies_mutex);
-
-	if (!copy)
-		return -ENOENT;
-
-	err = __real_bp_extack_genl_unregister_family(&copy->family);
-	WARN_ON(err);
-	kfree(copy);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(bp_extack_genl_unregister_family);
diff --git a/backport/compat/backport-genetlink.c b/backport/compat/backport-genetlink.c
new file mode 100644
index 000000000000..c2579b353de7
--- /dev/null
+++ b/backport/compat/backport-genetlink.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Backport functionality introduced in Linux 4.20.
+ * Much of this is based on 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.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <net/genetlink.h>
+#include <net/netlink.h>
+#include <net/sock.h>
+
+static const struct genl_family *find_family_real_ops(const struct genl_ops **ops)
+{
+	const struct genl_family *family;
+	const struct genl_ops *tmp_ops = *ops;
+
+	/* find the family ... */
+	while (tmp_ops->doit || tmp_ops->dumpit)
+		tmp_ops++;
+	family = (void *)tmp_ops->done;
+
+	/* cast to suppress const warning */
+	*ops = (void *)(family->ops + (*ops - family->copy_ops));
+
+	return family;
+}
+
+#if LINUX_VERSION_IS_LESS(4,12,0)
+enum nlmsgerr_attrs {
+	NLMSGERR_ATTR_UNUSED,
+	NLMSGERR_ATTR_MSG,
+	NLMSGERR_ATTR_OFFS,
+	NLMSGERR_ATTR_COOKIE,
+	__NLMSGERR_ATTR_MAX,
+	NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+
+#define NLM_F_CAPPED	0x100	/* request was capped */
+#define NLM_F_ACK_TLVS	0x200	/* extended ACK TVLs were included */
+
+static void extack_netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh,
+			       int err, const struct netlink_ext_ack *extack)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *rep;
+	struct nlmsgerr *errmsg;
+	size_t payload = sizeof(*errmsg);
+	size_t tlvlen = 0;
+	unsigned int flags = 0;
+	/* backports assumes everyone supports this - libnl does so it's true */
+	bool nlk_has_extack = true;
+
+	/* Error messages get the original request appened, unless the user
+	 * requests to cap the error message, and get extra error data if
+	 * requested.
+	 * (ignored in backports)
+	 */
+	if (nlk_has_extack && extack && extack->_msg)
+		tlvlen += nla_total_size(strlen(extack->_msg) + 1);
+
+	if (err) {
+		if (1)
+			payload += nlmsg_len(nlh);
+		else
+			flags |= NLM_F_CAPPED;
+		if (nlk_has_extack && extack && extack->bad_attr)
+			tlvlen += nla_total_size(sizeof(u32));
+	} else {
+		flags |= NLM_F_CAPPED;
+
+		if (nlk_has_extack && extack && extack->cookie_len)
+			tlvlen += nla_total_size(extack->cookie_len);
+	}
+
+	if (tlvlen)
+		flags |= NLM_F_ACK_TLVS;
+
+	skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
+	if (!skb) {
+		NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
+		NETLINK_CB(in_skb).sk->sk_error_report(NETLINK_CB(in_skb).sk);
+		return;
+	}
+
+	rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
+			  NLMSG_ERROR, payload, flags);
+	errmsg = nlmsg_data(rep);
+	errmsg->error = err;
+	memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
+
+	if (nlk_has_extack && extack) {
+		if (extack->_msg) {
+			WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
+					       extack->_msg));
+		}
+		if (err) {
+			if (extack->bad_attr &&
+			    !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
+				     (u8 *)extack->bad_attr >= in_skb->data +
+							       in_skb->len))
+				WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
+						    (u8 *)extack->bad_attr -
+						    in_skb->data));
+		} else {
+			if (extack->cookie_len)
+				WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
+						extack->cookie_len,
+						extack->cookie));
+		}
+	}
+
+	nlmsg_end(skb, rep);
+
+	netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);
+}
+
+static int extack_doit(struct sk_buff *skb, struct genl_info *info)
+{
+	int (*doit)(struct sk_buff *, struct genl_info *);
+	int err;
+
+	/* older kernels have a bug here */
+	if (IS_ERR(__bp_genl_info_userhdr(info))) {
+		extack_netlink_ack(skb, info->nlhdr,
+				   PTR_ERR(__bp_genl_info_userhdr(info)),
+				   genl_info_extack(info));
+		goto out;
+	}
+
+	doit = genl_info_extack(info)->__bp_doit;
+	err = doit(skb, info);
+
+	if (err == -EINTR)
+		return err;
+
+	if (info->nlhdr->nlmsg_flags & NLM_F_ACK || err)
+		extack_netlink_ack(skb, info->nlhdr, err,
+				   genl_info_extack(info));
+
+out:
+	/* suppress sending ACK from normal netlink code */
+	info->nlhdr->nlmsg_flags &= ~NLM_F_ACK;
+	return 0;
+}
+#endif /* LINUX_VERSION_IS_LESS(4,12,0) */
+
+static int backport_pre_doit(__genl_const struct genl_ops *ops,
+			     struct sk_buff *skb,
+			     struct genl_info *info)
+{
+	const struct genl_family *family = find_family_real_ops(&ops);
+	int err;
+#if LINUX_VERSION_IS_LESS(4,12,0)
+	struct netlink_ext_ack *extack = kzalloc(sizeof(*extack), GFP_KERNEL);
+
+	__bp_genl_info_userhdr_set(info, extack);
+
+	if (!extack) {
+		__bp_genl_info_userhdr_set(info, ERR_PTR(-ENOMEM));
+		return -ENOMEM;
+	}
+
+	extack->__bp_doit = ops->doit;
+#else
+	struct netlink_ext_ack *extack = info->extack;
+#endif
+
+	err = nlmsg_validate(info->nlhdr, GENL_HDRLEN + family->hdrsize,
+			     family->maxattr, ops->policy, extack);
+	if (err)
+		return err;
+
+	err = family->pre_doit(ops, skb, info);
+
+#if LINUX_VERSION_IS_LESS(4,12,0)
+	if (err) {
+		__bp_genl_info_userhdr_set(info, ERR_PTR(err));
+		kfree(extack);
+	}
+#endif
+
+	return err;
+}
+
+static void backport_post_doit(__genl_const struct genl_ops *ops,
+			       struct sk_buff *skb,
+			       struct genl_info *info)
+{
+	const struct genl_family *family = find_family_real_ops(&ops);
+
+	family->post_doit(ops, skb, info);
+
+	kfree(__bp_genl_info_userhdr(info));
+}
+
+int backport_genl_register_family(struct genl_family *family)
+{
+	struct genl_ops *ops;
+	int err, i;
+
+#define COPY(memb)	family->family.memb = family->memb
+#define BACK(memb)	family->memb = family->family.memb
+
+	/* we append one entry to the ops to find our family pointer ... */
+	ops = kzalloc(sizeof(*ops) * (family->n_ops + 1), GFP_KERNEL);
+	memcpy(ops, family->ops, sizeof(*ops) * family->n_ops);
+	/*
+	 * Remove policy to skip validation as the struct nla_policy
+	 * 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
+	}
+	/* keep doit/dumpit NULL - that's invalid */
+	ops[family->n_ops].done = (void *)family;
+
+	COPY(id);
+	memcpy(family->family.name, family->name, sizeof(family->name));
+	COPY(hdrsize);
+	COPY(version);
+	COPY(maxattr);
+	COPY(netnsok);
+#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;
+	/* attrbuf is output only */
+	family->copy_ops = ops;
+#if LINUX_VERSION_IS_GEQ(3,13,0)
+	family->family.ops = ops;
+	COPY(mcgrps);
+	COPY(n_ops);
+	COPY(n_mcgrps);
+#endif
+#if LINUX_VERSION_IS_GEQ(3,11,0)
+	COPY(module);
+#endif
+
+	err = __real_backport_genl_register_family(&family->family);
+
+	BACK(id);
+	BACK(attrbuf);
+
+	if (err)
+		return err;
+
+#if LINUX_VERSION_IS_GEQ(3,13,0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)
+	return 0;
+#else
+	for (i = 0; i < family->n_ops; i++) {
+		err = genl_register_ops(&family->family, &family->ops[i]);
+		if (err < 0)
+			goto error;
+	}
+
+	for (i = 0; i < family->n_mcgrps; i++) {
+		err = genl_register_mc_group(&family->family,
+					     &family->mcgrps[i]);
+		if (err)
+			goto error;
+	}
+
+	return 0;
+ error:
+	genl_unregister_family(family);
+	return err;
+#endif /* LINUX_VERSION_IS_GEQ(3,13,0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0) */
+}
+EXPORT_SYMBOL_GPL(backport_genl_register_family);
+
+int backport_genl_unregister_family(struct genl_family *family)
+{
+	return __real_backport_genl_unregister_family(&family->family);
+}
+EXPORT_SYMBOL_GPL(backport_genl_unregister_family);
+
+#define INVALID_GROUP	0xffffffff
+
+static u32 __backport_genl_group(const struct genl_family *family,
+				 u32 group)
+{
+	if (WARN_ON_ONCE(group >= family->n_mcgrps))
+		return INVALID_GROUP;
+#if LINUX_VERSION_IS_LESS(3,13,0)
+	return family->mcgrps[group].id;
+#else
+	return family->family.mcgrp_offset + group;
+#endif
+}
+
+void genl_notify(const struct genl_family *family, struct sk_buff *skb,
+		 struct genl_info *info, u32 group, gfp_t flags)
+{
+	struct net *net = genl_info_net(info);
+	struct sock *sk = net->genl_sock;
+	int report = 0;
+
+	if (info->nlhdr)
+		report = nlmsg_report(info->nlhdr);
+
+	group = __backport_genl_group(family, group);
+	if (group == INVALID_GROUP)
+		return;
+	nlmsg_notify(sk, skb, info->snd_portid, group, report, flags);
+}
+EXPORT_SYMBOL_GPL(genl_notify);
+
+void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
+		  const struct genl_family *family, int flags, u8 cmd)
+{
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *hdr;
+
+	nlh = nlmsg_put(skb, portid, seq, family->id, GENL_HDRLEN +
+			family->hdrsize, flags);
+	if (nlh == NULL)
+		return NULL;
+
+	hdr = nlmsg_data(nlh);
+	hdr->cmd = cmd;
+	hdr->version = family->version;
+	hdr->reserved = 0;
+
+	return (char *) hdr + GENL_HDRLEN;
+}
+EXPORT_SYMBOL_GPL(genlmsg_put);
+
+void *genlmsg_put_reply(struct sk_buff *skb,
+			struct genl_info *info,
+			const struct genl_family *family,
+			int flags, u8 cmd)
+{
+	return genlmsg_put(skb, info->snd_portid, info->snd_seq, family,
+			   flags, cmd);
+}
+EXPORT_SYMBOL_GPL(genlmsg_put_reply);
+
+int genlmsg_multicast_netns(const struct genl_family *family,
+			    struct net *net, struct sk_buff *skb,
+			    u32 portid, unsigned int group,
+			    gfp_t flags)
+{
+	group = __backport_genl_group(family, group);
+	if (group == INVALID_GROUP)
+		return -EINVAL;
+	return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
+}
+EXPORT_SYMBOL_GPL(genlmsg_multicast_netns);
+
+int genlmsg_multicast(const struct genl_family *family,
+		      struct sk_buff *skb, u32 portid,
+		      unsigned int group, gfp_t flags)
+{
+	return genlmsg_multicast_netns(family, &init_net, skb,
+				       portid, group, flags);
+}
+EXPORT_SYMBOL_GPL(genlmsg_multicast);
+
+static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
+			 gfp_t flags)
+{
+	struct sk_buff *tmp;
+	struct net *net, *prev = NULL;
+	bool delivered = false;
+	int err;
+
+	for_each_net_rcu(net) {
+		if (prev) {
+			tmp = skb_clone(skb, flags);
+			if (!tmp) {
+				err = -ENOMEM;
+				goto error;
+			}
+			err = nlmsg_multicast(prev->genl_sock, tmp,
+					      portid, group, flags);
+			if (!err)
+				delivered = true;
+			else if (err != -ESRCH)
+				goto error;
+		}
+
+		prev = net;
+	}
+
+	err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags);
+	if (!err)
+		delivered = true;
+	else if (err != -ESRCH)
+		return err;
+	return delivered ? 0 : -ESRCH;
+ error:
+	kfree_skb(skb);
+	return err;
+}
+
+int backport_genlmsg_multicast_allns(const struct genl_family *family,
+				     struct sk_buff *skb, u32 portid,
+				     unsigned int group, gfp_t flags)
+{
+	group = __backport_genl_group(family, group);
+	if (group == INVALID_GROUP)
+		return -EINVAL;
+	return genlmsg_mcast(skb, portid, group, flags);
+}
+EXPORT_SYMBOL_GPL(backport_genlmsg_multicast_allns);
diff --git a/backport/compat/compat-3.3.c b/backport/compat/compat-3.3.c
index c064f09d9abe..1185a5d2d4e0 100644
--- a/backport/compat/compat-3.3.c
+++ b/backport/compat/compat-3.3.c
@@ -224,16 +224,3 @@ void backport_destroy_workqueue(struct workqueue_struct *wq)
 	spin_unlock(&wq_name_lock);
 }
 EXPORT_SYMBOL_GPL(backport_destroy_workqueue);
-
-void genl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
-		 struct nlmsghdr *nlh, gfp_t flags)
-{
-	struct sock *sk = net->genl_sock;
-	int report = 0;
-
-	if (nlh)
-		report = nlmsg_report(nlh);
-
-	nlmsg_notify(sk, skb, pid, group, report, flags);
-}
-EXPORT_SYMBOL_GPL(genl_notify);
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 6/6] backports: genetlink: update completely
  2018-10-02 17:51 ` [PATCH 6/6] backports: genetlink: update completely Johannes Berg
@ 2018-10-02 18:38   ` Johannes Berg
  0 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2018-10-02 18:38 UTC (permalink / raw)
  To: backports

On Tue, 2018-10-02 at 19:51 +0200, Johannes Berg wrote:
> 
> +static int backport_pre_doit(__genl_const struct genl_ops *ops,
> +			     struct sk_buff *skb,
> +			     struct genl_info *info)
> +{
> +	const struct genl_family *family = find_family_real_ops(&ops);
> +	int err;
> +#if LINUX_VERSION_IS_LESS(4,12,0)
> +	struct netlink_ext_ack *extack = kzalloc(sizeof(*extack), GFP_KERNEL);
> +
> +	__bp_genl_info_userhdr_set(info, extack);
> +
> +	if (!extack) {
> +		__bp_genl_info_userhdr_set(info, ERR_PTR(-ENOMEM));
> +		return -ENOMEM;
> +	}
> +
> +	extack->__bp_doit = ops->doit;
> +#else
> +	struct netlink_ext_ack *extack = info->extack;
> +#endif
> +
> +	err = nlmsg_validate(info->nlhdr, GENL_HDRLEN + family->hdrsize,
> +			     family->maxattr, ops->policy, extack);
> +	if (err)
> +		return err;
> +
> +	err = family->pre_doit(ops, skb, info);
> +
> +#if LINUX_VERSION_IS_LESS(4,12,0)
> +	if (err) {
> +		__bp_genl_info_userhdr_set(info, ERR_PTR(err));
> +		kfree(extack);
> +	}
> +#endif

This is wrong, it doesn't free the extack on errors.

We could also immediately send the ACK out, I think, and include the
error there.

johannes
--
To unsubscribe from this list: send the line "unsubscribe backports" in

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-10-02 18:39 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-02 17:51 [PATCH 1/6] backports: rename magic functions for netlink parsing Johannes Berg
2018-10-02 17:51 ` [PATCH 2/6] backports: fix genlmsg_nlhdr() backport Johannes Berg
2018-10-02 17:51 ` [PATCH 3/6] backports: add copy-list.hwsim Johannes Berg
2018-10-02 17:51 ` [PATCH 4/6] backports: backport most of improved netlink policy validation Johannes Berg
2018-10-02 17:51 ` [PATCH 5/6] backports: add __skb_peek() Johannes Berg
2018-10-02 17:51 ` [PATCH 6/6] backports: genetlink: update completely Johannes Berg
2018-10-02 18:38   ` Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.