From ebd64fcbd4f3858b6986ff1a048e3467d96841ab Mon Sep 17 00:00:00 2001 From: Harlen Stenn 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