From a6c758229e79375efcbf4b30a68cd8c24b48e88f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 7 Oct 2022 18:29:07 +0200 Subject: [PATCH] libiptc: Fix for segfault when renaming a chain This is an odd bug: If the number of chains is right and one renames the last one in the list, libiptc dereferences a NULL pointer. Add fix and test case for it. Fixes: 64ff47cde38e4 ("libiptc: fix chain rename bug in libiptc") Reported-by: Julien Castets Signed-off-by: Phil Sutter (cherry picked from commit 97bf4e68fc0794adba3243fd96f40f4568e7216f) --- .../testcases/chain/0006rename-segfault_0 | 19 +++++++++++++++++++ libiptc/libiptc.c | 9 +++++++++ 2 files changed, 28 insertions(+) create mode 100755 iptables/tests/shell/testcases/chain/0006rename-segfault_0 diff --git a/iptables/tests/shell/testcases/chain/0006rename-segfault_0 b/iptables/tests/shell/testcases/chain/0006rename-segfault_0 new file mode 100755 index 0000000000000..c10a8006b56b4 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0006rename-segfault_0 @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Cover for a bug in libiptc: +# - the chain 'node-98-tmp' is the last in the list sorted by name +# - there are 81 chains in total, so three chain index buckets +# - the last index bucket contains only the 'node-98-tmp' chain +# => rename temporarily removes it from the bucket, leaving a NULL bucket +# behind which is dereferenced later when inserting the chain again with new +# name again + +( + echo "*filter" + for chain in node-1 node-10 node-101 node-102 node-104 node-107 node-11 node-12 node-13 node-14 node-15 node-16 node-17 node-18 node-19 node-2 node-20 node-21 node-22 node-23 node-25 node-26 node-27 node-28 node-29 node-3 node-30 node-31 node-32 node-33 node-34 node-36 node-37 node-39 node-4 node-40 node-41 node-42 node-43 node-44 node-45 node-46 node-47 node-48 node-49 node-5 node-50 node-51 node-53 node-54 node-55 node-56 node-57 node-58 node-59 node-6 node-60 node-61 node-62 node-63 node-64 node-65 node-66 node-68 node-69 node-7 node-70 node-71 node-74 node-75 node-76 node-8 node-80 node-81 node-86 node-89 node-9 node-92 node-93 node-95 node-98-tmp; do + echo ":$chain - [0:0]" + done + echo "COMMIT" +) | $XT_MULTI iptables-restore +$XT_MULTI iptables -E node-98-tmp node-98 +exit $? diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 5888201525213..56bb75e5c3bef 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -606,6 +606,15 @@ static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handl if (index_ptr == &c->list) { /* Chain used as index ptr */ + /* If this is the last chain in the list, its index bucket just + * became empty. Adjust the size to avoid a NULL-pointer deref + * later. + */ + if (next == &h->chains) { + h->chain_index_sz--; + return 0; + } + /* See if its possible to avoid a rebuild, by shifting * to next pointer. Its possible if the next pointer * is located in the same index bucket. -- 2.40.0