diff -up ntp-4.2.6p5/ntpd/ntp_control.c.cve-2015-5146 ntp-4.2.6p5/ntpd/ntp_control.c --- ntp-4.2.6p5/ntpd/ntp_control.c.cve-2015-5146 2015-07-16 15:37:02.297977248 +0200 +++ ntp-4.2.6p5/ntpd/ntp_control.c 2015-07-16 15:37:02.403977575 +0200 @@ -2471,6 +2471,35 @@ write_variables( ctl_flushpkt(0); } +/* Bug 2853 */ +/* evaluate the length of the command sequence. This breaks at the first + * char that is not >= SPACE and <= 127 after trimming from the right. + */ +static size_t +cmdlength( + const char *src_buf, + const char *src_end + ) +{ + const char *scan; + unsigned char ch; + + /* trim whitespace & garbage from the right */ + while (src_end != src_buf) { + ch = src_end[-1]; + if (ch > ' ' && ch < 128) + break; + --src_end; + } + /* now do a forward scan */ + for (scan = src_buf; scan != src_end; ++scan) { + ch = scan[0]; + if ((ch < ' ' || ch >= 128) && ch != '\t') + break; + } + return (size_t)(scan - src_buf); +} + /* * configure() processes ntpq :config/config-from-file, allowing * generic runtime reconfiguration. @@ -2482,7 +2511,6 @@ static void configure( { size_t data_count; int retval; - int replace_nl; /* I haven't yet implemented changes to an existing association. * Hence check if the association id is 0 @@ -2506,7 +2534,7 @@ static void configure( } /* Initialize the remote config buffer */ - data_count = reqend - reqpt; + data_count = cmdlength(reqpt, reqend); if (data_count > sizeof(remote_config.buffer) - 2) { snprintf(remote_config.err_msg, @@ -2520,33 +2548,41 @@ static void configure( stoa(&rbufp->recv_srcadr)); return; } + /* Bug 2853 -- check if all characters were acceptable */ + if (data_count != (size_t)(reqend - reqpt)) { + snprintf(remote_config.err_msg, + sizeof(remote_config.err_msg), + "runtime configuration failed: request contains an unprintable character"); + ctl_putdata(remote_config.err_msg, + strlen(remote_config.err_msg), 0); + ctl_flushpkt(0); + msyslog(LOG_NOTICE, + "runtime config from %s rejected: request contains an unprintable character: %0x", + stoa(&rbufp->recv_srcadr), + reqpt[data_count]); + return; + } memcpy(remote_config.buffer, reqpt, data_count); - if (data_count > 0 - && '\n' != remote_config.buffer[data_count - 1]) - remote_config.buffer[data_count++] = '\n'; + /* The buffer has no trailing linefeed or NUL right now. For + * logging, we do not want a newline, so we do that first after + * adding the necessary NUL byte. + */ remote_config.buffer[data_count] = '\0'; - remote_config.pos = 0; - remote_config.err_pos = 0; - remote_config.no_errors = 0; - - /* do not include terminating newline in log */ - if (data_count > 0 - && '\n' == remote_config.buffer[data_count - 1]) { - remote_config.buffer[data_count - 1] = '\0'; - replace_nl = 1; - } else - replace_nl = 0; - DPRINTF(1, ("Got Remote Configuration Command: %s\n", remote_config.buffer)); msyslog(LOG_NOTICE, "%s config: %s", stoa(&rbufp->recv_srcadr), remote_config.buffer); - if (replace_nl) - remote_config.buffer[data_count - 1] = '\n'; - + /* Now we have to make sure there is a NL/NUL sequence at the + * end of the buffer before we parse it. + */ + remote_config.buffer[data_count++] = '\n'; + remote_config.buffer[data_count] = '\0'; + remote_config.pos = 0; + remote_config.err_pos = 0; + remote_config.no_errors = 0; config_remotely(&rbufp->recv_srcadr); /*