lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-Id: <314B5322-3575-4449-90D2-3068BDC3F64D@mac.com> Date: Wed, 24 Oct 2007 20:07:23 -0400 From: Kyle Moffett <mrmacman_g4@....com> To: Matthew Wilcox <matthew@....cx> Cc: Linus Torvalds <torvalds@...l.org>, Andrew Morton <akpm@...l.org>, linux-kernel@...r.kernel.org, Matthew Wilcox <willy@...ux.intel.com> Subject: Re: [PATCH 1/4] stringbuf: A string buffer implementation On Oct 24, 2007, at 17:21:10, Matthew Wilcox wrote: > On Wed, Oct 24, 2007 at 04:59:48PM -0400, Kyle Moffett wrote: >> This seems unlikely to work reliably as the various "v*printf" >> functions modify the va_list argument they are passed. It may >> happen to work on your particular architecture depending on how >> that argument data is passed and stored, but you probably actually >> want to make a copy of the varargs list for the first vsnprintf call. > > I based what I did on how printk works: > > va_start(args, fmt); > r = vprintk(fmt, args); > va_end(args); > > It doesn't call va_* anywhere else. I don't claim to be a varargs > expert, but if I'm wrong, I'm at least wrong the same way that > printk is, so not in any way that's significant for any other > architecture Linux runs on. No, the problem is what happens when you don't have enough space allocated: you call "vsnprintf(s, len, format, args);" and then later call "vsprintf(s, format, args);" with the *SAME* "args". That's what's broken. So this is wrong: > va_list args; > va_start(args, fmt); > r1 = vprintk(fmt, args); > r2 = vprintk(fmt, args); > va_end(args); To fix it, you have 2 options. Option 1: > va_list args; > va_start(args, fmt); > r1 = vprintk(fmt, args); > va_end(args); > va_start(args, fmt); > r2 = vprintk(fmt, args); > va_end(args); Option 2: > va_list args, argscopy; > va_start(args, fmt); > va_copy(argscopy, args); > r1 = vprintk(fmt, argscopy); > va_end(argscopy); > r2 = vprintk(fmt, args); > va_end(args); Now in a function which *receives* a va_list from one of its callers, "Option 1" isn't an option because you don't have the original stack frame, so the result looks like this: > void func1(const char *fmt, ...) > { > va_list ap; > va_start(ap, fmt); > func2(fmt, ap); > va_end(ap); > } > > void func2(const char *fmt, va_list ap) > { > va_list ap2; > va_copy(ap2, ap); > vprintk(fmt, ap2); > va_end(ap2); > vprintk(fmt, ap); > } Cheers, Kyle Moffett - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists