Commit bec13ba9 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Florian Westphal says:

====================
netfilter: conntrack and nf_tables bug fixes

The following patchset contains netfilter fixes for net.

Broken since 5.19:
  A few ancient connection tracking helpers assume TCP packets cannot
  exceed 64kb in size, but this isn't the case anymore with 5.19 when
  BIG TCP got merged, from myself.

Regressions since 5.19:
  1. 'conntrack -E expect' won't display anything because nfnetlink failed
     to enable events for expectations, only for normal conntrack events.

  2. partially revert change that added resched calls to a function that can
     be in atomic context.  Both broken and fixed up by myself.

Broken for several releases (up to original merge of nf_tables):
  Several fixes for nf_tables control plane, from Pablo.
  This fixes up resource leaks in error paths and adds more sanity
  checks for mutually exclusive attributes/flags.

Kconfig:
  NF_CONNTRACK_PROCFS is very old and doesn't provide all info provided
  via ctnetlink, so it should not default to y. From Geert Uytterhoeven.

Selftests:
  rework nft_flowtable.sh: it frequently indicated failure; the way it
  tried to detect an offload failure did not work reliably.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  testing: selftests: nft_flowtable.sh: rework test to detect offload failure
  testing: selftests: nft_flowtable.sh: use random netns names
  netfilter: conntrack: NF_CONNTRACK_PROCFS should no longer default to y
  netfilter: nf_tables: check NFT_SET_CONCAT flag if field_count is specified
  netfilter: nf_tables: disallow NFT_SET_ELEM_CATCHALL and NFT_SET_ELEM_INTERVAL_END
  netfilter: nf_tables: NFTA_SET_ELEM_KEY_END requires concat and interval flags
  netfilter: nf_tables: validate NFTA_SET_ELEM_OBJREF based on NFT_SET_OBJECT flag
  netfilter: nf_tables: really skip inactive sets when allocating name
  netfilter: nfnetlink: re-enable conntrack expectation events
  netfilter: nf_tables: fix scheduling-while-atomic splat
  netfilter: nf_ct_irc: cap packet search space to 4k
  netfilter: nf_ct_ftp: prefer skb_linearize
  netfilter: nf_ct_h323: cap packet size at 64k
  netfilter: nf_ct_sane: remove pseudo skb linearization
  netfilter: nf_tables: possible module reference underflow in error path
  netfilter: nf_tables: disallow NFTA_SET_ELEM_KEY_END with NFT_SET_ELEM_INTERVAL_END flag
  netfilter: nf_tables: use READ_ONCE and WRITE_ONCE for shared generation id access
====================

Link: https://lore.kernel.org/r/20220817140015.25843-1-fw@strlen.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents fc4aaf9f c8550b90
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ struct nf_ip_net {

struct netns_ct {
#ifdef CONFIG_NF_CONNTRACK_EVENTS
	bool ctnetlink_has_listener;
	u8 ctnetlink_has_listener;
	bool ecache_dwork_pending;
#endif
	u8			sysctl_log_invalid; /* Log invalid packets */
+0 −1
Original line number Diff line number Diff line
@@ -144,7 +144,6 @@ config NF_CONNTRACK_ZONES

config NF_CONNTRACK_PROCFS
	bool "Supply CT list in procfs (OBSOLETE)"
	default y
	depends on PROC_FS
	help
	This option enables for the list of known conntrack entries
+6 −18
Original line number Diff line number Diff line
@@ -34,11 +34,6 @@ MODULE_DESCRIPTION("ftp connection tracking helper");
MODULE_ALIAS("ip_conntrack_ftp");
MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);

/* This is slow, but it's simple. --RR */
static char *ftp_buffer;

static DEFINE_SPINLOCK(nf_ftp_lock);

#define MAX_PORTS 8
static u_int16_t ports[MAX_PORTS];
static unsigned int ports_c;
@@ -398,6 +393,9 @@ static int help(struct sk_buff *skb,
		return NF_ACCEPT;
	}

	if (unlikely(skb_linearize(skb)))
		return NF_DROP;

	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
	if (th == NULL)
		return NF_ACCEPT;
@@ -411,12 +409,8 @@ static int help(struct sk_buff *skb,
	}
	datalen = skb->len - dataoff;

	spin_lock_bh(&nf_ftp_lock);
	fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
	if (!fb_ptr) {
		spin_unlock_bh(&nf_ftp_lock);
		return NF_ACCEPT;
	}
	spin_lock_bh(&ct->lock);
	fb_ptr = skb->data + dataoff;

	ends_in_nl = (fb_ptr[datalen - 1] == '\n');
	seq = ntohl(th->seq) + datalen;
@@ -544,7 +538,7 @@ static int help(struct sk_buff *skb,
	if (ends_in_nl)
		update_nl_seq(ct, seq, ct_ftp_info, dir, skb);
 out:
	spin_unlock_bh(&nf_ftp_lock);
	spin_unlock_bh(&ct->lock);
	return ret;
}

@@ -571,7 +565,6 @@ static const struct nf_conntrack_expect_policy ftp_exp_policy = {
static void __exit nf_conntrack_ftp_fini(void)
{
	nf_conntrack_helpers_unregister(ftp, ports_c * 2);
	kfree(ftp_buffer);
}

static int __init nf_conntrack_ftp_init(void)
@@ -580,10 +573,6 @@ static int __init nf_conntrack_ftp_init(void)

	NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_ftp_master));

	ftp_buffer = kmalloc(65536, GFP_KERNEL);
	if (!ftp_buffer)
		return -ENOMEM;

	if (ports_c == 0)
		ports[ports_c++] = FTP_PORT;

@@ -603,7 +592,6 @@ static int __init nf_conntrack_ftp_init(void)
	ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
	if (ret < 0) {
		pr_err("failed to register helpers\n");
		kfree(ftp_buffer);
		return ret;
	}

+9 −1
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include <net/netfilter/nf_conntrack_zones.h>
#include <linux/netfilter/nf_conntrack_h323.h>

#define H323_MAX_SIZE 65535

/* Parameters */
static unsigned int default_rrq_ttl __read_mostly = 300;
module_param(default_rrq_ttl, uint, 0600);
@@ -86,6 +88,9 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
	if (tcpdatalen <= 0)	/* No TCP data */
		goto clear_out;

	if (tcpdatalen > H323_MAX_SIZE)
		tcpdatalen = H323_MAX_SIZE;

	if (*data == NULL) {	/* first TPKT */
		/* Get first TPKT pointer */
		tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
@@ -1169,6 +1174,9 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
	if (dataoff >= skb->len)
		return NULL;
	*datalen = skb->len - dataoff;
	if (*datalen > H323_MAX_SIZE)
		*datalen = H323_MAX_SIZE;

	return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
}

@@ -1770,7 +1778,7 @@ static int __init nf_conntrack_h323_init(void)

	NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_h323_master));

	h323_buffer = kmalloc(65536, GFP_KERNEL);
	h323_buffer = kmalloc(H323_MAX_SIZE + 1, GFP_KERNEL);
	if (!h323_buffer)
		return -ENOMEM;
	ret = h323_helper_init();
+9 −3
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
EXPORT_SYMBOL_GPL(nf_nat_irc_hook);

#define HELPER_NAME "irc"
#define MAX_SEARCH_SIZE	4095

MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
@@ -121,6 +122,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
	int i, ret = NF_ACCEPT;
	char *addr_beg_p, *addr_end_p;
	typeof(nf_nat_irc_hook) nf_nat_irc;
	unsigned int datalen;

	/* If packet is coming from IRC server */
	if (dir == IP_CT_DIR_REPLY)
@@ -140,8 +142,12 @@ static int help(struct sk_buff *skb, unsigned int protoff,
	if (dataoff >= skb->len)
		return NF_ACCEPT;

	datalen = skb->len - dataoff;
	if (datalen > MAX_SEARCH_SIZE)
		datalen = MAX_SEARCH_SIZE;

	spin_lock_bh(&irc_buffer_lock);
	ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff,
	ib_ptr = skb_header_pointer(skb, dataoff, datalen,
				    irc_buffer);
	if (!ib_ptr) {
		spin_unlock_bh(&irc_buffer_lock);
@@ -149,7 +155,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
	}

	data = ib_ptr;
	data_limit = ib_ptr + skb->len - dataoff;
	data_limit = ib_ptr + datalen;

	/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
	 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
@@ -251,7 +257,7 @@ static int __init nf_conntrack_irc_init(void)
	irc_exp_policy.max_expected = max_dcc_channels;
	irc_exp_policy.timeout = dcc_timeout;

	irc_buffer = kmalloc(65536, GFP_KERNEL);
	irc_buffer = kmalloc(MAX_SEARCH_SIZE + 1, GFP_KERNEL);
	if (!irc_buffer)
		return -ENOMEM;

Loading