The day my ping took countermeasures The article describes a technical anomaly where the author's `ping` command displayed the message "taking countermeasures" after their computer's clock was rolled backward due to an unsynchronized NTP daemon. The author investigates the source code and discovers that `ping` prints this message when it detects a negative round-trip time (RTT), resetting the erroneous measurement to zero milliseconds. The piece also explores how `ping` measures time, noting that modern Linux systems use the vdso for fast userspace time calls, which standard debugging tools like `strace` cannot trace. Once my holidays had passed, I found myself reluctantly reemerging into the world of the living. I powered on a corporate laptop, scared to check on my email inbox. However, before turning on the browser, obviously, I had to run a ping. Debugging the network is a mandatory first step after a boot, right? As expected, the network was perfectly healthy but what caught me off guard was this message: I was not expecting ping to take countermeasures that early on in a day. Gosh, I wasn't expecting any countermeasures that Monday Once I got over the initial confusion, I took a deep breath and collected my thoughts. You don't have to be Sherlock Holmes to figure out what has happened. I'm really fast - I started ping before the system NTP daemon synchronized the time. In my case, the computer clock was rolled backward, confusing ping. While this doesn't happen too often, a computer clock can be freely adjusted either forward or backward. However, it's pretty rare for a regular network utility, like ping, to try to manage a situation like this. It's even less common to call it "taking countermeasures". I would totally expect ping to just print a nonsensical time value and move on without hesitation. Ping developers clearly put some thought into that. I wondered how far they went. Did they handle clock changes in both directions? Are the bad measurements excluded from the final statistics? How do they test the software? I can't just walk past ping "taking countermeasures" on me. Now I have to understand what ping did and why. An investigation like this starts with a quick glance at the source code: P I N G . C Using the InterNet Control Message Protocol ICMP "ECHO" facility, measure round-trip-delays and packet loss across network paths. Author - Mike Muuss U. S. Army Ballistic Research Laboratory December, 1983 Ping goes back a long way. It was originally written by Mike Muuss https://en.wikipedia.org/wiki/Mike Muuss while at the U. S. Army Ballistic Research Laboratory, in 1983, before I was born. The code we're looking for is under iputils/ping/ping common.c https://github.com/iputils/iputils/blob/ee0a515e74b8d39fbe9b68f3309f0cb2586ccdd4/ping/ping common.c L746 gather statistics function: The code is straightforward: the message in question is printed when the measured RTT https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/ is negative. In this case ping resets the latency measurement to zero. Here you are: "taking countermeasures" is nothing more than just marking an erroneous measurement as if it was 0ms. But what precisely does ping measure? Is it the wall clock? The man page https://man7.org/linux/man-pages/man8/ping.8.html comes to the rescue. Ping has two modes. The "old", -U mode, in which it uses the wall clock. This mode is less accurate has more jitter . It calls gettimeofday before sending and after receiving the packet. The "new", default, mode in which it uses "network time". It calls gettimeofday before sending, and gets the receive timestamp from a more accurate SO TIMESTAMP CMSG. More on this later. Tracing gettimeofday is hard Let's start with a good old strace: bash $ strace -e trace=gettimeofday,time,clock gettime -f ping -n -c1 1.1 /dev/null ... nil ... It doesn't show any calls to gettimeofday . What is going on? On modern Linux some syscalls are not true syscalls. Instead of jumping to the kernel space, which is slow, they remain in userspace and go to a special code page provided by the host kernel. This code page is called vdso . It's visible as a .so library to the program: bash $ ldd which ping | grep vds linux-vdso.so.1 0x00007ffff47f9000 Calls to the vdso region are not syscalls, they remain in userspace and are super fast, but classic strace can't see them. For debugging it would be nice to turn off vdso and fall back to classic slow syscalls. It's easier said than done. There is no way to prevent loading of the vdso . However there are two ways to convince a loaded program not to use it. The first technique is about fooling glibc into thinking the vdso is not loaded. This case must be handled for compatibility with ancient Linux. When bootstrapping in a freshly run process, glibc inspects the Auxiliary Vector https://www.gnu.org/software/libc/manual/html node/Auxiliary-Vector.html provided by ELF loader. One of the parameters has the location of the vdso pointer, the man page https://man7.org/linux/man-pages/man7/vdso.7.html gives this example: void vdso = uintptr t getauxval AT SYSINFO EHDR ; A technique proposed on Stack Overflow https://stackoverflow.com/a/63811017 works like that: let's hook on a program before execve exits and overwrite the Auxiliary Vector AT SYSINFO EHDR parameter. Here's the novdso.c https://github.com/danteu/novdso/blob/master/novdso.c code. However, the linked code doesn't quite work for me one too many kill SIGSTOP , and has one bigger, fundamental flaw. To hook on execve it uses ptrace therefore doesn't work under our strace bash $ strace -f ./novdso ping 1.1 -c1 -n ... pid 69316 ptrace PTRACE TRACEME = -1 EPERM Operation not permitted While this technique of rewriting AT SYSINFO EHDR is pretty cool, it won't work for us. I wonder if there is another way of doing that, but without ptrace. Maybe with some BPF? But that is another story. A second technique is to use LD PRELOAD and preload a trivial library overloading the functions in question, and forcing them to go to slow real syscalls. This works fine: bash $ cat vdso override.c include