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

====================
netfilter updates for net

Three late fixes for netfilter:

1) If nf_queue user requests packet truncation below size of l3 header,
   we corrupt the skb, then crash.  Reject such requests.

2) add cond_resched() calls when doing cycle detection in the
   nf_tables graph.  This avoids softlockup warning with certain
   rulesets.

3) Reject rulesets that use nftables 'queue' expression in family/chain
   combinations other than those that are supported.  Currently the ruleset
   will load, but when userspace attempts to reinject you get WARN splat +
   packet drops.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nft_queue: only allow supported familes and hooks
  netfilter: nf_tables: add rescheduling points during loop detection walks
  netfilter: nf_queue: do not allow packet truncation below transport header offset
====================

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


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e53f5293 47f4f510
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -3340,6 +3340,8 @@ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
			if (err < 0)
				return err;
		}

		cond_resched();
	}

	return 0;
@@ -9367,9 +9369,13 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
				break;
			}
		}

		cond_resched();
	}

	list_for_each_entry(set, &ctx->table->sets, list) {
		cond_resched();

		if (!nft_is_active_next(ctx->net, set))
			continue;
		if (!(set->flags & NFT_SET_MAP) ||
+6 −1
Original line number Diff line number Diff line
@@ -843,11 +843,16 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
}

static int
nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff)
{
	struct sk_buff *nskb;

	if (diff < 0) {
		unsigned int min_len = skb_transport_offset(e->skb);

		if (data_len < min_len)
			return -EINVAL;

		if (pskb_trim(e->skb, data_len))
			return -ENOMEM;
	} else if (diff > 0) {
+27 −0
Original line number Diff line number Diff line
@@ -68,6 +68,31 @@ static void nft_queue_sreg_eval(const struct nft_expr *expr,
	regs->verdict.code = ret;
}

static int nft_queue_validate(const struct nft_ctx *ctx,
			      const struct nft_expr *expr,
			      const struct nft_data **data)
{
	static const unsigned int supported_hooks = ((1 << NF_INET_PRE_ROUTING) |
						     (1 << NF_INET_LOCAL_IN) |
						     (1 << NF_INET_FORWARD) |
						     (1 << NF_INET_LOCAL_OUT) |
						     (1 << NF_INET_POST_ROUTING));

	switch (ctx->family) {
	case NFPROTO_IPV4:
	case NFPROTO_IPV6:
	case NFPROTO_INET:
	case NFPROTO_BRIDGE:
		break;
	case NFPROTO_NETDEV: /* lacks okfn */
		fallthrough;
	default:
		return -EOPNOTSUPP;
	}

	return nft_chain_validate_hooks(ctx->chain, supported_hooks);
}

static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
	[NFTA_QUEUE_NUM]	= { .type = NLA_U16 },
	[NFTA_QUEUE_TOTAL]	= { .type = NLA_U16 },
@@ -164,6 +189,7 @@ static const struct nft_expr_ops nft_queue_ops = {
	.eval		= nft_queue_eval,
	.init		= nft_queue_init,
	.dump		= nft_queue_dump,
	.validate	= nft_queue_validate,
	.reduce		= NFT_REDUCE_READONLY,
};

@@ -173,6 +199,7 @@ static const struct nft_expr_ops nft_queue_sreg_ops = {
	.eval		= nft_queue_sreg_eval,
	.init		= nft_queue_sreg_init,
	.dump		= nft_queue_sreg_dump,
	.validate	= nft_queue_validate,
	.reduce		= NFT_REDUCE_READONLY,
};