Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:chrony
User: [email protected]
Usertags: pu

Hi,

[ Reason ]
A security fix introduced in Linux 6.15¹, and backported to Linux stable
series down to version 5.10, prevents chronyd from starting if
it is set up to use a PHC refclock configured with the 'extpps' option.

[ Impact ]
chronyd would fail to start when configured as aforementioned on a system
featuring a kernel containing that security fix.

More precisely, chronyd would output: "Fatal error : Could not enable external 
PHC timestamping"

[ Tests ]
After some required adjustments to 'upstream-simulation-test-suite'
autopkgest, all the tests shipped by chrony pass.

The proposed fix has also been successfully tested by the person who reported
the bug. No regression has been observed.

[ Risks ]
As mentioned above, the proposed update is well tested so I would say
that the risk of regression should be quite low.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
- The refclock_phc_open-device-for-writing-with-extpps-option.patch file
  is a backport of upstream patch (already available in chrony 4.8) to
  open the PHC reference clock with the O_RDWR flag when enabling the
  extpps option as recently required by the kernel.

- The second change concerns the 'upstream-simulation-test-suite'
  autopkgtest that fails notably due to the patched open() call.

[ Other info ]
I will be filing an issue for bookworm to fix the same problem.

Cheers,
Vincent

¹ 
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=97529630d85f910f4e6dfc615f1d111ada9448e3
diff -Nru chrony-4.6.1/debian/changelog chrony-4.6.1/debian/changelog
--- chrony-4.6.1/debian/changelog       2025-06-03 17:16:37.000000000 +0200
+++ chrony-4.6.1/debian/changelog       2026-02-16 17:34:12.000000000 +0100
@@ -1,3 +1,14 @@
+chrony (4.6.1-3+deb13u1) trixie; urgency=medium
+
+  * debian/patches/:
+    - Add refclock_phc_open-device-for-writing-with-extpps-option.patch.
+    Thanks to Jan Lübbe for the report. (Closes: #1127659)
+
+  * debian/test/upstream-simulation-test-suite:
+    - Prevent simulation test failures.
+
+ -- Vincent Blut <[email protected]>  Mon, 16 Feb 2026 17:34:12 +0100
+
 chrony (4.6.1-3) unstable; urgency=medium
 
   * debian/patches/:
diff -Nru 
chrony-4.6.1/debian/patches/refclock_phc_open-device-for-writing-with-extpps-option.patch
 
chrony-4.6.1/debian/patches/refclock_phc_open-device-for-writing-with-extpps-option.patch
--- 
chrony-4.6.1/debian/patches/refclock_phc_open-device-for-writing-with-extpps-option.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
chrony-4.6.1/debian/patches/refclock_phc_open-device-for-writing-with-extpps-option.patch
   2026-02-16 17:34:12.000000000 +0100
@@ -0,0 +1,104 @@
+Description: Open PHC device for writing with extpps option
+ In version 6.15 the Linux kernel started checking write access on the
+ PHC file descriptor in the PTP_PIN_SETFUNC and PTP_EXTTS_REQUEST ioctls.
+ chronyd opened the PHC device as readonly, which caused the PHC refclock
+ driver configured with the extpps option to fail with the
+ "Could not enable external PHC timestamping" error message.
+
+ To ensure compatibility with new kernel versions, add flags to the
+ SYS_Linux_OpenPHC() function and open the device with the O_RDWR flag
+ when the extpps option is enabled.
+Origin: backport, 
https://gitlab.com/chrony/chrony/-/commit/f78e4681eff71d941fab3be5ee406d920a155a20
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1127659
+Last-Update: 2026-02-12
+---
+Index: chrony/ntp_io_linux.c
+===================================================================
+--- chrony.orig/ntp_io_linux.c
++++ chrony/ntp_io_linux.c
+@@ -220,7 +220,7 @@ add_interface(CNF_HwTsInterface *conf_if
+ 
+   SCK_CloseSocket(sock_fd);
+ 
+-  phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
++  phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index, O_RDONLY);
+   if (phc_fd < 0)
+     return 0;
+ 
+Index: chrony/refclock_phc.c
+===================================================================
+--- chrony.orig/refclock_phc.c
++++ chrony/refclock_phc.c
+@@ -66,7 +66,7 @@ static int phc_initialise(RCL_Instance i
+ {
+   const char *options[] = {"nocrossts", "extpps", "pin", "channel", "clear", 
NULL};
+   struct phc_instance *phc;
+-  int phc_fd, rising_edge;
++  int rising_edge;
+   struct stat st;
+   char *path, *s;
+ 
+@@ -74,19 +74,20 @@ static int phc_initialise(RCL_Instance i
+ 
+   path = RCL_GetDriverParameter(instance);
+  
+-  phc_fd = SYS_Linux_OpenPHC(path, 0);
+-  if (phc_fd < 0)
+-    LOG_FATAL("Could not open PHC");
+-
+   phc = MallocNew(struct phc_instance);
+-  phc->fd = phc_fd;
+-  if (fstat(phc_fd, &st) < 0 || !S_ISCHR(st.st_mode))
+-    LOG_FATAL("Could not get PHC index");
+-  phc->dev_index = minor(st.st_rdev);
+   phc->mode = 0;
+   phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
+   phc->extpps = RCL_GetDriverOption(instance, "extpps") ? 1 : 0;
+   UTI_ZeroTimespec(&phc->last_extts);
++
++  phc->fd = SYS_Linux_OpenPHC(path, 0, phc->extpps ? O_RDWR : O_RDONLY);
++  if (phc->fd < 0)
++    LOG_FATAL("Could not open PHC");
++
++  if (fstat(phc->fd, &st) < 0 || !S_ISCHR(st.st_mode))
++    LOG_FATAL("Could not get PHC index");
++  phc->dev_index = minor(st.st_rdev);
++
+   phc->clock = HCL_CreateInstance(0, 16, 
UTI_Log2ToDouble(RCL_GetDriverPoll(instance)),
+                                   RCL_GetPrecision(instance));
+ 
+Index: chrony/sys_linux.c
+===================================================================
+--- chrony.orig/sys_linux.c
++++ chrony/sys_linux.c
+@@ -903,7 +903,7 @@ get_precise_phc_readings(int phc_fd, int
+ /* ================================================== */
+ 
+ int
+-SYS_Linux_OpenPHC(const char *path, int phc_index)
++SYS_Linux_OpenPHC(const char *path, int phc_index, int flags)
+ {
+   struct ptp_clock_caps caps;
+   char phc_path[64];
+@@ -915,7 +915,7 @@ SYS_Linux_OpenPHC(const char *path, int
+     path = phc_path;
+   }
+ 
+-  phc_fd = open(path, O_RDONLY);
++  phc_fd = open(path, flags);
+   if (phc_fd < 0) {
+     LOG(LOGS_ERR, "Could not open %s : %s", path, strerror(errno));
+     return -1;
+Index: chrony/sys_linux.h
+===================================================================
+--- chrony.orig/sys_linux.h
++++ chrony/sys_linux.h
+@@ -39,7 +39,7 @@ extern void SYS_Linux_EnableSystemCallFi
+ 
+ extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
+ 
+-extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
++extern int SYS_Linux_OpenPHC(const char *path, int phc_index, int flags);
+ 
+ extern int SYS_Linux_GetPHCReadings(int fd, int nocrossts, int *reading_mode, 
int max_readings,
+                                     struct timespec tss[][3]);
diff -Nru chrony-4.6.1/debian/patches/series chrony-4.6.1/debian/patches/series
--- chrony-4.6.1/debian/patches/series  2025-06-03 17:16:37.000000000 +0200
+++ chrony-4.6.1/debian/patches/series  2026-02-16 17:34:12.000000000 +0100
@@ -1,3 +1,4 @@
+refclock_phc_open-device-for-writing-with-extpps-option.patch
 conf:_fix_sourcedir_reloading_to_not_multiply_sources.patch
 debianize-chronyd-restricted-unit-file.patch
 nm-dispatcher-dhcp_Move-server_dir-to-run.patch
diff -Nru chrony-4.6.1/debian/tests/upstream-simulation-test-suite 
chrony-4.6.1/debian/tests/upstream-simulation-test-suite
--- chrony-4.6.1/debian/tests/upstream-simulation-test-suite    2025-06-03 
17:16:37.000000000 +0200
+++ chrony-4.6.1/debian/tests/upstream-simulation-test-suite    2026-02-16 
17:34:12.000000000 +0100
@@ -27,6 +27,24 @@
     tar -xvzf "$CLKNETSIM_PATH"/"$clknetsim_archive" \
         -C "$CLKNETSIM_PATH" --strip-components=1 2>&1 || exit 77
 
+    # Prevent simulation test failures introduced by
+    # refclock_phc_open-device-for-writing-with-extpps-option.patch
+    sed -i '
+        1498i\
+    int __open_2(const char *pathname, int oflag) {\
+            return open(pathname, oflag);\
+    }\
+    \
+    int __open64_2(const char *pathname, int oflag) {\
+            return open(pathname, oflag);\
+    }\
+
+        1538i\
+    ssize_t __read_chk(int fd, void *buf, size_t count, size_t buflen) {\
+            return read(fd, buf, count);\
+    }\
+    ' "$CLKNETSIM_PATH/client.c"
+
     if [ ! -x "$CLKNETSIM_PATH/clknetsim" ] && [ ! -e 
"$CLKNETSIM_PATH/clknetsim.so" ]; then
         case "$DEB_BUILD_ARCH" in
             armel|armhf)

Attachment: signature.asc
Description: PGP signature

Reply via email to