}
+/* TALOS-CAN-0055: possibly DoS attack by setting the key file to the
+ * log file. This is hard to prevent (it would need to check two files
+ * to be the same on the inode level, which will not work so easily with
+ * Windows or VMS) but we can avoid the self-amplification loop: We only
+ * log the first 5 errors, silently ignore the next 10 errors, and give
+ * up when when we have found more than 15 errors.
+ *
+ * This avoids the endless file iteration we will end up with otherwise,
+ * and also avoids overflowing the log file.
+ *
+ * Nevertheless, once this happens, the keys are gone since this would
+ * require a save/swap strategy that is not easy to apply due to the
+ * data on global/static level.
+ */
+
+static const size_t nerr_loglimit = 5u;
+static const size_t nerr_maxlimit = 15;
+
+static void log_maybe(size_t*, const char*, ...) NTP_PRINTF(2, 3);
+
+static void
+log_maybe(
+ size_t *pnerr,
+ const char *fmt ,
+ ...)
+{
+ va_list ap;
+ if (++(*pnerr) <= nerr_loglimit) {
+ va_start(ap, fmt);
+ mvsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
+ }
+}
+
/*
* authreadkeys - (re)read keys from a file.
*/
u_char keystr[32]; /* Bug 2537 */
size_t len;
size_t j;
-
+ size_t nerr;
/*
* Open file. Complain and return if it can't be opened.
*/
/*
* Now read lines from the file, looking for key entries
*/
+ nerr = 0;
while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
+ if (nerr > nerr_maxlimit)
+ break;
token = nexttok(&line);
if (token == NULL)
continue;
*/
keyno = atoi(token);
if (keyno == 0) {
- msyslog(LOG_ERR,
- "authreadkeys: cannot change key %s", token);
+ log_maybe(&nerr,
+ "authreadkeys: cannot change key %s",
+ token);
continue;
}
if (keyno > NTP_MAXKEY) {
- msyslog(LOG_ERR,
- "authreadkeys: key %s > %d reserved for Autokey",
- token, NTP_MAXKEY);
+ log_maybe(&nerr,
+ "authreadkeys: key %s > %d reserved for Autokey",
+ token, NTP_MAXKEY);
continue;
}
*/
token = nexttok(&line);
if (token == NULL) {
- msyslog(LOG_ERR,
- "authreadkeys: no key type for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: no key type for key %d",
+ keyno);
continue;
}
#ifdef OPENSSL
*/
keytype = keytype_from_text(token, NULL);
if (keytype == 0) {
- msyslog(LOG_ERR,
- "authreadkeys: invalid type for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: invalid type for key %d",
+ keyno);
continue;
}
if (EVP_get_digestbynid(keytype) == NULL) {
- msyslog(LOG_ERR,
- "authreadkeys: no algorithm for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: no algorithm for key %d",
+ keyno);
continue;
}
#else /* !OPENSSL follows */
* 'm' for compatibility.
*/
if (!(*token == 'M' || *token == 'm')) {
- msyslog(LOG_ERR,
- "authreadkeys: invalid type for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: invalid type for key %d",
+ keyno);
continue;
}
keytype = KEY_TYPE_MD5;
*/
token = nexttok(&line);
if (token == NULL) {
- msyslog(LOG_ERR,
- "authreadkeys: no key for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: no key for key %d", keyno);
continue;
}
len = strlen(token);
keystr[j / 2] = temp << 4;
}
if (j < jlim) {
- msyslog(LOG_ERR,
- "authreadkeys: invalid hex digit for key %d", keyno);
+ log_maybe(&nerr,
+ "authreadkeys: invalid hex digit for key %d",
+ keyno);
continue;
}
MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
}
}
fclose(fp);
+ if (nerr > nerr_maxlimit) {
+ msyslog(LOG_ERR,
+ "authreadkeys: emergeny break after %u errors",
+ nerr);
+ return (0);
+ } else if (nerr > nerr_loglimit) {
+ msyslog(LOG_ERR,
+ "authreadkeys: found %u more error(s)",
+ nerr - nerr_loglimit);
+ }
return (1);
}