[systemd-bugs] [Bug 55213] New: Early boot vsnprintf/vasprintf segfault
bugzilla-daemon at freedesktop.org
bugzilla-daemon at freedesktop.org
Sat Sep 22 00:28:15 PDT 2012
https://bugs.freedesktop.org/show_bug.cgi?id=55213
Bug #: 55213
Summary: Early boot vsnprintf/vasprintf segfault
Classification: Unclassified
Product: systemd
Version: unspecified
Platform: x86 (IA32)
OS/Version: Linux (All)
Status: NEW
Severity: blocker
Priority: medium
Component: general
AssignedTo: systemd-bugs at lists.freedesktop.org
ReportedBy: jpsinthemix at verizon.net
QAContact: systemd-bugs at lists.freedesktop.org
Created attachment 67533
--> https://bugs.freedesktop.org/attachment.cgi?id=67533
Working (but ugly) fix of early boot vsnprintf/vasprintf segfault
Hi,
Beginning in post-systemd-189 git, and still present in systemd-191, there is a
nasty problem in function log_struct_internal() (src/shared/log.c), which
renders my PC unbootable, giving an early boot systemd[1] segfault in
/lib/libc-2.16.90.so, and 'Freezing execution.'
My system: i686-pc-linux-gnu, gcc-4.7.1, glibc-2.16.0, linux-3.6.0-rc6,
systemd-191 (all software built from source).
The segfault is due to a misuse of the vsnprintf() and vasprintf() functions.
Specifically, one must not use va_arg() after calls to vsnprintf() or
vasprintf() as these function/macros internally use va_arg() and may modify it
undefined ways. In particular, from the vsnprintf manpage:
The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() are equivalent to
the functions printf(), fprintf(), sprintf(), snprintf(), respectively, except
that they are called with a va_list instead of a variable number of arguments.
These functions do not call the va_end macro. Because they invoke the
va_arg macro, the value of ap is undefined after the call. See stdarg(3),
and from the stdarg manpage:
va_arg()
...
If ap is passed to a function that uses va_arg(ap,type) then the value of
ap is undefined after the return of that function.
In systemd-191/src/shared/log.c, we have the following problematic code in
log_struct_internal():
705 va_start(ap, format);
706 while (format && n + 1 < ELEMENTSOF(iovec)) {
707 char *buf;
708
709 if (vasprintf(&buf, format, ap) < 0) {
710 r = -ENOMEM;
711 goto finish;
712 }
713
714 IOVEC_SET_STRING(iovec[n++], buf);
715
716 iovec[n].iov_base = (char*) &nl;
717 iovec[n].iov_len = 1;
718 n++;
719
720 format = va_arg(ap, char *); <---- use of ap here
is invalid/non-portable
721 }
722 va_end(ap);
741 /* Fallback if journal logging is not available */
742
743 va_start(ap, format);
744 while (format) {
745
746 vsnprintf(buf, sizeof(buf), format, ap);
747 char_array_0(buf);
748
749 if (startswith(buf, "MESSAGE=")) {
750 found = true;
751 break;
752 }
753
754 format = va_arg(ap, char *); <---- use of ap here
is invalid/non-portable
755 }
756 va_end(ap);
It appears that the assumption has been made that ap is internally incremented
as values are formatted into buf, but there is no guarantee that this will
occur. Apparently it does occur for some architecture/compiler/libcs, while not
for others. This is truly unfortunate as the vsnprintf/vasprintf-relaled code
now in log_struct_internal() is, in my judgement, quite elegant.
One way around this would be to write code to parse the format strings enough
to figure out the number and types of args associated with each format (tricky
and counter to the use of vsnprintf/vasprintf in the first place, and probably
a pain to maintain and port).
I have attached a patch which 'fixes' this issue in the sense that I'm now up
and running with systemd-191, and all appears to be well.. but it's a bit of a
hack, and admittedly rather ugly. What I've done is to pass each
format-vararglist pair in now occuring in log_struct_internal() calls to a new
function log_struct_entry() which produces the desired string. Then,
log_struct_internal() calls simply have to deal with a vararglist of strings.
hope this helps, and thanks for your time,
John
PS: I've been using systemd since v188 (w/o sysvinit) for desktop/laptops (and
even in ramroots) and love it. The unit file syntax is nice and intuitive and
things mostly work great out-of-the-box. This, is after several years of using
Upstart, which worked adequately, but still was not as flexible as it should've
been, and a was bit fragile..
--
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA Contact for the bug.
You are the assignee for the bug.
More information about the systemd-bugs
mailing list