Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How guard against unterminated strings

Tags:

c

In a C program I have a function that writes a message to a log file

LogResult writeLog(const char* format, ...)

That function passes its arguments on to 'vfprintf()' as a 'format' string and a 'va_list'. It just occurred to me that I don't have any control over what would happen if someone were to pass an unterminated string, e.g.

const char unterminatedString[5] = {'h', 'e', 'l', 'l', 'o'};
writeLog("Log message: %s", unterminatedString);

Is there any way to guard against this?

like image 711
jokki Avatar asked Feb 15 '14 22:02

jokki


4 Answers

I assume your log function has its own internal buffer and you know the size of that.

You can then use the vsprintf() functions that specify a buffer size. See Possible buffer overflow vulnerability.

like image 145
Richard Chambers Avatar answered Nov 20 '22 15:11

Richard Chambers


There are many other ways (on top of the one that you've mentioned) for passing an illegal string.

A few examples:

char* unterminatedString;
writeLog("Log message: %s", unterminatedString);

char* unterminatedString = (char*)0xA5A5A5A5;
writeLog("Log message: %s", unterminatedString);

char unterminatedString[] = "abc";
unterminatedString[3] = 'd';
writeLog("Log message: %s", unterminatedString);

int x = -1;
char* unterminatedString = (char*)&x;
writeLog("Log message: %s", unterminatedString);

A legal string must start at a valid memory address, and end (with a 0 character) at a valid memory address. There is no definite way to assert that, except for iterating the string itself, until reaching a 0 character or performing a memory access violation (which is exactly what the vfprintf function does).

like image 34
barak manos Avatar answered Nov 20 '22 13:11

barak manos


const char* does not know the length of the array, it is just an address. So that is not simply possible.

If you want to stay in pure C, you could pass the length int len of the string as an extra argument and check if format[len]==0. I do not really think this is helpful though, it is even worse in my opinion.

Since you flagged this question with C++, you could (and imo should) use std::string:

LogResult writeLog(const std::string& format, ...)

An std::string is always correctly terminated, you can access its underlying C-style string with std::string::c_str().

Note that std::string can store \0-Characters, so functions using an C-style string would stop at the first \0, not necessarily at the end of the std::string.

like image 2
Baum mit Augen Avatar answered Nov 20 '22 15:11

Baum mit Augen


No, there is no way to portably do it.

What you could do is look for this types of bugs using a tool like valgrind.

like image 1
NPE Avatar answered Nov 20 '22 13:11

NPE