Bugtraq mailing list archives

Re: Format String Attacks


From: Nate Eldredge <neldredge () HMC EDU>
Date: Thu, 21 Sep 2000 11:30:52 -0700

Ajax writes:
Forgive my naivete here, but...  Isn't the essential problem, besides poor
coding practice which we all know is not an excuse yadda yadda yadda, the
fact that C doesn't define a way to detect the end of a va_list?  We have
va_start(), va_arg(), and the misleadingly named va_end(), but no
"va_last()".

Would it be that hard to implement an int va_last(va_list ap) that would
return true if ap pointed to the last element in a set of varargs?

The default stdarg.h implementation for gcc seems to do this (for
little-endian architectures, comments mine):

/* init AP to the next arg we pop from the stack */
#define va_start(AP, LASTARG)                                           \
 (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG)))

/* advance the AP pointer and return the next arg */
#define va_arg(AP, TYPE)                                                \
 (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),     \
  *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))

Note how this works; AP is treated as, essentially, void *AP[], an array
of pointers to arbitrary types.  This creates a natural terminating
condition, where the last element in the array is NULL (_not_ a pointer to
NULL).

This is wrong.  AP is instead an array *of* arbitrary types (or
rather, a pointer to a sequence of arbitrary types).  Read the code
more carefully and you'll see that this is so.  In essence, if we let
va_list be a `char *', then `foo = va_arg(ap, struct bar)' would be
equivalent to:

foo = *(struct bar *)ap;
ap += sizeof(struct bar);

Thus, since the objects themselves are stored in the array, there is
no way to identify which is the last one.  No marker we could insert
at the end could be distinguished from an actual argument with the
same value.

Note: This is certainly true for i386 at least.  I'm not sufficiently
familiar with other architectures to generalize this, but I believe it
is similar.

--

Nate Eldredge
neldredge () hmc edu


Current thread: