7947ad20b75e839bd0bb944db858bc73b56e568f max Mon Jun 16 05:36:01 2025 -0700 XSS prevention in error message output for errAbort(), refs #34157 diff --git src/lib/errAbort.c src/lib/errAbort.c index cc57a3e1df0..185248aaeb6 100644 --- src/lib/errAbort.c +++ src/lib/errAbort.c @@ -42,39 +42,76 @@ boolean errAbortInProgress; /* Flag to indicate that an error abort is in progress. * Needed so that a warn handler can tell if it's really * being called because of a warning or an error. */ WarnHandler warnArray[maxWarnHandlers]; int warnIx; AbortHandler abortArray[maxAbortHandlers]; int abortIx; }; static struct perThreadAbortVars *getThreadVars(); // forward declaration static void defaultVaWarn(char *format, va_list args) /* Default error message handler. */ { if (format != NULL) { - // vfprintf() cannot be called twice in a row without a va_end/va_start - // so this must be an if/else situation if (doContentType) { puts("Content-type: text/html\n"); puts("Error: "); - vfprintf(stdout, format, args); + + // Need to destroy < and > in format AND args, to make XSS impossible. + // and vfprintf() cannot be called twice in a row without a va_copy + va_list args_copy; + + // first output message to stderr, as before + va_copy(args_copy, args); + vfprintf(stderr, format, args); + va_end(args_copy); + + // get size of buffer needed + va_copy(args_copy, args); + int needed = vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); + if (needed < 0) + { + puts("defaultVaWarn - string format error in errAbort"); // Formatting error + return; + } + + // allocate buffer + char *buffer = malloc(needed + 1); + if (!buffer) + { + puts("defaultVaWarn - cannot allocate memory for errAbort message"); // Formatting error + return; + } + + // write message to buffer + vsprintf(buffer, format, args); + + // sanitize buffer + for (char *p = buffer; *p; ++p) { + if (*p == '<') *p = '['; + if (*p == '>') *p = ']'; + } + + // output + fputs(buffer, stdout); // or log it fprintf(stdout, "\n"); fflush(stdout); + free(buffer); } else { fflush(stdout); vfprintf(stderr, format, args); fprintf(stderr, "\n"); fflush(stderr); } } } static void silentVaWarn(char *format, va_list args) /* Warning handler that just hides it. Useful sometimes when high level code * expects low level code may fail (as in finding a file on the net) but doesn't * want user to be bothered about it. */