criu icon indicating copy to clipboard operation
criu copied to clipboard

iptables: Bad rule (does a matching rule exist in that chain?)

Open rst0git opened this issue 3 months ago • 1 comments

The socket-tcp-syn-sent test, running with the ns/uns flavors, fails in CircleCI when CRIU is built with libnftables-dev. Investigating further, it appears that CRIU does not restore the iptables rules created by the test. When this package is removed and CRIU is recompiled, it works as expected.

I was not able to reproduce this problem with newer kernel on Fedora.

$ uname -a
Linux ip-10-0-53-248 6.8.0-1019-aws #21~22.04.1-Ubuntu SMP Thu Nov  7 17:33:30 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

$ iptables --version
iptables v1.8.7 (nf_tables)

$ git diff
diff --git a/test/zdtm/static/socket-tcp-syn-sent.c b/test/zdtm/static/socket-tcp-syn-sent.c
index 8265d5fb7..76917240b 100644
--- a/test/zdtm/static/socket-tcp-syn-sent.c
+++ b/test/zdtm/static/socket-tcp-syn-sent.c
@@ -75,6 +75,8 @@ int main(int argc, char **argv)
        if (system(cmd))
                return -1;
 
+       system("iptables -L INPUT -n -v --line-numbers");
+
        /* Construct the server address structure */
        memset(&addr, 0, sizeof(addr));
        if (ZDTM_FAMILY == AF_INET) {
@@ -96,6 +98,8 @@ int main(int argc, char **argv)
        test_daemon();
        test_waitsig();
 
+       system("iptables -L INPUT -n -v --line-numbers");
+
        snprintf(cmd, sizeof(cmd), "iptables -w -t filter --protocol tcp -D INPUT --dport %d -j DROP", port);
        if (system(cmd))
                return -1;

The test output below shows that the DROP rule has not been restored:

python3 ./zdtm.py run -t zdtm/static/socket-tcp-syn-sent -f ns
userns is supported
Checking feature tcp_half_closed
tcp_half_closed is supported
Checking feature has_ipt_legacy
has_ipt_legacy is supported
=== Run 1/1 ================ zdtm/static/socket-tcp-syn-sent
================== Run zdtm/static/socket-tcp-syn-sent in ns ===================
 DEP       socket-tcp-syn-sent.d
 CC        socket-tcp-syn-sent.o
 LINK      socket-tcp-syn-sent
Construct root for zdtm/static/socket-tcp-syn-sent
Start test
Test is SUID
Running zdtm/static/socket-tcp-syn-sent.hook(--post-start)
./socket-tcp-syn-sent --pidfile=socket-tcp-syn-sent.pid --outfile=socket-tcp-syn-sent.out
Running zdtm/static/socket-tcp-syn-sent.hook(--pre-dump)
State                      Recv-Q                   Send-Q                                     Local Address:Port                                      Peer Address:Port                  Process                   
LISTEN                     0                        1                                                0.0.0.0:8880                                           0.0.0.0:*                                               
SYN-SENT                   0                        1                                              127.0.0.1:51469                                        127.0.0.1:8880                                            
Run criu dump
Running zdtm/static/socket-tcp-syn-sent.hook(--pre-restore)
Run criu restore
=[log]=> dump/zdtm/static/socket-tcp-syn-sent/135/1/restore.log
------------------------ grep Error ------------------------
b'(00.003191)      1: No ipcns-sem-11.img image'
b'(00.003835)      1: net: Try to restore a link 10:1:lo'
b'(00.003837)      1: net: Restoring link lo type 1'
b'(00.004231)      1: net: \tRunning ip addr restore'
b'Error: ipv4: Address already assigned.'
b'Error: ipv6: address already assigned.'
------------------------ ERROR OVER ------------------------
Running zdtm/static/socket-tcp-syn-sent.hook(--post-restore)
State                      Recv-Q                   Send-Q                                     Local Address:Port                                      Peer Address:Port                  Process                   
LISTEN                     0                        1                                                0.0.0.0:8880                                           0.0.0.0:*                                               
SYN-SENT                   0                        1                                              127.0.0.1:51469                                        127.0.0.1:8880                                            
Check TCP images
Send the 15 signal to  172
Wait for zdtm/static/socket-tcp-syn-sent(172) to die for 0.100000
########## Test zdtm/static/socket-tcp-syn-sent FAIL at result check ###########
Test output: ================================
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8880
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        1    60 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           
iptables: Bad rule (does a matching rule exist in that chain?).

 <<< ================================
Running zdtm/static/socket-tcp-syn-sent.hook(--clean)
##################################### FAIL #####################################

When removing this package and rebuilding CRIU, the test passes:

python3 ./zdtm.py run -t zdtm/static/socket-tcp-syn-sent -f ns
userns is supported
Checking feature tcp_half_closed
tcp_half_closed is supported
Checking feature has_ipt_legacy
has_ipt_legacy is supported
=== Run 1/1 ================ zdtm/static/socket-tcp-syn-sent
================== Run zdtm/static/socket-tcp-syn-sent in ns ===================
 DEP       socket-tcp-syn-sent.d
 CC        socket-tcp-syn-sent.o
 LINK      socket-tcp-syn-sent
Construct root for zdtm/static/socket-tcp-syn-sent
Start test
Test is SUID
Running zdtm/static/socket-tcp-syn-sent.hook(--post-start)
./socket-tcp-syn-sent --pidfile=socket-tcp-syn-sent.pid --outfile=socket-tcp-syn-sent.out
Running zdtm/static/socket-tcp-syn-sent.hook(--pre-dump)
State                      Recv-Q                   Send-Q                                     Local Address:Port                                      Peer Address:Port                  Process                   
LISTEN                     0                        1                                                0.0.0.0:8880                                           0.0.0.0:*                                               
SYN-SENT                   0                        1                                              127.0.0.1:48163                                        127.0.0.1:8880                                            
Run criu dump
Running zdtm/static/socket-tcp-syn-sent.hook(--pre-restore)
Run criu restore
=[log]=> dump/zdtm/static/socket-tcp-syn-sent/135/1/restore.log
------------------------ grep Error ------------------------
b'(00.002958)      1: No ipcns-sem-11.img image'
b'(00.003607)      1: net: Try to restore a link 10:1:lo'
b'(00.003610)      1: net: Restoring link lo type 1'
b'(00.003964)      1: net: \tRunning ip addr restore'
b'Error: ipv4: Address already assigned.'
b'Error: ipv6: address already assigned.'
------------------------ ERROR OVER ------------------------
Running zdtm/static/socket-tcp-syn-sent.hook(--post-restore)
State                      Recv-Q                   Send-Q                                     Local Address:Port                                      Peer Address:Port                  Process                   
LISTEN                     0                        1                                                0.0.0.0:8880                                           0.0.0.0:*                                               
SYN-SENT                   0                        1                                              127.0.0.1:48163                                        127.0.0.1:8880                                            
Check TCP images
Send the 15 signal to  168
Wait for zdtm/static/socket-tcp-syn-sent(168) to die for 0.100000
Wait for zdtm/static/socket-tcp-syn-sent(168) to die for 0.200000
Wait for zdtm/static/socket-tcp-syn-sent(168) to die for 0.400000
Wait for zdtm/static/socket-tcp-syn-sent(168) to die for 0.800000
Running zdtm/static/socket-tcp-syn-sent.hook(--clean)
Removing dump/zdtm/static/socket-tcp-syn-sent/135
================== Test zdtm/static/socket-tcp-syn-sent PASS ===================

The test output below shows that the DROP rule exists after restore:

$ cat zdtm/static/socket-tcp-syn-sent.out
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8880
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8880
17:30:29.750:     5: PASS

rst0git avatar Sep 25 '25 17:09 rst0git

A friendly reminder that this issue had no activity for 30 days.

github-actions[bot] avatar Oct 26 '25 00:10 github-actions[bot]

I encountered this failure in zdtm/static/socket-tcp-syn-sent during the cleanup phase on Ubuntu 22.04 with AWS Kernel 6.8. It appears to be related to the known iptables-nft v1.8.7 rule canonicalization issue, where iptables fails to find the matching rule to delete, returning Bad rule.

I can reliably fix this by changing the specific deletion command (-D) to a chain flush:

snprintf(cmd, sizeof(cmd), "iptables -w -t filter -F INPUT"); My question is: Is it safe to flush the entire INPUT chain in this test context? Does the ZDTM harness or the namespace initialization populate the INPUT chain with any other essential rules that would be accidentally removed by a flush, or is the chain guaranteed to be owned solely by this test case?

DongSunchao avatar Dec 19 '25 10:12 DongSunchao

Here is my machine configuration:

ubuntu@ip-172-31-92-244:~/criu$ uname -a
Linux ip-172-31-92-244 6.8.0-1040-aws #42~22.04.1-Ubuntu SMP Wed Sep 24 10:26:57 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
ubuntu@ip-172-31-92-244:~/criu$ iptables --version
iptables v1.8.7 (nf_tables)

And I think the file socket-tcp-closed.c has same problem which will cause test fail. Maybe we can use the command(-D) to fix this bug: snprintf(cmd, sizeof(cmd), "iptables -w -t filter -F INPUT"); I'd appreciate it if you can give me any help :)

DongSunchao avatar Dec 19 '25 11:12 DongSunchao