Bugtraq mailing list archives
Re: Format String Attacks
From: Ajax <ajax () FIREST0RM ORG>
Date: Fri, 22 Sep 2000 14:48:55 -0500
Yeah, i thought varargs got passed on the stack. Apologies, it's been a long week, but I think I'm still right, kinda...
When the compiler constructs the va_list that ap will point to, it simply makes the last element NULL, which can (ought) never be a valid pointer to anything. ap then looks like:methinks this is more suitable for comp.lang.c, but what the heck... we'll let Elias moderate this. :=) You cannot assume anything about va_list based on its definition or prototypes. va_list and va_*() macros are to be treated as black-boxes. Use them, but do not assume anything about how they are implemented or how it works.
I'll quote you on that in a second.
For example, on the x86, all args are passed on the stack. If you're calling printf("help %i %s %f\n", 123, "abc", 2.35432): <=== remainder of the stack --------------- | 2.3542 | <=== 3rd vararg, a float --------------- | char "abc\0"| <=== 2nd vararg, a ptr to a character string --------------- | 123 | <=== first varable arg, in this case an integer --------------- | const char* | <=== first arg of printf(), a ptr to the fmt string --------------- | ret address | <=== return address, duh --------------- | ..... | <=== SP upon entry to printf() As you can see, there are no pointers to the integer or float vararg. varargs is similar to an array of Visual Basic-like variant types, but since one can't have an array of voids in C, the closest thing is an array of void pointers. In this example, when you call va_start(), "ap" is set to point at the first vararg, which is the integer 123. When you fetch that int using va_arg() macro, it increments "ap" by the size of the integer.
So, we're supposed to treat va* as black boxes, right? The compiler emits the code that pushes everything onto the stack. It could emit some code that keeps a count of, if not the number of objects it pushed, then at least the size of the array for perverse x86-like architectures. Maybe put this in some process- or thread-specific copy-on-write page that the C library maintains on process entry. Make va_arg decrement the counter. Implement va_last accordingly, maybe passing it the expected "next type". Even if we cons our own va_list up, the compiler still has to push everything, so it can always keep something of a count. This should not break any ABI, since the count variable is not kept in a register or in the stack. You can always use #ifdef. It might require modifying libgcc or crt0.o a bit, but we shouldn't _need_ to touch any system library. And we can always make the new vararg entry code dependent on the presence of va_last, should that happen to break something. .over.enthusiastic. -=:[ ajax (firest0rm)
Current thread:
- Re: Format String Attacks, (continued)
- Re: Format String Attacks Dan Harkless (Sep 15)
- Re: Format String Attacks Dan Harkless (Sep 17)
- Re: Format String Attacks Drazen Kacar (Sep 14)
- Re: Format String Attacks Dan Harkless (Sep 14)
- Re: Format String Attacks Serguei Patchkovskii (Sep 14)
- Re: Format String Attacks Rick Perry (Sep 14)
- Re: Format String Attacks Ajax (Sep 21)
- Re: Format String Attacks Nate Eldredge (Sep 21)
- Re: Format String Attacks Matthias Meixner (Sep 22)
- Re: Format String Attacks jsl2 (Sep 22)
- Re: Format String Attacks Ajax (Sep 25)