[PATCH] makedumpfile-1.5.4 dump dmesg may not work due to improper sprintf usage
Atsushi Kumagai
kumagai-atsushi at mxc.nes.nec.co.jp
Tue Aug 6 00:15:10 EDT 2013
Hello Nick,
On Mon, 29 Jul 2013 09:27:57 -0700
Nick Bartos <nick at pistoncloud.com> wrote:
> I am reporting this bug as requested in the "BUG REPORT" of
> the makedumpfile README.
>
> There are several times when sprintf is used to append to a buffer like so:
> sprintf(buf, "%s.", buf);
>
> In the sprintf manpage, it describes that behavior is not consistent. I
> first noticed this as my hardned system would make all dmesg output lines
> empty. Here is the excerpt from the man page:
>
> C99 and POSIX.1-2001 specify that the results are undefined if a call
> to sprintf(), snprintf(), vsprintf(), or vsnprintf() would cause copying
> to take place between objects that overlap (e.g., if the target string
> array and one of the supplied input arguments refer to the same buffer).
> See NOTES.
>
> NOTES
> Some programs imprudently rely on code such as the following
>
> sprintf(buf, "%s some further text", buf);
>
> to append text to buf. However, the standards explicitly note that
> the results are undefined if source and destination buffers overlap
> when calling sprintf(), snprintf(), vsprintf(), and vsnprintf().
> Depending on the version of gcc(1) used, and the compiler options employed,
> calls such as the above will not produce the expected results.
>
> The glibc implementation of the functions snprintf() and vsnprintf()
> conforms to the C99 standard, that is, behaves as described above, since
> glibc version 2.1. Until glibc 2.0.6 they would return -1 when the output
> was truncated.
>
>
> In addition to using sprintf improperly, it appears that there may be
> buffer overflow potential in the current code, since the loop does not stop
> if the size of buf is exhausted.
>
> I have attached a patch which modifies this behavior.
I have some comments on this patch, please see below.
> diff -U3 -r makedumpfile-1.5.4.orig/makedumpfile.c makedumpfile-1.5.4/makedumpfile.c
> --- makedumpfile-1.5.4.orig/makedumpfile.c 2013-07-01 08:08:49.000000000 +0000
> +++ makedumpfile-1.5.4/makedumpfile.c 2013-07-22 22:47:34.195721706 +0000
> @@ -3701,6 +3701,7 @@
> char *msg, *p;
> unsigned int i, text_len;
> unsigned long long ts_nsec;
> + int buf_s;
> char buf[BUFSIZE];
> ulonglong nanos;
> ulong rem;
> @@ -3713,21 +3714,49 @@
>
> msg = logptr + SIZE(log);
>
> - sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
> + buf_s = snprintf(buf, BUFSIZE, "[%5lld.%06ld] ", nanos, rem/1000);
> + if (buf_s < 0) {
> + DEBUG_MSG("snprintf returned an error in dump_log_entry.\n");
> + return FALSE;
> + }
This is the error case, so you should use ERRMSG instead of DEBUG_MSG.
The same can be said about all other messages.
> + if (buf_s >= BUFSIZE) {
> + DEBUG_MSG("snprintf truncated output in dump_log_entry.\n");
> + DEBUG_MSG(" increase BUFSIZE and recompile.\n");
> + /* No point in continuing, we can't append anything useful */
> + return FALSE;
> + }
> +
> + /* It's unlikely but possible we may not have enough to terminate the
> + string */
> + if (buf_s >= BUFSIZE - 1) {
> + DEBUG_MSG("not enough buffer space in dump_log_entry.\n");
> + DEBUG_MSG(" increase BUFSIZE and recompile.\n");
> + return FALSE;
> + }
> +
> + for (i = 0, p = msg; i < text_len; i++, p++, buf_s++) {
> + if (buf_s >= BUFSIZE - 2) {
> + DEBUG_MSG("output truncated in dump_log_entry.\n");
> + DEBUG_MSG(" increase BUFSIZE and recompile.\n");
> + break;
> + }
I don't think to check the remaining buffer space 3 times is meaningful,
they indicate just "lack of buffer space".
Is the last one enough to check the remaining buffer space ?
>
> - for (i = 0, p = msg; i < text_len; i++, p++) {
> if (*p == '\n')
> - sprintf(buf, "%s.", buf);
> + buf[buf_s] = '.';
> else if (isprint(*p) || isspace(*p))
> - sprintf(buf, "%s%c", buf, *p);
> + buf[buf_s] = *p;
> else
> - sprintf(buf, "%s.", buf);
> + buf[buf_s] = '.';
> }
>
> - sprintf(buf, "%s\n", buf);
> + buf[buf_s] = '\n';
> + buf_s++;
> + buf[buf_s] = NULL;
Null character(\0) should be used to terminate strings instead of
null pointer.
>
> - if (write(info->fd_dumpfile, buf, strlen(buf)) < 0)
> + if (write(info->fd_dumpfile, buf, strlen(buf)) < 0) {
> + DEBUG_MSG("Problem writing to dump file.\n");
> return FALSE;
> + }
> else
> return TRUE;
> }
Thanks
Atsushi Kumagai
More information about the kexec
mailing list