On Tuesday, 9 May 2017 at 06:15:12 UTC, H. S. Teoh wrote:
On Mon, May 08, 2017 at 06:33:08PM +0000, Jerry via Digitalmars-d wrote:


        strncpy(buf, src, sizeof(buf));

Quick, without looking: what's wrong with the above line of code?

Not so obvious, huh? The problem is that strncpy is, in spite of being the "safe" version of strcpy, badly designed. It does not guarantee buf is null-terminated if src was too long to fit in buf! Next thing you know -- why, hello, unterminated string used to inject shellcode into your "secure" webserver!

The "obvious" fix, of course, is to leave 1 byte for the \0 terminator:

        strncpy(buf, src, sizeof(buf)-1);

Except that this is *still* wrong, because strncpy doesn't write a '\0' to the end. You have to manually put one there:

        strncpy(buf, src, sizeof(buf)-1);
        buf[sizeof(buf)-1] = '\0';

The second line there has a -1 that lazy/careless C coders often forget, so you end up *introducing* a buffer overrun in the name of fixing another.

This single problem area (improper use of strncpy) accounts for a larger chunk of code I've audited than I dare to admit -- all just timebombs waiting for somebody to write an exploit for.

Adding to that, strncpy() is also a performance trap. strncpy will not stop when the input string is finished, it will fill the buffer up with 0.
so

char buff[4000];
strncpy(buff, "hello", sizeof buff);

will write 4000 bytes on every call.

The thing with strncpy() is that it's a badly named function. It is named as a string function but isn't a string function. Had it been named as memncpy() or something like that, it wouldn't confuse most C programmers. If I get my C lore right, the function was initially written for writing the file name in the Unix directory strncpy(dirent, filename, 14); or something like that.


Reply via email to