On 2020-08-16, at 14:48:12 +0200, Bernhard Übelacker wrote: > Program received signal SIGSEGV, Segmentation fault. > nftnl_rule_list_add (r=r@entry=0x5555555f5900, list=0x0) at rule.c:782 > 782 list_add(&r->head, &list->list); > (gdb) bt > #0 nftnl_rule_list_add (r=r@entry=0x5555555f5900, list=0x0) at rule.c:782 > #1 0x0000555555567eac in nft_rule_insert (h=h@entry=0x7fffffffe480, > chain=chain@entry=0x7fffffffe848 "OUTPUT", table=table@entry=0x55555557b126 > "filter", data=data@entry=0x7fffffffe300, rulenum=rulenum@entry=0, > verbose=verbose@entry=false) at nft.c:2146 > #2 0x0000555555562629 in add_entry (chain=0x7fffffffe848 "OUTPUT", > table=0x55555557b126 "filter", cs=cs@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@entry=0x7fffffffe480, > argc=argc@entry=3, argv=argv@entry=0x7fffffffe608, > table=table@entry=0x7fffffffe478, restore=restore@entry=false) at > xtables.c:1122 > #4 0x0000555555562350 in xtables_main (family=family@entry=2, > progname=progname@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.
--- iptables/nft.c.orig 2020-08-16 15:58:02.799901382 +0100 +++ iptables/nft.c 2020-08-16 15:58:07.507901423 +0100 @@ -2110,11 +2110,11 @@ nft_fn = nft_rule_insert; - if (rulenum > 0) { - list = nft_rule_list_get(h); - if (list == NULL) - goto err; + list = nft_rule_list_get(h); + if (list == NULL) + goto err; + if (rulenum > 0) { r = nft_rule_find(h, list, chain, table, data, rulenum); if (r == NULL) { /* special case: iptables allows to insert into @@ -2132,8 +2132,6 @@ 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);
signature.asc
Description: PGP signature