diff mbox series

[meta-networking,kirkstone] ntp: backport patch for 5 CVEs CVE-2023-26551/2/3/4/5

Message ID 20230628200637.1393267-1-peter.marko@siemens.com
State New
Headers show
Series [meta-networking,kirkstone] ntp: backport patch for 5 CVEs CVE-2023-26551/2/3/4/5 | expand

Commit Message

Peter Marko June 28, 2023, 8:06 p.m. UTC
From: Peter Marko <peter.marko@siemens.com>

Patch taken from https://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p15-3806-3807.patch
It is linked as official patch for p15 in:
- https://www.ntp.org/support/securitynotice/ntpbug3807/
- https://www.ntp.org/support/securitynotice/ntpbug3806/

Small adaptation to build is needed because of how tests are built.

Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 .../ntp/ntp/CVE-2023-2655x.patch              | 323 ++++++++++++++++++
 .../recipes-support/ntp/ntp_4.2.8p15.bb       |   9 +
 2 files changed, 332 insertions(+)
 create mode 100755 meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch
diff mbox series

Patch

diff --git a/meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch b/meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch
new file mode 100755
index 0000000000..fbd0ec151a
--- /dev/null
+++ b/meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch
@@ -0,0 +1,323 @@ 
+CVE: CVE-2023-26551
+CVE: CVE-2023-26552
+CVE: CVE-2023-26553
+CVE: CVE-2023-26554
+CVE: CVE-2023-26555
+Upstream-Status: Backport [https://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p15-3806-3807.patch]
+
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+--- include/ntp_fp.h	2019-06-03 23:41:14.000000000 -0500
++++ ../ntp-stable-p16-sec/include/ntp_fp.h	2023-04-17 03:17:01.655121000 -0500
+@@ -195,9 +195,9 @@
+ 	do { \
+ 		int32 add_f = (int32)(f); \
+ 		if (add_f >= 0) \
+-			M_ADD((r_i), (r_f), 0, (uint32)( add_f)); \
++			M_ADD((r_i), (r_f), 0, (u_int32)( add_f)); \
+ 		else \
+-			M_SUB((r_i), (r_f), 0, (uint32)(-add_f)); \
++			M_SUB((r_i), (r_f), 0, (u_int32)(-add_f)); \
+ 	} while(0)
+ 
+ #define	M_ISNEG(v_i)			/* v < 0 */ \
+--- libntp/mstolfp.c	2019-06-03 23:41:14.000000000 -0500
++++ ../ntp-stable-p16-sec/libntp/mstolfp.c	2023-04-17 03:07:38.598581000 -0500
+@@ -14,86 +14,58 @@
+ 	l_fp *lfp
+ 	)
+ {
+-	register const char *cp;
+-	register char *bp;
+-	register const char *cpdec;
+-	char buf[100];
++	int        ch, neg = 0; 
++	u_int32    q, r;
+ 
+ 	/*
+ 	 * We understand numbers of the form:
+ 	 *
+ 	 * [spaces][-|+][digits][.][digits][spaces|\n|\0]
+ 	 *
+-	 * This is one enormous hack.  Since I didn't feel like
+-	 * rewriting the decoding routine for milliseconds, what
+-	 * is essentially done here is to make a copy of the string
+-	 * with the decimal moved over three places so the seconds
+-	 * decoding routine can be used.
++	 * This is kinda hack.  We use 'atolfp' to do the basic parsing
++	 * (after some initial checks) and then divide the result by
++	 * 1000.  The original implementation avoided that by
++	 * hacking up the input string to move the decimal point, but
++	 * that needed string manipulations prone to buffer overruns.
++	 * To avoid that trouble we do the conversion first and adjust
++	 * the result.
+ 	 */
+-	bp = buf;
+-	cp = str;
+-	while (isspace((unsigned char)*cp))
+-	    cp++;
+ 	
+-	if (*cp == '-' || *cp == '+') {
+-		*bp++ = *cp++;
+-	}
+-
+-	if (*cp != '.' && !isdigit((unsigned char)*cp))
+-	    return 0;
+-
+-
+-	/*
+-	 * Search forward for the decimal point or the end of the string.
+-	 */
+-	cpdec = cp;
+-	while (isdigit((unsigned char)*cpdec))
+-	    cpdec++;
+-
+-	/*
+-	 * Found something.  If we have more than three digits copy the
+-	 * excess over, else insert a leading 0.
+-	 */
+-	if ((cpdec - cp) > 3) {
+-		do {
+-			*bp++ = (char)*cp++;
+-		} while ((cpdec - cp) > 3);
+-	} else {
+-		*bp++ = '0';
+-	}
+-
+-	/*
+-	 * Stick the decimal in.  If we've got less than three digits in
+-	 * front of the millisecond decimal we insert the appropriate number
+-	 * of zeros.
+-	 */
+-	*bp++ = '.';
+-	if ((cpdec - cp) < 3) {
+-		size_t i = 3 - (cpdec - cp);
+-		do {
+-			*bp++ = '0';
+-		} while (--i > 0);
+-	}
+-
+-	/*
+-	 * Copy the remainder up to the millisecond decimal.  If cpdec
+-	 * is pointing at a decimal point, copy in the trailing number too.
+-	 */
+-	while (cp < cpdec)
+-	    *bp++ = (char)*cp++;
++	while (isspace(ch = *(const unsigned char*)str))
++		++str;
+ 	
+-	if (*cp == '.') {
+-		cp++;
+-		while (isdigit((unsigned char)*cp))
+-		    *bp++ = (char)*cp++;
++	switch (ch) {
++	    case '-': neg = TRUE;
++	    case '+': ++str;
++	    default : break;
+ 	}
+-	*bp = '\0';
+-
+-	/*
+-	 * Check to make sure the string is properly terminated.  If
+-	 * so, give the buffer to the decoding routine.
+-	 */
+-	if (*cp != '\0' && !isspace((unsigned char)*cp))
+-	    return 0;
+-	return atolfp(buf, lfp);
++	
++	if (!isdigit(ch = *(const unsigned char*)str) && (ch != '.'))
++		return 0;
++	if (!atolfp(str, lfp))
++		return 0;
++
++	/* now do a chained/overlapping division by 1000 to get from
++	 * seconds to msec. 1000 is small enough to go with temporary
++	 * 32bit accus for Q and R.
++	 */
++	q = lfp->l_ui / 1000u;
++	r = lfp->l_ui - (q * 1000u);
++	lfp->l_ui = q;
++
++	r = (r << 16) | (lfp->l_uf >> 16);
++	q = r / 1000u;
++	r = ((r - q * 1000) << 16) | (lfp->l_uf & 0x0FFFFu);
++	lfp->l_uf = q << 16;
++	q = r / 1000;
++	lfp->l_uf |= q;
++	r -= q * 1000u;
++
++	/* fix sign */
++	if (neg)
++		L_NEG(lfp);
++	/* round */
++	if (r >= 500)
++		L_ADDF(lfp, (neg ? -1 : 1));
++	return 1;
+ }
+--- ntpd/refclock_palisade.c	2020-04-11 04:31:33.000000000 -0500
++++ ../ntp-stable-p16-sec/ntpd/refclock_palisade.c	2023-04-15 18:09:29.787588000 -0500
+@@ -1225,9 +1225,9 @@
+ 		return;  /* using synchronous packet input */
+ 
+ 	if(up->type == CLK_PRAECIS) {
+-		if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0)
++		if (write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) {
+ 			msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit);
+-		else {
++		} else {
+ 			praecis_msg = 1;
+ 			return;
+ 		}
+@@ -1249,20 +1249,53 @@
+ 
+ 	pp = peer->procptr;
+ 
+-	memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length);
++	if (p + rbufp->recv_length >= sizeof buf) {
++		struct palisade_unit *up;
++		up = pp->unitptr;
++
++		/*
++		 * We COULD see if there is a \r\n in the incoming
++		 * buffer before it overflows, and then process the
++		 * current line.
++		 *
++		 * Similarly, if we already have a hunk of data that
++		 * we're now flushing, that will cause the line of
++		 * data we're in the process of collecting to be garbage.
++		 *
++		 * Since we now check for this overflow and log when it
++		 * happens, we're now in a better place to easily see
++		 * what's going on and perhaps better choices can be made.
++		 */
++
++		/* Do we need to log the size of the overflow? */
++		msyslog(LOG_ERR, "Palisade(%d) praecis_parse(): input buffer overflow", 
++			up->unit);
++
++		p = 0;
++		praecis_msg = 0;
++
++		refclock_report(peer, CEVNT_BADREPLY);
++
++		return;
++	}
++
++	memcpy(buf+p, rbufp->recv_buffer, rbufp->recv_length);
+ 	p += rbufp->recv_length;
+ 
+-	if(buf[p-2] == '\r' && buf[p-1] == '\n') {
++	if (   p >= 2
++	    && buf[p-2] == '\r' 
++	    && buf[p-1] == '\n') {
+ 		buf[p-2] = '\0';
+ 		record_clock_stats(&peer->srcadr, buf);
+ 
+ 		p = 0;
+ 		praecis_msg = 0;
+ 
+-		if (HW_poll(pp) < 0)
++		if (HW_poll(pp) < 0) {
+ 			refclock_report(peer, CEVNT_FAULT);
+-
++		}
+ 	}
++	return;
+ }
+ 
+ static void
+@@ -1407,7 +1440,10 @@
+ 
+ 	/* Edge trigger */
+ 	if (up->type == CLK_ACUTIME)
+-		write (pp->io.fd, "", 1);
++		if (write (pp->io.fd, "", 1) != 1)
++			msyslog(LOG_WARNING,
++				"Palisade(%d) HW_poll: failed to send trigger: %m", 
++				up->unit);
+ 		
+ 	if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { 
+ #ifdef DEBUG
+--- tests/libntp/strtolfp.c	2020-05-22 01:33:24.000000000 -0500
++++ ../ntp-stable-p16-sec/tests/libntp/strtolfp.c	2023-04-16 03:28:16.967582000 -0500
+@@ -26,6 +26,13 @@
+ 	return;
+ }
+ 
++static const char* fmtLFP(const l_fp *e, const l_fp *a)
++{
++    static char buf[100];
++    snprintf(buf, sizeof(buf), "e=$%08x.%08x, a=$%08x.%08x",
++	     e->l_ui, e->l_uf, a->l_ui, a->l_uf);
++    return buf;
++}
+ 
+ void test_PositiveInteger(void) {
+ 	const char *str = "500";
+@@ -37,8 +44,8 @@
+ 	TEST_ASSERT_TRUE(atolfp(str, &actual));
+ 	TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms));
+ 
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual));
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual_ms));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms));
+ }
+ 
+ void test_NegativeInteger(void) {
+@@ -54,8 +61,8 @@
+ 	TEST_ASSERT_TRUE(atolfp(str, &actual));
+ 	TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms));
+ 
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual));
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual_ms));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms));
+ }
+ 
+ void test_PositiveFraction(void) {
+@@ -68,8 +75,8 @@
+ 	TEST_ASSERT_TRUE(atolfp(str, &actual));
+ 	TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms));
+ 
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual));
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual_ms));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms));
+ }
+ 
+ void test_NegativeFraction(void) {
+@@ -85,8 +92,8 @@
+ 	TEST_ASSERT_TRUE(atolfp(str, &actual));
+ 	TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms));
+ 
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual));
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual_ms));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms));
+ }
+ 
+ void test_PositiveMsFraction(void) {
+@@ -100,9 +107,8 @@
+ 	TEST_ASSERT_TRUE(atolfp(str, &actual));
+ 	TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms));
+ 
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual));
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual_ms));
+-
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms));
+ }
+ 
+ void test_NegativeMsFraction(void) {
+@@ -118,9 +124,8 @@
+ 	TEST_ASSERT_TRUE(atolfp(str, &actual));
+ 	TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms));
+ 
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual));
+-	TEST_ASSERT_TRUE(IsEqual(expected, actual_ms));
+-
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual));
++	TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms));
+ }
+ 
+ void test_InvalidChars(void) {
diff --git a/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb b/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb
index 91e4945a17..7861a5e3e6 100644
--- a/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb
+++ b/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb
@@ -24,6 +24,7 @@  SRC_URI = "http://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-${PV}.tar.g
            file://sntp.service \
            file://sntp \
            file://ntpd.list \
+           file://CVE-2023-2655x.patch;striplevel=0 \
 "
 
 SRC_URI[sha256sum] = "f65840deab68614d5d7ceb2d0bb9304ff70dcdedd09abb79754a87536b849c19"
@@ -92,6 +93,14 @@  PACKAGECONFIG[debug] = "--enable-debugging,--disable-debugging"
 PACKAGECONFIG[mdns] = "ac_cv_header_dns_sd_h=yes,ac_cv_header_dns_sd_h=no,mdns"
 PACKAGECONFIG[ipv6] = "--enable-ipv6,--disable-ipv6,"
 
+do_configure:append() {
+    # tests are generated but also checked-in to source control
+    # when CVE-2023-2655x.patch changes timestamp of test source file, Makefile detects it and tries to regenerate it
+    # however it fails because of missing ruby interpretter; adding ruby-native as dependency fixes it
+    # since the regenerated file is identical to the one from source control, touch the generated file instead of adding heavy dependency
+    touch ${S}/tests/libntp/run-strtolfp.c
+}
+
 do_install:append() {
     install -d ${D}${sysconfdir}/init.d
     install -m 644 ${WORKDIR}/ntp.conf ${D}${sysconfdir}