Problem with va_start()/vsnprintf()

M

Manju

Hi All,

I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues. Any idea why? I
can't control %n as this is contained in the user input string.

Code Snip:

#include <stdio.h>
#include <stdarg.h>

void call_print(const char *fmt, ...)
{
va_list valist;
char tmp[1000];
va_start(valist, fmt);
printf("%s\n",fmt);
strncpy(tmp, fmt, 1000);
if (valist)
{
vsnprintf(tmp, 1000, fmt, valist);
} else
{
snprintf(tmp, 1000, fmt);
}
va_end(valist);
}

main()
{
const char *test = "testing0%x";

call_print(test);
}


Thanks in advance.

Manju
 
M

mark_bluemel

Manju said:
Hi All,

I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues. Any idea why? I
can't control %n as this is contained in the user input string.

It's not at all strange - have you read what "%n" means in a printf()
format string?

I suggest you do so.
 
M

matevzb

Hi All,

I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues. Any idea why? I
can't control %n as this is contained in the user input string.

Code Snip:

#include <stdio.h>
#include <stdarg.h>

void call_print(const char *fmt, ...)
{
va_list valist;
char tmp[1000];
va_start(valist, fmt);
printf("%s\n",fmt);
strncpy(tmp, fmt, 1000);
if (valist)
{
vsnprintf(tmp, 1000, fmt, valist);
} else
{
snprintf(tmp, 1000, fmt);
}
va_end(valist);

}main()
{
const char *test = "testing0%x";

call_print(test);

}Thanks in advance.

Manju
Because you didn't provide the argument to call_print()/printf() - %n
expects a pointer to integer into which it will store the number of
characters written so far. Note that %x expects an integer that you
also didn't provide, which means:
"If there are insufficient arguments for the format, the behavior is
undefined."
So for %n, you would do it like this:
...
int count;
printf ("hello world%n", &count);
...
man printf() or similar for more detail...
 
B

Ben Bacarisse

Manju said:
Hi All,

I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues.

I don't entirely agree. The code you posted has an "issue" in that you
give a %x format with no corresponding argument to convert. %n will
often have a more dramatic effect in that it requires a valid int *
argument, but any miss-match between the format string and the other
arguments can be equally serious.
Any idea why?

Presumably because no valid int * argument was provided.
I can't control %n as this is contained in the user input string.

Then your program is in the lap of the gods (otherwise known as
users). You will have to control either the format or the other
arguments (or both) if you want your program to have defined behaviour.
#include <stdio.h>
#include <stdarg.h>

void call_print(const char *fmt, ...)
{
va_list valist;
char tmp[1000];
va_start(valist, fmt);
printf("%s\n",fmt);
strncpy(tmp, fmt, 1000);
if (valist)
{
vsnprintf(tmp, 1000, fmt, valist);
} else
{
snprintf(tmp, 1000, fmt);
}
va_end(valist);
}

main()
{
const char *test = "testing0%x";

call_print(test);
}
 
M

Manju

Thanks for all the replies.

I'd definitely go through books again to know about %n !

The string I have put is a test string to show that this is the kind of
string I get from user input or from the network. I have know way of
controlling that. All we need is to just treat it as a string and
nothing else (like vsnprintf trying to see %n within the string as a
format string).

Thanks in advance.

Manju
 
M

Manju

Thanks for all the replies.

I'd definitely go through books again to know about %n !

The string I have put is a test string to show that this is the kind of
string I get from user input or from the network. All we need is to
just treat it as a string ("my book" and "test%n%x" should be treated
as just strings) and
nothing else (like vsnprintf trying to see %n within the string as a
format string).

Is there a way to get around this problem (not by parsing the string)?


Thanks in advance.

Manju
I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues. Any idea why? I
can't control %n as this is contained in the user input string.
Code Snip:
#include <stdio.h>
#include <stdarg.h>
void call_print(const char *fmt, ...)
{
va_list valist;
char tmp[1000];
va_start(valist, fmt);
printf("%s\n",fmt);
strncpy(tmp, fmt, 1000);
if (valist)
{
vsnprintf(tmp, 1000, fmt, valist);
} else
{
snprintf(tmp, 1000, fmt);
}
va_end(valist);
}main()
{
const char *test = "testing0%x";

}Thanks in advance.
ManjuBecause you didn't provide the argument to call_print()/printf() - %n
expects a pointer to integer into which it will store the number of
characters written so far. Note that %x expects an integer that you
also didn't provide, which means:
"If there are insufficient arguments for the format, the behavior is
undefined."
So for %n, you would do it like this:
...
int count;
printf ("hello world%n", &count);
...
man printf() or similar for more detail...
 
B

Bill Medland

Manju said:
Thanks for all the replies.

I'd definitely go through books again to know about %n !

The string I have put is a test string to show that this is the kind of
string I get from user input or from the network. All we need is to
just treat it as a string ("my book" and "test%n%x" should be treated
as just strings) and
nothing else (like vsnprintf trying to see %n within the string as a
format string).

Is there a way to get around this problem (not by parsing the string)?

So you are saying you just want to print the string itself? Thank heavens
for that! I thought we were going to have to explain the security
implications of you using a format entered by the user!

How about printf("%s", string)?
Thanks in advance.

Manju
I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues. Any idea why? I
can't control %n as this is contained in the user input string.
Code Snip:
#include <stdio.h>
#include <stdarg.h>
void call_print(const char *fmt, ...)
{
va_list valist;
char tmp[1000];
va_start(valist, fmt);
printf("%s\n",fmt);
strncpy(tmp, fmt, 1000);
if (valist)
{
vsnprintf(tmp, 1000, fmt, valist);
} else
{
snprintf(tmp, 1000, fmt);
}
va_end(valist);
}main()
{
const char *test = "testing0%x";

}Thanks in advance.
ManjuBecause you didn't provide the argument to call_print()/printf() -
%n
expects a pointer to integer into which it will store the number of
characters written so far. Note that %x expects an integer that you
also didn't provide, which means:
"If there are insufficient arguments for the format, the behavior is
undefined."
So for %n, you would do it like this:
...
int count;
printf ("hello world%n", &count);
...
man printf() or similar for more detail...
 
S

Scott Fluhrer

Manju said:
Thanks for all the replies.

I'd definitely go through books again to know about %n !

The string I have put is a test string to show that this is the kind of
string I get from user input or from the network. All we need is to
just treat it as a string ("my book" and "test%n%x" should be treated
as just strings) and
nothing else (like vsnprintf trying to see %n within the string as a
format string).

Is there a way to get around this problem (not by parsing the string)?

Well, if you don't want any of the % formatting characters expanded, why not
do something like:

void call_printf(const char *fmt, ...)
{
char temp[1000];
snprintf( temp, 1000, "%s", fmt );
}

and not bother with the va_list. If you want some formatting characters
expanded, and others not, well, you're pretty much stuck with parsing the
format string (at the very least).

BTW: the statement "if (valist)" isn't portable -- a C compiler can make
va_list a type that can't be compared to 0 (and, in any case, it's not clear
what that if statement is supposed to do even if the compiler accepts it).
Thanks in advance.

Manju
I am facing a strange issue. if the string passed to
va_start()/vsnprintf() contains "%n", there is a segmentation fault. If
it's replaced with any other character, no issues. Any idea why? I
can't control %n as this is contained in the user input string.
Code Snip:
#include <stdio.h>
#include <stdarg.h>
void call_print(const char *fmt, ...)
{
va_list valist;
char tmp[1000];
va_start(valist, fmt);
printf("%s\n",fmt);
strncpy(tmp, fmt, 1000);
if (valist)
{
vsnprintf(tmp, 1000, fmt, valist);
} else
{
snprintf(tmp, 1000, fmt);
}
va_end(valist);
}main()
{
const char *test = "testing0%x";

}Thanks in advance.
ManjuBecause you didn't provide the argument to call_print()/printf() -
%n
expects a pointer to integer into which it will store the number of
characters written so far. Note that %x expects an integer that you
also didn't provide, which means:
"If there are insufficient arguments for the format, the behavior is
undefined."
So for %n, you would do it like this:
...
int count;
printf ("hello world%n", &count);
...
man printf() or similar for more detail...
 
R

Randy Howard

So you are saying you just want to print the string itself? Thank heavens
for that! I thought we were going to have to explain the security
implications of you using a format entered by the user!

There's a surprising number of programs that can be broken (induce evil
behavior) simply by entering format specifiers when prompted for input.


Your post reminds me that I've been meaning to implement a generic
"strip_all_potential_bs_from_string()" function for a while now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top