views:

433

answers:

5

I understand that strlcpy and strlcat were designed as secure replacements for strncpy and strncat, however some people are still of the opinion that they are insecure, and simply cause a different type of problem.

http://en.wikipedia.org/wiki/Strlcpy#Criticism

Can someone give an example of how using strlcpy or strlcat, i.e. a function that always null terminates its strings, can lead to security problems?

Ulrich Drepper and James Antill states this is true, but never provide examples or clarify this point.

+2  A: 

Firstly, strlcpy has never been intended as a secure version of strncpy (and strncpy has never been intended as a secure version of strcpy). These two functions are totally unrelated. strncpy is a function that has no relation to C-strings (i.e. null-terminated strings) at all. The fact that it has the str... prefix in its name is just a historical blunder. The history and purpose of strncpy is well-known and well-documented. This is a function created for working with so called "fixed width" strings (not with C-strings) used in some historical versions of Unix file system. Some programmers today get confused by its name and assume that strncpy is somehow supposed to serve as limited length C-string copying function (a "secure" sibling of strcpy), which in reality is complete nonsense and bad programming practice. C standard library in its current form has no function for limited length C-string copying whatsoever. This is where strlcpy fits in. strlcpy is indeed a true function created for working with C-strings. strlcpy is a very good function that does everything a limited-length copying function should do. The only criticism one can aim at it is that it is, regretfully, not standard.

Secondly, strncat on the other hand, is indeed a function that works with C-strings and performs a limited length concatenation (it is indeed a "secure" sibling of strcat). In order to used this function properly the programmer has to take some special care, since the size parameter this function accepts is not really the size of the buffer that receives the result, but rather the size of its remaining part (also, the terminator character is counted implicitly). This could be confusing, since in order to tie that size to the size of the buffer, the programmer has to remember to perform some additional calculations, which is often used to criticize the strncat. strlcat takes care of these issues, changing the interface so that no extra calculations are necessary. Again, the only basis I see one can criticise this on is that the function is not standard. Also, functions from strcat group is something you won't see in professional code very often due to the limited usability of the very idea of rescan-based string concatenation.

As for how these functions can lead to security problems... They simply can't. They can't lead to security problems in any greater degree than the C language itself can "lead to security problems". You see, for quite a while there was a strong sentiment out there that C++ language has to move in the direction of developing into some weird flavor of Java. This sentiment sometimes spills into the domain of C language as well, resulting in rather clueless and forced criticism of C language features and the features of C standard library. I suspect that we might be dealing with something like that in this case as well, although I surely hope things are not really that bad.

AndreyT
+1  A: 
Alok
`strlcpy` is faster than `memcpy` on many architectures, especially if the `memcpy` copies unnecessary trailing data. `strlcpy` also returns how much data you missed which might allow you to recover faster and with less code.
jbcreix
@jbcreix: my point is that there should be no data to miss, and `n` in my memcpy call is the exact number of bytes to be written, so the efficiency isn't that much of a problem either.
Alok
And how do you get that n? The only n you can know in advance is the buffer size. Of course if you suggest re implementing `strlcpy` each time you need it using `memcpy` and `strlen` that is okay too, but then why stopping at `strlcpy`, you don't *need* a `memcpy` function either, you can copy the bytes one by one. The reference implementation only loops through the data once in the normal case and that is better for most architectures. But even if the best implementation used `strlen` + `memcpy`, that is still no reason to not having to re-implement a secure strcpy again and again.
jbcreix
@jbcreix: I get the `n` by doing `strlen()` on the source string, and as I said, I make sure that the destination has enough space. Of course, if you're okay with the fact that your string may be truncated, you can use `strlcpy()`. Personally, I would rather call `strlen()` on the source and make sure the destination has enough space. So, I am not reimplementing `strlcpy()` at all. The trade off is between speed and copying all data. My point is that `strcpy()` is/can be safe if the programmer is careful. I am not saying that `strlcpy()` is completely useless. (continued...)
Alok
...but it's also not standard. And `strncpy()`, although standard, has deficiencies.
Alok
+3  A: 

Ulrich's criticism is based on the idea that a string truncation that is not detected by the program can lead to security issues, through incorrect logic. Therefore, to be secure, you need to check for truncation. To do this for a string concatenation means that you are doing a check along the lines of this:

if (destlen + sourcelen > dest_maxlen)
{
    /* Bug out */
}

Now, strlcat does effectively do this check, if the programmer remembers to check the result - so you can use it safely:

if (strlcat(dest, source, dest_bufferlen) >= dest_bufferlen)
{
    /* Bug out */
}

Ulrich's point is that since you have to have destlen and sourcelen around (or recalculate them, which is what strlcat effectively does), you might as well just use the more efficient memcpy anyway:

if (destlen + sourcelen > dest_maxlen)
{
    goto error_out;
}
memcpy(dest + destlen, source, sourcelen + 1);
destlen += sourcelen;

(In the above code, dest_maxlen is the maximum length of the string that can be stored in dest - one less than the size of the dest buffer. dest_bufferlen is the full size of the dest buffer).

caf
+3  A: 

There are two "problems" related to using strl functions:

  1. You have to check return values to avoid truncation.

The c1x standard draft writers and Drepper, argue that programmers won't check the return value. Drepper says we should somehow know the length and use memcpy and avoid string functions altogether, The standards committee argues that the secure strcpy should return nonzero on truncation unless otherwise stated by the _TRUNCATE flag. The idea is that people are more likely to use if(strncpy_s(...)).

  1. Cannot be used on non-strings.

Some people think that string functions should never crash even when fed bogus data. This affects standard functions such as strlen which in normal conditions will segfault. The new standard will include many such functions. The checks of course have a performance penalty.

The upside over the proposed standard functions is that you can know how much data you missed with strl functions.

jbcreix
note that `strncpy_s` is not a secure version of `strncpy` but basically a `strlcpy` replacement.
jbcreix
+1  A: 

I think Ulrich and others think it'll give a false sense of security. Accidentally truncating strings can have security implications for other parts of the code (for example, if a file system path is truncated, the program might not be performing operations on the intended file).

jamesdlin