Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@rrobgill
Copy link
Contributor

@rrobgill rrobgill commented Jul 15, 2025

What does this PR aim to accomplish?:

Avoid the buffer overflow when repying to ipv6 ntp packets.

This was observed to cause crashes on 32 bit systems #2567.

How does this PR accomplish the above?:

Use SOCKADDR_STORAGE struct to hold address (guaranteed sufficient for ipv4 or ipv6 address)

Uses pointer casting to avoid potential buffer overflow copying socket addresses into socket structures.

Together this should be safer against buffer overflows and alignment issues on 32 bit systems

Adds more detailed ntp debug logging.

Link documentation PRs if any are needed to support this PR:

N/A


By submitting this pull request, I confirm the following:

  1. I have read and understood the contributors guide, as well as this entire template. I understand which branch to base my commits and Pull Requests against.
  2. I have commented my proposed changes within the code and I have tested my changes.
  3. I am willing to help maintain this change if there are issues with it later.
  4. It is compatible with the EUPL 1.2 license
  5. I have squashed any insignificant commits. (git rebase)
  6. I have checked that another pull request for this purpose does not exist.
  7. I have considered, and confirmed that this submission will be valuable to others.
  8. I accept that this submission may not be used, and the pull request closed at the will of the maintainer.
  9. I give this submission freely, and claim no ownership to its content.

  • I have read the above and my PR is ready for review. Check this box to confirm

@rrobgill rrobgill requested a review from a team as a code owner July 15, 2025 10:35
@rrobgill
Copy link
Contributor Author

Built and tested on x86-64 and arm-v6 (on a pi 2b - an ordeal I don't care to repeat). No crashes observed on IPv6 ntp packets, and responses generated as expected.

I don't have access to any other platforms for testing.

I wouldn't class this as WIP, but it would be reassuring if someone is able to (real world) test this on especially 386, but also risc.

@DL6ER
Copy link
Member

DL6ER commented Jul 15, 2025

I do have a RISCV board I can use for testing I could try to boot and see if it still runs. Do you have some CLI command or demo script that generates such packages you'd like to see it being tested against?

Edit: nvm, I should have read the issue you referenced, before replying here.

ntpd -p fd07::20a:cdff:fe32:d4b5

@yubiuser yubiuser linked an issue Jul 15, 2025 that may be closed by this pull request
@rrobgill
Copy link
Contributor Author

rrobgill commented Jul 15, 2025

There is a one-liner from https://seriot.ch/projects/tiny_ntp_client.html that doesn't rely on any ntp package being installed.

[ EDITED to quote as block code instead of plain text : These were originally broken by github's formatting as there are backticks in the commands ]

To test on localhost,
ipv6:
date -d@$((0x`printf c%47s|nc -6 -uw1 ::1 123|xxd -s40 -l4 -p`-64#23GDW0))
ipv4:
date -d@$((0x`printf c%47s|nc -uw1 127.0.0.1 123|xxd -s40 -l4 -p`-64#23GDW0))
image

If it gets a response it prints the time and date reported by the ntp server.

I was thinking something like this may be possible to add to the tests, a quick sanity check that the returned time is within 2 seconds either way of the sent time (it should be the same on localhost, but this allows for second rollover and a little extra padding.

Is Pi-hole able to sync its own time within the test environment to even be able to send a response?

@test "NTP IPv4" {
SEND=$(date +%Y%m%d%H%M%S)
RECV=$(date -d@$((0x`printf c%47s|nc -6 -uw1 ::1 123|xxd -s40 -l4 -p`-64#23GDW0)) +%Y%m%d%H%M%S)
DIFF="$(($RECV - SEND))"
[[ "$DIFF" -ge -2 && "$DIFF" -le 2 ]]
}

@test "NTP IPv4" {
SEND=$(date +%Y%m%d%H%M%S)
RECV=$(date -d@$((0x`printf c%47s|nc -4 -uw1 192.168.1.1 123|xxd -s40 -l4 -p`-64#23GDW0)) +%Y%m%d%H%M%S)
DIFF="$(($RECV - SEND))"
[[ "$DIFF" -ge -2 && "$DIFF" -le 2 ]]
}

@DL6ER
Copy link
Member

DL6ER commented Jul 16, 2025

printf c%47s|nc -6 -uw1 ::1 123

does not return anything for me on neither my v86_64 nor the riscv64 Pi-hole so the one-liner doesn't seem to work.

The ntpd -p <IPv6 address> command doesn't work either, so I guess it should have been ntpq -p ::1 but this always ends in a timeout:

$ ntpq -p
***Request timed out

Pi-hole's internal NTP checking tool seems to work just fine:

$ pihole-FTL ntp ::1

Using NTP server: ::1
........
Received 8/8 valid NTP replies from ::1
Time offset: 3.474099e-03 ms (excluded 1 outliers)
Round-trip delay: 1.201630e-01 ms (excluded 1 outliers)

Note that RISCV is also 64-bit but I nonetheless fired up my StarFive VisionFive 2 running RISCV Ubuntu

$ uname -a
Linux ubuntu 6.14.0-23-generic #23.1~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Jun 24 07:31:07 UTC riscv64 riscv64 riscv64 GNU/Linux
$ cat /proc/cpuinfo 
processor       : 0
hart            : 1
isa             : rv64imafdc_zicntr_zicsr_zifencei_zihpm_zba_zbb
mmu             : sv39
uarch           : sifive,u74-mc
mvendorid       : 0x489
marchid         : 0x8000000000000007
mimpid          : 0x4210427
hart isa        : rv64imafdc_zicntr_zicsr_zifencei_zihpm_zba_zbb

(repeated 4 times)

Wow, I forgot how slow this thing is. Comparable to a Raspberry Pi 2... Anyway, I'd be ready to run any test you have for me.

@rrobgill
Copy link
Contributor Author

rrobgill commented Jul 16, 2025

does not return anything for me on neither my v86_64 nor the riscv64 Pi-hole so the one-liner doesn't seem to work.

Sorry I hadn't notices but the one-liners got mangled by github's formatting, it clobbered the backticks.

#!/bin/bash
echo "IPv6 NTP"
date -d@$((0x`printf c%47s|nc -6 -uw1 ::1 123|xxd -s40 -l4 -p`-64#23GDW0))
echo "IPv4 NTP"
date -d@$((0x`printf c%47s|nc -uw1 127.0.0.1 123|xxd -s40 -l4 -p`-64#23GDW0))

If you could set debug ntp = true in pihole.toml, and issue the commands either in terminal or this script if it doesn't get mangled.

It was crashing armv6 on almost every IPv6 ntp packet, so if there are still problems on the other architectures (if there were any to begin with?) it should show up fairly quickly.

image image

Assuming that doesn't cause a crash, and the returned dates are sensible, the next step is to add that machine as a source to the ntp client of a system on your network, ideally chrony.

If you're running chrony, add a server directive for the ipv4 and ipv6 address to /etc/chrony/chrony.conf (noselect so your system's time won't be effected, and high polling so packets are arriving frequently).

server  192.168.1.123 noselect maxpoll -4 minpoll -4
server  fe80::4951 noselect maxpoll -4 minpoll -4

Then restart chrony
sudo systemctl restart chronyd

After some time check back on FTL log for crashes and get the client information from chronyc
sudo chronyc clients -v

@DL6ER
Copy link
Member

DL6ER commented Jul 16, 2025

Thank you. With

date -d@$((0x`printf c%47s|nc -6 -uw1 ::1 123|xxd -s40 -l4 -p`-64#23GDW0))

I don't see any crashes, also not on RISCV, but, as said, this is a 64 bit system so the crash may not actually be expected.

use pointer casting to avoid potential buffer overflow copying socket addresses into socket structures

use sockaddr_storage to ensure adress size and alignment across achitectures

add additional and ntp debug logging

check for address type rather than specified protocol

Signed-off-by: Rob Gill <[email protected]>
@DL6ER DL6ER merged commit 4c9c6b6 into pi-hole:development Jul 18, 2025
13 checks passed
@rrobgill rrobgill deleted the ntpfix branch July 21, 2025 20:41
@PromoFaux PromoFaux mentioned this pull request Oct 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IPv6 NTP Server crashes FTL

2 participants