[pkg-netfilter-team] Bug#968457: Bug#968457: iptables: segfault with specific command when run as non-root

Jeremy Sowden jeremy at azazel.net
Sun Aug 16 16:02:12 BST 2020


On 2020-08-16, at 14:48:12 +0200, Bernhard Übelacker wrote:
> Program received signal SIGSEGV, Segmentation fault.
> nftnl_rule_list_add (r=r at entry=0x5555555f5900, list=0x0) at rule.c:782
> 782             list_add(&r->head, &list->list);
> (gdb) bt
> #0  nftnl_rule_list_add (r=r at entry=0x5555555f5900, list=0x0) at rule.c:782
> #1  0x0000555555567eac in nft_rule_insert (h=h at entry=0x7fffffffe480, chain=chain at entry=0x7fffffffe848 "OUTPUT", table=table at entry=0x55555557b126 "filter", data=data at entry=0x7fffffffe300, rulenum=rulenum at entry=0, verbose=verbose at entry=false) at nft.c:2146
> #2  0x0000555555562629 in add_entry (chain=0x7fffffffe848 "OUTPUT", table=0x55555557b126 "filter", cs=cs at entry=0x7fffffffe300, rulenum=0, family=2, s=..., d=..., verbose=false, h=0x7fffffffe480, append=false) at xtables.c:412
> #3  0x0000555555564270 in do_commandx (h=h at entry=0x7fffffffe480, argc=argc at entry=3, argv=argv at entry=0x7fffffffe608, table=table at entry=0x7fffffffe478, restore=restore at entry=false) at xtables.c:1122
> #4  0x0000555555562350 in xtables_main (family=family at entry=2, progname=progname at entry=0x55555557a011 "iptables", argc=3, argv=0x7fffffffe608) at xtables-standalone.c:72
> #5  0x000055555556248a in xtables_ip4_main (argc=<optimized out>, argv=<optimized out>) at xtables-standalone.c:96
> #6  0x00007ffff763809b in __libc_start_main (main=0x55555555cfb0 <main>, argc=3, argv=0x7fffffffe608, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe5f8) at ../csu/libc-start.c:308
> #7  0x000055555555cfea in _start ()

Here is the relevant part of nft_rule_insert (iptables/nft.c,
ll. 2131ff.):

	if (rulenum > 0) {
		list = nft_rule_list_get(h);
		if (list == NULL)
			goto err;

		r = nft_rule_find(h, list, chain, table, data, rulenum);
		if (r == NULL) {
			/* special case: iptables allows to insert into
			 * rule_count + 1 position.
			 */
			r = nft_rule_find(h, list, chain, table, data,
					  rulenum - 1);
			if (r != NULL)
				return nft_rule_append(h, chain, table, data,
						       0, verbose);

			errno = ENOENT;
			goto err;
		}

		handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE);
		DEBUGP("adding after rule handle %"PRIu64"\n", handle);
	} else {
		nft_rule_list_get(h);
	}

	new_rule = nft_rule_add(h, chain, table, data, handle, verbose);
	if (!new_rule)
		goto err;

	if (handle)
		nftnl_rule_list_insert_at(new_rule, r);
	else
		nftnl_rule_list_add(new_rule, h->rule_cache);

If rulenum == 0, the code assumes that nft_rule_list_get, which sets
h->rule_cache, does not fail.

Here is the relevant part of nft_rule_list_get (iptables/nft.c,
ll. 1407ff.):

	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
					NLM_F_DUMP, h->seq);

	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list);
	if (ret < 0) {
		if (errno == EINTR) {
			assert(nft_restart(h) >= 0);
			nftnl_rule_list_free(list);
			goto retry;
		}

		nftnl_rule_list_free(list);
		return NULL;
	}

Because we are running iptables as an unprivileged user, the kernel
returns EPERM in response to our NFT_MSG_GETRULE request.

We need to check the return value of nft_rule_list_get in both cases.

Patch attached.

J.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: iptables-nft.eperm_segv_fix.patch
Type: text/x-diff
Size: 724 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-netfilter-team/attachments/20200816/43b1e400/attachment.patch>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-netfilter-team/attachments/20200816/43b1e400/attachment.sig>


More information about the pkg-netfilter-team mailing list