Repository: checkpoint-restore/criu (C)

Issue:
Fix sockopts handling for 6.16+ kernels
On 6.16+ kernels the following tests are failing (https://github.com/checkpoint-restore/criu/pull/2652/checks?check_run_id=47767998459):
```
################### 78 TEST(S) FAILED (TOTAL 479/SKIPPED 41) ###################
 * zdtm/static/bridge(uns)
 * zdtm/static/net_lock_socket_iptables(h)
 * zdtm/static/net_lock_socket_iptables6(h)
 * zdtm/static/net_lock_socket_nftables(h)
 * zdtm/static/net_lock_socket_nftables6(h)
 * zdtm/static/packet_sock(uns)
 * zdtm/static/packet_sock_mmap(h)
 * zdtm/static/packet_sock_spkt(uns)
 * zdtm/static/sk-freebind(ns)
 * zdtm/static/sk-freebind-false(uns)
 * zdtm/static/sock_filter00(ns)
 * zdtm/static/sock_filter01(uns)
 * zdtm/static/sock_ip_opts00(ns)
 * zdtm/static/sock_ip_opts01(ns)
 * zdtm/static/sock_opts00(ns)
 * zdtm/static/sock_opts01(uns)
 * zdtm/static/sock_opts02(ns)
 * zdtm/static/sock_tcp_opts00(ns)
 * zdtm/static/sock_tcp_opts01(uns)
 * zdtm/static/socket-dump-tcp-close(uns)
 * zdtm/static/socket-linger(ns)
 * zdtm/static/socket-raw(ns)
 * zdtm/static/socket-tcp(h)
 * zdtm/static/socket-tcp-close0(uns)
 * zdtm/static/socket-tcp-close-wait(h)
 * zdtm/static/socket-tcp-close2(ns)
 * zdtm/static/socket-tcp-close1(uns)
 * zdtm/static/socket-tcp-closed-last-ack(uns)
 * zdtm/static/socket-tcp-closed(uns)
 * zdtm/static/socket-tcp-fin-wait1(h)
 * zdtm/static/socket-tcp-closing(uns)
 * zdtm/static/socket-tcp-fin-wait2(h)
 * zdtm/static/socket-tcp-ipt-nfconntrack(h)
 * zdtm/static/socket-tcp-keepalive(h)
 * zdtm/static/socket-tcp-listen(uns)
 * zdtm/static/socket-tcp-last-ack(uns)
 * zdtm/static/socket-tcp-nft-nfconntrack(h)
 * zdtm/static/socket-tcp-local(ns)
 * zdtm/static/socket-tcp-reuseport(h)
 * zdtm/static/socket-tcp-reseted(ns)
 * zdtm/static/socket-tcp-skip-in-flight(uns)
 * zdtm/static/socket-tcp-unconn(h)
 * zdtm/static/socket-tcp-syn-sent(uns)
 * zdtm/static/socket-tcp4v6(h)
 * zdtm/static/socket-tcp4v6-close-wait(ns)
 * zdtm/static/socket-tcp4v6-closed(uns)
 * zdtm/static/socket-tcp4v6-fin-wait1(ns)
 * zdtm/static/socket-tcp4v6-fin-wait2(h)
 * zdtm/static/socket-tcp4v6-closing(h)
 * zdtm/static/socket-tcp4v6-last-ack(ns)
 * zdtm/static/socket-tcp4v6-local(h)
 * zdtm/static/socket-tcp6-close-wait(ns)
 * zdtm/static/socket-tcp6(h)
 * zdtm/static/socket-tcp6-closed(uns)
 * zdtm/static/socket-tcp6-fin-wait1(ns)
 * zdtm/static/socket-tcp6-fin-wait2(ns)
 * zdtm/static/socket-tcp6-closing(h)
 * zdtm/static/socket-tcp6-last-ack(h)
 * zdtm/static/socket-tcp6-local(ns)
 * zdtm/static/socket-tcp6-unconn(uns)
 * zdtm/static/socket-tcpbuf(h)
 * zdtm/static/socket-tcpbuf-local(uns)
 * zdtm/static/socket-tcpbuf6(h)
 * zdtm/static/socket6_icmp(uns)
 * zdtm/static/socket-tcpbuf6-local(uns)
 * zdtm/static/socket6_udp(ns)
 * zdtm/static/socket_aio(uns)
 * zdtm/static/socket_icmp(uns)
 * zdtm/static/socket_listen(h)
 * zdtm/static/socket_listen4v6(ns)
 * zdtm/static/socket_listen6(uns)
 * zdtm/static/socket_udp(ns)
 * zdtm/static/socket_udp-broadcast(h)
 * zdtm/static/socket_udp_shutdown(h)
 * zdtm/static/socket_udplite(ns)
 * zdtm/static/unbound_sock(h)
 * zdtm/transition/socket-tcp(h)
 * zdtm/transition/socket-tcp6(h)
##################################### FAIL #####################################
```

with
```
b'(00.004834) sockets: Searching for socket 0x99985 family 2'
b"(00.004847) Error (criu/sockets.c:640): sockets: Can't get 1:16 opt: Operation not supported"
b"(00.004855) Error (criu/sockets.c:640): sockets: Can't get 1:34 opt: Operation not supported"
```

These errors are from:
https://github.com/checkpoint-restore/criu/blob/116e56ba46382c05066d33a8bbadcc495dbdb644/criu/sockets.c#L640
https://github.com/checkpoint-restore/criu/blob/116e56ba46382c05066d33a8bbadcc495dbdb644/criu/sockets.c#L691
https://github.com/checkpoint-restore/criu/blob/116e56ba46382c05066d33a8bbadcc495dbdb644/criu/sockets.c#L695

Reproducer:
```
./test/zdtm.py run -t zdtm/static/sock_opts00 -f ns
```

It is because of this commit https://github.com/torvalds/linux/commit/7d8d93fdde50b86bbbf46a203c368ed320e729ab changes UAPI in that way so we can't do `getsockopt` on `SO_PASSCRED` and `SO_PASSSEC` blindly. We need to have an additional check based on socket family.


Discussion: Hello!
I'm new to this project.
May I take this bug for investigation as my very first issue, please?
Thanks in advance!
Hi, 
I have been working on this issue for a few hours and have identified a core problem. The **zdtm/static/sock_opts00(ns)** test uses a  `PF_INET` socket to set `SO_PASSCRED` and `SO_PASSSEC`.
However, these options have been restricted to `AF_{UNIX,NETLINK,BLUETOOTH}` since 6.16. This is causing the test to fail. What is the intend fix here? Should we:
1.Modify the test to skip these options for `PF_INET` sockets?
2.Change the test to use an `AF_{UNIX,NETLINK,BLUETOOTH}` sockets instead?
Your guidance would be appreciated.
> Modify the test to skip these options for PF_INET sockets

@DongSunchao This sounds reasonable. Can you open a draft PR with this change and a comment explaining the problem? 

https://github.com/checkpoint-restore/criu/pull/2707 was a good starting point but it might be good to use the approach Alex suggested: 
> We need to have an additional check based on socket family.
> I'm new to this project. May I take this bug for investigation as my very first issue, please?

@ansavin Your are very welcome to contribute. The following file provides more information on how to contribute to CRIU:
https://github.com/checkpoint-restore/criu/blob/criu-dev/CONTRIBUTING.md
> > Modify the test to skip these options for PF_INET sockets
> 
> [@DongSunchao](https://github.com/DongSunchao) This sounds reasonable. Can you open a draft PR with this change and a comment explaining the problem?
> 
> [#2707](https://github.com/checkpoint-restore/criu/pull/2707) was a good starting point but it might be good to use the approach Alex suggested:
> 
> > We need to have an additional check based on socket family.

Hi, 
I believe I have fixed this bug after running a few tests.
I'm excited about making my first open-source contribution here. I'd really appreciate it if you could review my code and provide any feedback.
I am looking for to learning from your suggestions.
Also noticed with the podman upstream tests on openSUSE Tumbleweed:

criu-4.1-3.1
kernel-default-6.16.0-1.1

To reproduce:
https://openqa.opensuse.org/tests/5240079/file/podman-commands.txt

```
# [12:19:09.089081072] # /usr/bin/podman --root /tmp/podman_bats.lEsaFF/root --runroot /tmp/podman_bats.lEsaFF/runroot --tmpdir /tmp/podman_bats.lEsaFF/tmpdir --events-backend file container checkpoint --ignore-rootfs --export=/tmp/podman_bats.lEsaFF/c-t655-3hd3kpwa.tar.gz c-t655-3hd3kpwa
# [12:19:09.244304687] time="2025-08-13T12:19:09-04:00" level=warning msg="--- Quoting \"/tmp/podman_bats.lEsaFF/root/overlay-containers/fe391008ecace7c8aaebbd95d79e4ad7a4e0d8f15a9a9c49e4329151063ad5c9/userdata/dump.log\""
# time="2025-08-13T12:19:09-04:00" level=warning msg="779:(00.024796) Dumping path for 0 fd via self 15 [/dev/null]"
# time="2025-08-13T12:19:09-04:00" level=warning msg="780:(00.024917) 647928 fdinfo 1: pos:                0 flags:           100002/0"
# time="2025-08-13T12:19:09-04:00" level=warning msg="781:(00.024969) 647928 fdinfo 2: pos:                0 flags:           100002/0"
# time="2025-08-13T12:19:09-04:00" level=warning msg="782:(00.025015) 647928 fdinfo 3: pos:                0 flags:                2/0"
# time="2025-08-13T12:19:09-04:00" level=warning msg="783:(00.025042) sockets: Searching for socket 0x20cac2 family 10"
# time="2025-08-13T12:19:09-04:00" level=warning msg="784:(00.025087) Error (criu/sockets.c:628): sockets: Can't get 1:16 opt: Operation not supported"
# time="2025-08-13T12:19:09-04:00" level=warning msg="785:(00.025104) Error (criu/sockets.c:628): sockets: Can't get 1:34 opt: Operation not supported"
# time="2025-08-13T12:19:09-04:00" level=warning msg="786:(00.025125) sockets: No filter for socket"
# time="2025-08-13T12:19:09-04:00" level=warning msg="787:(00.025139) ----------------------------------------"
# time="2025-08-13T12:19:09-04:00" level=warning msg="788:(00.025174) Error (criu/cr-dump.c:1681): Dump files (pid: 647928) failed with -1"
# time="2025-08-13T12:19:09-04:00" level=warning msg=...
# time="2025-08-13T12:19:09-04:00" level=warning msg="800:(00.026029) \tRPC"
# time="2025-08-13T12:19:09-04:00" level=warning msg="801:(00.032488) Unfreezing tasks into 1"
# time="2025-08-13T12:19:09-04:00" level=warning msg="802:(00.032499) \tUnseizing 647915 into 1"
# time="2025-08-13T12:19:09-04:00" level=warning msg="803:(00.032511) \tUnseizing 647928 into 1"
# time="2025-08-13T12:19:09-04:00" level=warning msg="804:(00.032520) \tUnseizing 647972 into 1"
# time="2025-08-13T12:19:09-04:00" level=warning msg="805:(00.032635) Error (criu/cr-dump.c:2111): Dumping FAILED."
# time="2025-08-13T12:19:09-04:00" level=warning msg=---
# time="2025-08-13T12:19:09-04:00" level=error msg="criu failed: type DUMP errno 0"
# Error: `/usr/bin/runc checkpoint --image-path /tmp/podman_bats.lEsaFF/root/overlay-containers/fe391008ecace7c8aaebbd95d79e4ad7a4e0d8f15a9a9c49e4329151063ad5c9/userdata/checkpoint --work-path /tmp/podman_bats.lEsaFF/root/overlay-containers/fe391008ecace7c8aaebbd95d79e4ad7a4e0d8f15a9a9c49e4329151063ad5c9/userdata fe391008ecace7c8aaebbd95d79e4ad7a4e0d8f15a9a9c49e4329151063ad5c9` failed: exit status 1
```


Issue still seen on criu 4.1.1.

https://openqa.opensuse.org/tests/5244517/logfile?filename=podman-bats-root-local.tap.txt



Fix (patch):
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index c3e7c879a7..6c81d3edd7 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -25,7 +25,7 @@ struct socket_desc {
 };
 
 extern int dump_socket(struct fd_parms *p, int lfd, FdinfoEntry *);
-extern int dump_socket_opts(int sk, SkOptsEntry *soe);
+extern int dump_socket_opts(int sk, int family, SkOptsEntry *soe);
 extern int restore_socket_opts(int sk, SkOptsEntry *soe);
 extern int sk_setbufs(int sk, uint32_t *bufs);
 extern void release_skopts(SkOptsEntry *);
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
index 6e0acf2ce3..422edc6567 100644
--- a/criu/sk-inet.c
+++ b/criu/sk-inet.c
@@ -581,7 +581,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
 	if (dump_ip_opts(lfd, family, type, proto, &ipopts))
 		goto err;
 
-	if (dump_socket_opts(lfd, &skopts))
+	if (dump_socket_opts(lfd, family, &skopts))
 		goto err;
 
 	pr_info("Dumping inet socket at %d\n", p->fd);
diff --git a/criu/sk-netlink.c b/criu/sk-netlink.c
index a219b69be1..dc2baa1b80 100644
--- a/criu/sk-netlink.c
+++ b/criu/sk-netlink.c
@@ -165,7 +165,7 @@ static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
 	ne.fown = (FownEntry *)&p->fown;
 	ne.opts = &skopts;
 
-	if (dump_socket_opts(lfd, &skopts))
+	if (dump_socket_opts(lfd, AF_NETLINK, &skopts))
 		goto err;
 
 	fe.type = FD_TYPES__NETLINKSK;
diff --git a/criu/sk-packet.c b/criu/sk-packet.c
index 1d2e23522a..6530bff580 100644
--- a/criu/sk-packet.c
+++ b/criu/sk-packet.c
@@ -173,7 +173,7 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
 	psk.fown = (FownEntry *)&p->fown;
 	psk.opts = &skopts;
 
-	if (dump_socket_opts(lfd, &skopts))
+	if (dump_socket_opts(lfd, AF_PACKET, &skopts))
 		return -1;
 
 	psk.protocol = sd->proto;
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 70ca16be4a..6145fe7347 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -527,7 +527,7 @@ static int dump_one_unix_fd(int lfd, uint32_t id, const struct fd_parms *p)
 			}
 	}
 dump:
-	if (dump_socket_opts(lfd, skopts))
+	if (dump_socket_opts(lfd, AF_UNIX, skopts))
 		goto err;
 
 	pr_info("Dumping unix socket at %d\n", p->fd);
diff --git a/criu/sockets.c b/criu/sockets.c
index 0affccad02..e4adae03cd 100644
--- a/criu/sockets.c
+++ b/criu/sockets.c
@@ -649,7 +649,7 @@ int do_dump_opt(int sk, int level, int name, void *val, int len)
 	return 0;
 }
 
-int dump_socket_opts(int sk, SkOptsEntry *soe)
+int dump_socket_opts(int sk, int family, SkOptsEntry *soe)
 {
 	int ret = 0, val;
 	struct timeval tv;
@@ -688,13 +688,15 @@ int dump_socket_opts(int sk, SkOptsEntry *soe)
 	soe->so_reuseport = val ? true : false;
 	soe->has_so_reuseport = true;
 
-	ret |= dump_opt(sk, SOL_SOCKET, SO_PASSCRED, &val);
-	soe->has_so_passcred = true;
-	soe->so_passcred = val ? true : false;
+	if (family == AF_UNIX || family == AF_NETLINK) {
+		ret |= dump_opt(sk, SOL_SOCKET, SO_PASSCRED, &val);
+		soe->has_so_passcred = true;
+		soe->so_passcred = val ? true : false;
 
-	ret |= dump_opt(sk, SOL_SOCKET, SO_PASSSEC, &val);
-	soe->has_so_passsec = true;
-	soe->so_passsec = val ? true : false;
+		ret |= dump_opt(sk, SOL_SOCKET, SO_PASSSEC, &val);
+		soe->has_so_passsec = true;
+		soe->so_passsec = val ? true : false;
+	}
 
 	ret |= dump_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val);
 	soe->has_so_dontroute = true;