Skip to content

Commit

Permalink
net: fix network unlock with iptables-nft
Browse files Browse the repository at this point in the history
When iptables-nft is used as backend for iptables, the rules for
network locking are translated into the following nft rules:

```
$ iptables-restore-translate -f lock.txt
add table ip filter
add chain ip filter CRIU
insert rule ip filter INPUT counter jump CRIU
insert rule ip filter OUTPUT counter jump CRIU
add rule ip filter CRIU mark 0xc114 counter accept
add rule ip filter CRIU counter drop
```

These rules create the following chains:

```
table ip filter { # handle 1
	chain CRIU { # handle 1
		meta mark 0x0000c114 counter packets 16 bytes 890 accept # handle 6
		counter packets 1 bytes 60 drop # handle 7
		meta mark 0x0000c114 counter packets 0 bytes 0 accept # handle 8
		counter packets 0 bytes 0 drop # handle 9
	}

	chain INPUT { # handle 2
		type filter hook input priority filter; policy accept;
		counter packets 8 bytes 445 jump CRIU # handle 3
		counter packets 0 bytes 0 jump CRIU # handle 10
	}

	chain OUTPUT { # handle 4
		type filter hook output priority filter; policy accept;
		counter packets 9 bytes 505 jump CRIU # handle 5
		counter packets 0 bytes 0 jump CRIU # handle 11
	}
}
```

In order to delete the CRIU chain, we need to first delete all four
jump targets. Otherwise, `-X CRIU` would fail with the following error:

iptables-restore v1.8.10 (nf_tables):
line 5: CHAIN_DEL failed (Resource busy): chain CRIU

Reported-by: Andrei Vagin <[email protected]>
Signed-off-by: Radostin Stoyanov <[email protected]>
  • Loading branch information
rst0git authored and avagin committed Jan 17, 2024
1 parent cda1c5c commit 0416d81
Showing 1 changed file with 42 additions and 8 deletions.
50 changes: 42 additions & 8 deletions criu/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -3178,19 +3178,53 @@ static inline int nftables_network_unlock(void)
#endif
}

static int iptables_has_criu_jump_target(void)
{
int fd, ret;
char *argv[4] = { "sh", "-c", "iptables -C INPUT -j CRIU", NULL };

fd = open("/dev/null", O_RDWR);
if (fd < 0) {
fd = -1;
pr_perror("failed to open /dev/null, using log fd");
}

ret = cr_system(fd, fd, fd, "sh", argv, CRS_CAN_FAIL);
close_safe(&fd);
return ret;
}

static int iptables_network_unlock_internal(void)
{
char conf[] = "*filter\n"
":CRIU - [0:0]\n"
"-D INPUT -j CRIU\n"
"-D OUTPUT -j CRIU\n"
"-X CRIU\n"
"COMMIT\n";
char delete_jump_targets[] = "*filter\n"
":CRIU - [0:0]\n"
"-D INPUT -j CRIU\n"
"-D OUTPUT -j CRIU\n"
"COMMIT\n";

char delete_criu_chain[] = "*filter\n"
":CRIU - [0:0]\n"
"-X CRIU\n"
"COMMIT\n";

int ret = 0;

ret |= iptables_restore(false, conf, sizeof(conf) - 1);
ret |= iptables_restore(false, delete_jump_targets, sizeof(delete_jump_targets) - 1);
if (kdat.ipv6)
ret |= iptables_restore(true, conf, sizeof(conf) - 1);
ret |= iptables_restore(true, delete_jump_targets, sizeof(delete_jump_targets) - 1);

/* For compatibility with iptables-nft backend, we need to make sure that all jump
* targets have been removed before deleting the CRIU chain.
*/
if (!iptables_has_criu_jump_target()) {
ret |= iptables_restore(false, delete_jump_targets, sizeof(delete_jump_targets) - 1);
if (kdat.ipv6)
ret |= iptables_restore(true, delete_jump_targets, sizeof(delete_jump_targets) - 1);
}

ret |= iptables_restore(false, delete_criu_chain, sizeof(delete_criu_chain) - 1);
if (kdat.ipv6)
ret |= iptables_restore(true, delete_criu_chain, sizeof(delete_criu_chain) - 1);

return ret;
}
Expand Down

0 comments on commit 0416d81

Please sign in to comment.