168 lines
4.4 KiB
Diff
168 lines
4.4 KiB
Diff
From ebd64fcbd4f3858b6986ff1a048e3467d96841ab Mon Sep 17 00:00:00 2001
|
|
From: Harlen Stenn <stenn@ntp.org>
|
|
Date: Sat, 13 May 2023 05:23:33 UTC
|
|
Subject: [PATCH] mstolfp:make sure the buffer has enough room for the input extra characters
|
|
|
|
Conflict:NA
|
|
Reference:https://www.eecis.udel.edu/~ntp/ntp_spool//ntp4/ntp-4.2.8p15-3806-3807.patch
|
|
|
|
CVE-2023-26552, CVE-2023-26553, and CVE-2023-26554 are marked identical to CVE-2023-26551
|
|
https://github.com/spwpun/ntp-4.2.8p15-cves/issues/1
|
|
|
|
---
|
|
include/ntp_fp.h | 4 +-
|
|
libntp/mstolfp.c | 109 +++++++++++++++-------------------------
|
|
2 files changed, 42 insertions(+), 71 deletions(-)
|
|
|
|
diff --git a/include/ntp_fp.h b/include/ntp_fp.h
|
|
index afd1f82..fe6e390 100644
|
|
--- a/include/ntp_fp.h
|
|
+++ b/include/ntp_fp.h
|
|
@@ -195,9 +195,9 @@ typedef u_int32 u_fp;
|
|
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 */ \
|
|
diff --git a/libntp/mstolfp.c b/libntp/mstolfp.c
|
|
index 3dfc4ef..a428d17 100644
|
|
--- a/libntp/mstolfp.c
|
|
+++ b/libntp/mstolfp.c
|
|
@@ -14,86 +14,57 @@ mstolfp(
|
|
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';
|
|
+ while (isspace(ch = *(const unsigned char*)str))
|
|
+ ++str;
|
|
+ switch (ch) {
|
|
+ case '-': neg = TRUE;
|
|
+ case '+': ++str;
|
|
+ default : break;
|
|
}
|
|
|
|
- /*
|
|
- * 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);
|
|
- }
|
|
+ if (!isdigit(ch = *(const unsigned char*)str) && (ch != '.'))
|
|
+ return 0;
|
|
+ if (!atolfp(str, lfp))
|
|
+ return 0;
|
|
|
|
- /*
|
|
- * Copy the remainder up to the millisecond decimal. If cpdec
|
|
- * is pointing at a decimal point, copy in the trailing number too.
|
|
+ /* 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.
|
|
*/
|
|
- while (cp < cpdec)
|
|
- *bp++ = (char)*cp++;
|
|
-
|
|
- if (*cp == '.') {
|
|
- cp++;
|
|
- while (isdigit((unsigned char)*cp))
|
|
- *bp++ = (char)*cp++;
|
|
- }
|
|
- *bp = '\0';
|
|
+ q = lfp->l_ui / 1000u;
|
|
+ r = lfp->l_ui - (q * 1000u);
|
|
+ lfp->l_ui = q;
|
|
|
|
- /*
|
|
- * 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);
|
|
+ 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;
|
|
}
|
|
--
|
|
2.33.0
|
|
|
|
|