Commit a717932d authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Update nf_tables kdoc to keep it in sync with the code, from George Guo.

2) Handle NETDEV_UNREGISTER event for inet/ingress basechain.

3) Reject configuration that cause nft_limit to overflow,
   from Florian Westphal.

4) Restrict anonymous set/map names to 16 bytes, from Florian Westphal.

5) Disallow to encode queue number and error in verdicts. This reverts
   a patch which seems to have introduced an early attempt to support for
   nfqueue maps, which is these days supported via nft_queue expression.

6) Sanitize family via .validate for expressions that explicitly refer
   to NF_INET_* hooks.

* tag 'nf-24-01-24' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nf_tables: validate NFPROTO_* family
  netfilter: nf_tables: reject QUEUE/DROP verdict parameters
  netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
  netfilter: nft_limit: reject configurations that cause integer overflow
  netfilter: nft_chain_filter: handle NETDEV_UNREGISTER for inet/ingress basechain
  netfilter: nf_tables: cleanup documentation
====================

Link: https://lore.kernel.org/r/20240124191248.75463-1-pablo@netfilter.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents f6cc4b6a d0009eff
Loading
Loading
Loading
Loading
+39 −10
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
 *	@nla: netlink attributes
 *	@portid: netlink portID of the original message
 *	@seq: netlink sequence number
 *	@flags: modifiers to new request
 *	@family: protocol family
 *	@level: depth of the chains
 *	@report: notify via unicast netlink message
@@ -282,6 +283,7 @@ struct nft_elem_priv { };
 *
 *	@key: element key
 *	@key_end: closing element key
 *	@data: element data
 *	@priv: element private data and extensions
 */
struct nft_set_elem {
@@ -325,10 +327,10 @@ struct nft_set_iter {
 *	@dtype: data type
 *	@dlen: data length
 *	@objtype: object type
 *	@flags: flags
 *	@size: number of set elements
 *	@policy: set policy
 *	@gc_int: garbage collector interval
 *	@timeout: element timeout
 *	@field_len: length of each field in concatenation, bytes
 *	@field_count: number of concatenated fields in element
 *	@expr: set must support for expressions
@@ -351,9 +353,9 @@ struct nft_set_desc {
/**
 *	enum nft_set_class - performance class
 *
 *	@NFT_LOOKUP_O_1: constant, O(1)
 *	@NFT_LOOKUP_O_LOG_N: logarithmic, O(log N)
 *	@NFT_LOOKUP_O_N: linear, O(N)
 *	@NFT_SET_CLASS_O_1: constant, O(1)
 *	@NFT_SET_CLASS_O_LOG_N: logarithmic, O(log N)
 *	@NFT_SET_CLASS_O_N: linear, O(N)
 */
enum nft_set_class {
	NFT_SET_CLASS_O_1,
@@ -422,9 +424,13 @@ struct nft_set_ext;
 *	@remove: remove element from set
 *	@walk: iterate over all set elements
 *	@get: get set elements
 *	@commit: commit set elements
 *	@abort: abort set elements
 *	@privsize: function to return size of set private data
 *	@estimate: estimate the required memory size and the lookup complexity class
 *	@init: initialize private data of new set instance
 *	@destroy: destroy private data of set instance
 *	@gc_init: initialize garbage collection
 *	@elemsize: element private size
 *
 *	Operations lookup, update and delete have simpler interfaces, are faster
@@ -540,13 +546,16 @@ struct nft_set_elem_expr {
 *	@policy: set parameterization (see enum nft_set_policies)
 *	@udlen: user data length
 *	@udata: user data
 *	@expr: stateful expression
 *	@pending_update: list of pending update set element
 * 	@ops: set ops
 * 	@flags: set flags
 *	@dead: set will be freed, never cleared
 *	@genmask: generation mask
 * 	@klen: key length
 * 	@dlen: data length
 *	@num_exprs: numbers of exprs
 *	@exprs: stateful expression
 *	@catchall_list: list of catch-all set element
 * 	@data: private set data
 */
struct nft_set {
@@ -692,6 +701,7 @@ extern const struct nft_set_ext_type nft_set_ext_types[];
 *
 *	@len: length of extension area
 *	@offset: offsets of individual extension types
 *	@ext_len: length of the expected extension(used to sanity check)
 */
struct nft_set_ext_tmpl {
	u16	len;
@@ -840,6 +850,7 @@ struct nft_expr_ops;
 *	@select_ops: function to select nft_expr_ops
 *	@release_ops: release nft_expr_ops
 *	@ops: default ops, used when no select_ops functions is present
 *	@inner_ops: inner ops, used for inner packet operation
 *	@list: used internally
 *	@name: Identifier
 *	@owner: module reference
@@ -881,14 +892,22 @@ struct nft_offload_ctx;
 *	struct nft_expr_ops - nf_tables expression operations
 *
 *	@eval: Expression evaluation function
 *	@clone: Expression clone function
 *	@size: full expression size, including private data size
 *	@init: initialization function
 *	@activate: activate expression in the next generation
 *	@deactivate: deactivate expression in next generation
 *	@destroy: destruction function, called after synchronize_rcu
 *	@destroy_clone: destruction clone function
 *	@dump: function to dump parameters
 *	@type: expression type
 *	@validate: validate expression, called during loop detection
 *	@reduce: reduce expression
 *	@gc: garbage collection expression
 *	@offload: hardware offload expression
 *	@offload_action: function to report true/false to allocate one slot or not in the flow
 *			 offload array
 *	@offload_stats: function to synchronize hardware stats via updating the counter expression
 *	@type: expression type
 *	@data: extra data to attach to this expression operation
 */
struct nft_expr_ops {
@@ -1041,14 +1060,21 @@ struct nft_rule_blob {
/**
 *	struct nft_chain - nf_tables chain
 *
 *	@blob_gen_0: rule blob pointer to the current generation
 *	@blob_gen_1: rule blob pointer to the future generation
 *	@rules: list of rules in the chain
 *	@list: used internally
 *	@rhlhead: used internally
 *	@table: table that this chain belongs to
 *	@handle: chain handle
 *	@use: number of jump references to this chain
 *	@flags: bitmask of enum nft_chain_flags
 *	@flags: bitmask of enum NFTA_CHAIN_FLAGS
 *	@bound: bind or not
 *	@genmask: generation mask
 *	@name: name of the chain
 *	@udlen: user data length
 *	@udata: user data in the chain
 *	@blob_next: rule blob pointer to the next in the chain
 */
struct nft_chain {
	struct nft_rule_blob		__rcu *blob_gen_0;
@@ -1146,6 +1172,7 @@ struct nft_hook {
 *	@hook_list: list of netfilter hooks (for NFPROTO_NETDEV family)
 *	@type: chain type
 *	@policy: default policy
 *	@flags: indicate the base chain disabled or not
 *	@stats: per-cpu chain stats
 *	@chain: the chain
 *	@flow_block: flow block (for hardware offload)
@@ -1274,11 +1301,13 @@ struct nft_object_hash_key {
 *	struct nft_object - nf_tables stateful object
 *
 *	@list: table stateful object list node
 *	@key:  keys that identify this object
 *	@rhlhead: nft_objname_ht node
 *	@key: keys that identify this object
 *	@genmask: generation mask
 *	@use: number of references to this stateful object
 *	@handle: unique object handle
 *	@udlen: length of user data
 *	@udata: user data
 *	@ops: object operations
 *	@data: object data, layout depends on type
 */
@@ -1344,6 +1373,7 @@ struct nft_object_type {
 *	@destroy: release existing stateful object
 *	@dump: netlink dump stateful object
 *	@update: update stateful object
 *	@type: pointer to object type
 */
struct nft_object_ops {
	void				(*eval)(struct nft_object *obj,
@@ -1379,9 +1409,8 @@ void nft_unregister_obj(struct nft_object_type *obj_type);
 *	@genmask: generation mask
 *	@use: number of references to this flow table
 * 	@handle: unique object handle
 *	@dev_name: array of device names
 *	@hook_list: hook list for hooks per net_device in flowtables
 *	@data: rhashtable and garbage collector
 * 	@ops: array of hooks
 */
struct nft_flowtable {
	struct list_head		list;
+10 −10
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <net/sock.h>

#define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-"))
#define NFT_SET_MAX_ANONLEN 16

unsigned int nf_tables_net_id __read_mostly;

@@ -4413,6 +4414,9 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
		if (p[1] != 'd' || strchr(p + 2, '%'))
			return -EINVAL;

		if (strnlen(name, NFT_SET_MAX_ANONLEN) >= NFT_SET_MAX_ANONLEN)
			return -EINVAL;

		inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
		if (inuse == NULL)
			return -ENOMEM;
@@ -10988,16 +10992,10 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
	data->verdict.code = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));

	switch (data->verdict.code) {
	default:
		switch (data->verdict.code & NF_VERDICT_MASK) {
	case NF_ACCEPT:
	case NF_DROP:
	case NF_QUEUE:
		break;
		default:
			return -EINVAL;
		}
		fallthrough;
	case NFT_CONTINUE:
	case NFT_BREAK:
	case NFT_RETURN:
@@ -11032,6 +11030,8 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,

		data->verdict.chain = chain;
		break;
	default:
		return -EINVAL;
	}

	desc->len = sizeof(data->verdict);
+9 −2
Original line number Diff line number Diff line
@@ -357,9 +357,10 @@ static int nf_tables_netdev_event(struct notifier_block *this,
				  unsigned long event, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct nft_base_chain *basechain;
	struct nftables_pernet *nft_net;
	struct nft_table *table;
	struct nft_chain *chain, *nr;
	struct nft_table *table;
	struct nft_ctx ctx = {
		.net	= dev_net(dev),
	};
@@ -371,7 +372,8 @@ static int nf_tables_netdev_event(struct notifier_block *this,
	nft_net = nft_pernet(ctx.net);
	mutex_lock(&nft_net->commit_mutex);
	list_for_each_entry(table, &nft_net->tables, list) {
		if (table->family != NFPROTO_NETDEV)
		if (table->family != NFPROTO_NETDEV &&
		    table->family != NFPROTO_INET)
			continue;

		ctx.family = table->family;
@@ -380,6 +382,11 @@ static int nf_tables_netdev_event(struct notifier_block *this,
			if (!nft_is_base_chain(chain))
				continue;

			basechain = nft_base_chain(chain);
			if (table->family == NFPROTO_INET &&
			    basechain->ops.hooknum != NF_INET_INGRESS)
				continue;

			ctx.chain = chain;
			nft_netdev_event(event, dev, &ctx);
		}
+12 −0
Original line number Diff line number Diff line
@@ -350,6 +350,12 @@ static int nft_target_validate(const struct nft_ctx *ctx,
	unsigned int hook_mask = 0;
	int ret;

	if (ctx->family != NFPROTO_IPV4 &&
	    ctx->family != NFPROTO_IPV6 &&
	    ctx->family != NFPROTO_BRIDGE &&
	    ctx->family != NFPROTO_ARP)
		return -EOPNOTSUPP;

	if (nft_is_base_chain(ctx->chain)) {
		const struct nft_base_chain *basechain =
						nft_base_chain(ctx->chain);
@@ -595,6 +601,12 @@ static int nft_match_validate(const struct nft_ctx *ctx,
	unsigned int hook_mask = 0;
	int ret;

	if (ctx->family != NFPROTO_IPV4 &&
	    ctx->family != NFPROTO_IPV6 &&
	    ctx->family != NFPROTO_BRIDGE &&
	    ctx->family != NFPROTO_ARP)
		return -EOPNOTSUPP;

	if (nft_is_base_chain(ctx->chain)) {
		const struct nft_base_chain *basechain =
						nft_base_chain(ctx->chain);
+5 −0
Original line number Diff line number Diff line
@@ -384,6 +384,11 @@ static int nft_flow_offload_validate(const struct nft_ctx *ctx,
{
	unsigned int hook_mask = (1 << NF_INET_FORWARD);

	if (ctx->family != NFPROTO_IPV4 &&
	    ctx->family != NFPROTO_IPV6 &&
	    ctx->family != NFPROTO_INET)
		return -EOPNOTSUPP;

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

Loading