質問

My question is from a security perspective. I'm in the process of cleaning up some code and I've found the current code has a uncontrolled format string vulnerability; it's passing a string to printf() something like:

void print_it(char * str)
{
    printf(str);

which is obviously considered insecure programming, even gcc will typically ding you with at least some sort of warning:

warning: format not a string literal and no format arguments

Now to "fix" the issue we can make sure what you're getting is treated as a string

printf("%s", str);

But I was wondering if there's any... additional security in using a length specificer as well. Something like:

printf("%.*s", (int)sizeof(str), str);

I can't think of any reason why that would be more secure, but it wouldn't surprise me if I was missing something obvious here.

役に立ちましたか?

解決

Sort of, but not to the extent that modern C shops guard their printf statements this safely. That is used when you are handling non-null terminated strings, which is very common when interacting with Fortran code.

Strictly speaking it would be a security gain in order to guard against runaway reads, perhaps you were about to printf sensitive data following a breached null character.

But

printf("%.*s", (int)sizeof(str), str);

is far worse; you just said "ignore the null character and print out the full contents anyway." Or rather, it's worse unless you're dealing with space-padded strings all the way to their memory's end, which is likely the case if the string came from Fortran.

This however is extremely important:

printf("%s", str);

as printf(str) is a major security flaw. Read about printf attacks using the %n specifier, which writes.

他のヒント

There's some additional security in

printf("%.*s", (int)sizeof(str), str);

since it will print at most sizeof(char*) bytes - usually four or eight - so it won't go and read much of the memory if str points to a char array that is not 0-terminated.

But more typically, it will cut the output short without a good reason to do so.

If you meant

printf("%.*s", (int)strlen(str), str);

that is entirely pointless, since in the cases where a precision for the printf would be necessary, the strlen call will do the same invalid memory accesses.

This idea won't work when the array is passed to a function as arrays decay into a pointer or for any malloc'ed pointer for that matter. Because sizeof(var) is going give the size of the pointer, not the array. So it can't be used in the printf() to specify the length.

This is only applicable to automatic (stack allocated) arrays. So when can this be useful then? I can think of two cases:

1. when you write into array more than the size of the array.

In this case, you have already caused undefined behaviour by writing somewhere that doesn't belong to you. End of story.

2. when you don't have a null-byte at the end of the string (but not crossed the boundary of the array).

In this case, the array has some valid content but not the null byte.. Two possibilities here:

2.a. Using the length specifier is going to print the whole content of the array. So if you access uninitialized bytes in the array (even within its size), it's still going to cause undefined behaviour. Otherwise you have to track the length of the valid content in order to use %s in the printf() along with the length specifier to avoid UB. In this case, you already know the length of the valid content. Hence you can simply null-terminate it yourself rather telling printf() to print only the valid content.

2.b. Let's say, you have initialized the whole array at the beginning with zeros. In the case, the array is going to be a valid string and hence no need of the length modifier.

So I'd say it's not of much use.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top