schweikert / fping

High performance ping tool

Home Page:https://fping.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unprivileged mode no longer works

sfan5 opened this issue · comments

commented

This is inside an systemd-nspawn container running Alpine Linux edge (aarch64). ping_group_range is configured on the host.
Did an update yesterday and it no longer works, I think the last working version was 5.0.

strace output attached: You can see it receives responses but seems to ignore them.

localhost:/# fping --version
fping: Version 5.1
localhost:/# strace fping 8.8.8.8
execve("/usr/sbin/fping", ["fping", "8.8.8.8"], 0xffffeee5ef58 /* 19 vars */) = 0
set_tid_address(0xffffac2f4230)         = 618
brk(NULL)                               = 0xaaaae0952000
brk(0xaaaae0954000)                     = 0xaaaae0954000
mmap(0xaaaae0952000, 4096, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xaaaae0952000
mprotect(0xaaaac9ae9000, 4096, PROT_READ) = 0
geteuid()                               = 0
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = -1 EPERM (Operation not permitted)
socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP) = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0
socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) = -1 EPERM (Operation not permitted)
socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6) = 4
fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0
getuid()                                = 0
getpid()                                = 618
getuid()                                = 0
setsockopt(3, SOL_SOCKET, SO_TIMESTAMPNS_OLD, [1], 4) = 0
setsockopt(4, SOL_SOCKET, SO_TIMESTAMPNS_OLD, [1], 4) = 0
rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=0xaaaac9ad2db4, sa_mask=[INT QUIT], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0xffffac294de8}, NULL, 8) = 0
rt_sigaction(SIGINT, {sa_handler=0xaaaac9ad2db4, sa_mask=[INT QUIT], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0xffffac294de8}, NULL, 8) = 0
mmap(NULL, 1048580, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xffffac147000
sendto(3, "\10\0\365\225\2j\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 64, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, 16) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=500001000}, {sigmask=NULL, sigsetsize=8}) = 1 (in [3], left {tv_sec=0, tv_nsec=482443459})
recvmsg(3, {msg_name={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, msg_namelen=128 => 16, msg_iov=[{iov_base="\0\0E\326\272)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CTRUNC}, MSG_TRUNC) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=0}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=480241000}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
sendto(3, "\10\0\365\224\2j\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 64, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, 16) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=750001000}, {sigmask=NULL, sigsetsize=8}) = 1 (in [3], left {tv_sec=0, tv_nsec=732169869})
recvmsg(3, {msg_name={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, msg_namelen=128 => 16, msg_iov=[{iov_base="\0\0E\325\272)\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CTRUNC}, MSG_TRUNC) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=0}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=730211000}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
sendto(3, "\10\0\365\223\2j\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 64, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, 16) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=1, tv_nsec=125000000}, {sigmask=NULL, sigsetsize=8}) = 1 (in [3], left {tv_sec=1, tv_nsec=107416000})
recvmsg(3, {msg_name={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, msg_namelen=128 => 16, msg_iov=[{iov_base="\0\0E\324\272)\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CTRUNC}, MSG_TRUNC) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=0}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
pselect6(5, [3 4], NULL, NULL, {tv_sec=1, tv_nsec=105566000}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
sendto(3, "\10\0\365\222\2j\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 64, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, 16) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=1, tv_nsec=687500000}, {sigmask=NULL, sigsetsize=8}) = 1 (in [3], left {tv_sec=1, tv_nsec=670026544})
recvmsg(3, {msg_name={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, msg_namelen=128 => 16, msg_iov=[{iov_base="\0\0E\323\272)\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CTRUNC}, MSG_TRUNC) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=0}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
pselect6(5, [3 4], NULL, NULL, {tv_sec=1, tv_nsec=668183000}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
writev(1, [{iov_base="8.8.8.8 is unreachable", iov_len=22}, {iov_base="\n", iov_len=1}], 28.8.8.8 is unreachable
) = 23
exit_group(1)                           = ?
+++ exited with 1 +++

It has euid 0 (root), but not the required capability (CAP_NET_RAW) -- socket() returning EPERM -- so it can't use ICMP. Give it CAP_NET_RAW and it will work for IPv4. You might need CAP_NET_ADMIN for IPv6 if you're doing link-local pings, though, since that requires one to bind to a specific interface to work.

Why this regressed, I don't know. Maybe an strace of the working version (with the same base operating system image, please) ?

commented
localhost:~/fping-5.0# ./src/fping --version
./src/fping: Version 5.0
localhost:~/fping-5.0# strace ./src/fping 8.8.8.8
execve("./src/fping", ["./src/fping", "8.8.8.8"], 0xffffef313ff8 /* 18 vars */) = 0
set_tid_address(0xffffbb817230)         = 254
brk(NULL)                               = 0xaaaad053c000
brk(0xaaaad053e000)                     = 0xaaaad053e000
mmap(0xaaaad053c000, 4096, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xaaaad053c000
mprotect(0xaaaaaedc9000, 4096, PROT_READ) = 0
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = -1 EPERM (Operation not permitted)
socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP) = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0
socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) = -1 EPERM (Operation not permitted)
socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6) = 4
fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0
getuid()                                = 0
getpid()                                = 254
setsockopt(3, SOL_SOCKET, SO_TIMESTAMPNS_OLD, [1], 4) = 0
setsockopt(4, SOL_SOCKET, SO_TIMESTAMPNS_OLD, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(47842), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
bind(4, {sa_family=AF_INET6, sin6_port=htons(0), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, 28) = 0
getsockname(4, {sa_family=AF_INET6, sin6_port=htons(47843), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, [28]) = 0
rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=0xaaaaaedb2dc0, sa_mask=[INT QUIT], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0xffffbb7b7de8}, NULL, 8) = 0
rt_sigaction(SIGINT, {sa_handler=0xaaaaaedb2dc0, sa_mask=[INT QUIT], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0xffffbb7b7de8}, NULL, 8) = 0
mmap(NULL, 1048580, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xffffbb66a000
sendto(3, "\10\0=\35\272\342\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 64, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, 16) = 64
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=500001000}, {sigmask=NULL, sigsetsize=8}) = 1 (in [3], left {tv_sec=0, tv_nsec=482108226})
recvmsg(3, {msg_name={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("8.8.8.8")}, msg_namelen=128 => 16, msg_iov=[{iov_base="\0\0E\35\272\342\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CTRUNC}, MSG_TRUNC) = 64
writev(1, [{iov_base="8.8.8.8 is alive", iov_len=16}, {iov_base="\n", iov_len=1}], 28.8.8.8 is alive
) = 17
pselect6(5, [3 4], NULL, NULL, {tv_sec=0, tv_nsec=0}, {sigmask=NULL, sigsetsize=8}) = 0 (Timeout)
exit_group(0)                           = ?
+++ exited with 0 +++

Eh, it notices it can't do ICMP, switches to UDP mode, sends packets and receives the reply. But from the strace, it looks like it doesn't recognize the reply as the target being alive.

I feared the regression was related to the changes I submitted to drop privileges later (required for IPv6 link-local to work on Linux), but it doesn't look related to that change at all. Instead, it looks like some logic got broken in 5.1.

I will leave the debugging of the other changes to someone who knows the code better...

This seems caused by commit 31f76f6