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

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

1) Incorrect loop in error path of nft_set_elem_expr_clone(),
   from Colin Ian King.

2) Missing xt_table_get_private_protected() to access table
   private data in x_tables, from Subash Abhinov Kasiviswanathan.

3) Possible oops in ipset hash type resize, from Vasily Averin.

4) Fix shift-out-of-bounds in ipset hash type, also from Vasily.

* git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf:
  netfilter: ipset: fix shift-out-of-bounds in htable_bits()
  netfilter: ipset: fixes possible oops in mtype_resize
  netfilter: x_tables: Update remaining dereference to RCU
  netfilter: nftables: fix incorrect increment of loop counter
====================

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


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 698285da 5c8193f5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1379,7 +1379,7 @@ static int compat_get_entries(struct net *net,
	xt_compat_lock(NFPROTO_ARP);
	t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
	if (!IS_ERR(t)) {
		const struct xt_table_info *private = t->private;
		const struct xt_table_info *private = xt_table_get_private_protected(t);
		struct xt_table_info info;

		ret = compat_table_info(private, &info);
+1 −1
Original line number Diff line number Diff line
@@ -1589,7 +1589,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
	xt_compat_lock(AF_INET);
	t = xt_find_table_lock(net, AF_INET, get.name);
	if (!IS_ERR(t)) {
		const struct xt_table_info *private = t->private;
		const struct xt_table_info *private = xt_table_get_private_protected(t);
		struct xt_table_info info;
		ret = compat_table_info(private, &info);
		if (!ret && get.size == info.size)
+1 −1
Original line number Diff line number Diff line
@@ -1598,7 +1598,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
	xt_compat_lock(AF_INET6);
	t = xt_find_table_lock(net, AF_INET6, get.name);
	if (!IS_ERR(t)) {
		const struct xt_table_info *private = t->private;
		const struct xt_table_info *private = xt_table_get_private_protected(t);
		struct xt_table_info info;
		ret = compat_table_info(private, &info);
		if (!ret && get.size == info.size)
+18 −24
Original line number Diff line number Diff line
@@ -141,20 +141,6 @@ htable_size(u8 hbits)
	return hsize * sizeof(struct hbucket *) + sizeof(struct htable);
}

/* Compute htable_bits from the user input parameter hashsize */
static u8
htable_bits(u32 hashsize)
{
	/* Assume that hashsize == 2^htable_bits */
	u8 bits = fls(hashsize - 1);

	if (jhash_size(bits) != hashsize)
		/* Round up to the first 2^n value */
		bits = fls(hashsize);

	return bits;
}

#ifdef IP_SET_HASH_WITH_NETS
#if IPSET_NET_COUNT > 1
#define __CIDR(cidr, i)		(cidr[i])
@@ -640,7 +626,7 @@ mtype_resize(struct ip_set *set, bool retried)
	struct htype *h = set->data;
	struct htable *t, *orig;
	u8 htable_bits;
	size_t dsize = set->dsize;
	size_t hsize, dsize = set->dsize;
#ifdef IP_SET_HASH_WITH_NETS
	u8 flags;
	struct mtype_elem *tmp;
@@ -664,14 +650,12 @@ mtype_resize(struct ip_set *set, bool retried)
retry:
	ret = 0;
	htable_bits++;
	if (!htable_bits) {
		/* In case we have plenty of memory :-) */
		pr_warn("Cannot increase the hashsize of set %s further\n",
			set->name);
		ret = -IPSET_ERR_HASH_FULL;
		goto out;
	}
	t = ip_set_alloc(htable_size(htable_bits));
	if (!htable_bits)
		goto hbwarn;
	hsize = htable_size(htable_bits);
	if (!hsize)
		goto hbwarn;
	t = ip_set_alloc(hsize);
	if (!t) {
		ret = -ENOMEM;
		goto out;
@@ -813,6 +797,12 @@ mtype_resize(struct ip_set *set, bool retried)
	if (ret == -EAGAIN)
		goto retry;
	goto out;

hbwarn:
	/* In case we have plenty of memory :-) */
	pr_warn("Cannot increase the hashsize of set %s further\n", set->name);
	ret = -IPSET_ERR_HASH_FULL;
	goto out;
}

/* Get the current number of elements and ext_size in the set  */
@@ -1521,7 +1511,11 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
	if (!h)
		return -ENOMEM;

	hbits = htable_bits(hashsize);
	/* Compute htable_bits from the user input parameter hashsize.
	 * Assume that hashsize == 2^htable_bits,
	 * otherwise round up to the first 2^n value.
	 */
	hbits = fls(hashsize - 1);
	hsize = htable_size(hbits);
	if (hsize == 0) {
		kfree(h);
+2 −2
Original line number Diff line number Diff line
@@ -5254,8 +5254,8 @@ static int nft_set_elem_expr_clone(const struct nft_ctx *ctx,
	return 0;

err_expr:
	for (k = i - 1; k >= 0; k++)
		nft_expr_destroy(ctx, expr_array[i]);
	for (k = i - 1; k >= 0; k--)
		nft_expr_destroy(ctx, expr_array[k]);

	return -ENOMEM;
}