Why is strncpy insecure?

56,735

Solution 1

Take a look at this site; it's a fairly detailed explanation. Basically, strncpy() doesn't require NUL termination, and is therefore susceptible to a variety of exploits.

Solution 2

The original problem is obviously that strcpy(3) was not a memory-safe operation, so an attacker could supply a string longer than the buffer which would overwrite code on the stack, and if carefully arranged, could execute arbitrary code from the attacker.

But strncpy(3) has another problem in that it doesn't supply null termination in every case at the destination. (Imagine a source string longer than the destination buffer.) Future operations may expect conforming C nul-terminated strings between equally sized buffers and malfunction downstream when the result is copied to yet a third buffer.

Using strncpy(3) is better than strcpy(3) but things like strlcpy(3) are better still.

Solution 3

To safely use strncpy, one must either (1) manually stick a null character onto the result buffer, (2) know that the buffer ends with a null beforehand, and pass (length-1) to strncpy, or (3) know that the buffer will never be copied using any method that won't bound its length to the buffer length.

It's important to note that strncpy will zero-fill everything in the buffer past the copied string, while other length-limited strcpy variants will not. This may at some cases be a performance drain, but in other cases be a security advantage. For example, if one used strlcpy to copy "supercalifragilisticexpalidocious" into a buffer and then to copy "it", the buffer would hold "it^ercalifragilisticexpalidocious^" (using "^" to represent a zero byte). If the buffer gets copied to a fixed-sized format, the extra data might tag along with it.

Solution 4

The question is based on a "loaded" premise, which makes the question itself invalid.

The bottom line here is that strncpy is not considered insecure and has never been considered insecure. The only claims of "insecurity" that can be attached to that function are the broad claims of general insecurity of C memory model and C language itself. (But that is obviously a completely different topic).

Within the realm of C language the misguided belief of some kind of "insecurity" inherent in strncpy is derived from the widespread dubious pattern of using strncpy for "safe string copying", i.e. something this function does not do and has never been intended for. Such usage is indeed highly error prone. But even if you put an equality sign between "highly error prone" and "insecure", it is still a usage problem (i.e. a lack of education problem) not a strncpy problem.

Basically, one can say that the only problem with strncpy is a unfortunate naming, which makes newbie programmers assume that they understand what this function does instead of actually reading the specification. Looking at the function name an incompetent programmer assumes that strncpy is a "safe version" of strcpy, while in reality these two functions are completely unrelated.

Exactly the same claim can be made against the division operator, for one example. As most of you know, one of the most frequently-asked questions about C language goes as "I assumed that 1/2 will evaluate to 0.5 but I got 0 instead. Why?" Yet, we don't claim that the division operator is insecure just because language beginners tend to misinterpret its behavior.

For another example, we don't call pseudo-random number generator functions "insecure" just because incompetent programmers are often unpleasantly surprised by the fact that their output is not truly random.

That is exactly how it is with strncpy function. Just like it takes time for beginner programmers to learn what pseudo-random number generators actually do, it takes them time to learn what strncpy actually does. It takes time to learn that strncpy is a conversion function, intended for converting zero-terminated strings to fixed-width strings. It takes time to learn that strncpy has absolutely nothing to do with "safe string copying" and can't be meaningfully used for that purpose.

Granted, it usually takes much longer for a language student to learn the purpose of strncpy than to sort things out with the division operator. However, this is a basis for any "insecurity" claims against strncpy.

P.S. The CERT document linked in the accepted answer is dedicated to exactly that: to demonstrate the insecurities of the typical incompetent abuse of strncpy function as a "safe" version of strcpy. It is not in any way intended to claim that strncpy itself is somehow insecure.

Solution 5

A pathc of Git 2.19 (Q3 2018) finds that it is too easy to misuse system API functions such as strcat(); strncpy(); ... and forbids those functions in this codebase.

See commit e488b7a, commit cc8fdae, commit 1b11b64 (24 Jul 2018), and commit c8af66a (26 Jul 2018) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit e28daf2, 15 Aug 2018)

banned.h: mark strcat() as banned

The strcat() function has all of the same overflow problems as strcpy().
And as a bonus, it's easy to end up accidentally quadratic, as each subsequent call has to walk through the existing string.

The last strcat() call went away in f063d38 (daemon: use cld->env_array when re-spawning, 2015-09-24, Git 2.7.0).
In general, strcat() can be replaced either with a dynamic string (strbuf or xstrfmt), or with xsnprintf if you know the length is bounded.

Share:
56,735
stimms
Author by

stimms

I work as a freelance software developer with an interest in distributed systems, CQRS, cloud computing and ice cream. Ice cream most of all.

Updated on July 05, 2022

Comments

  • stimms
    stimms almost 2 years

    I am looking to find out why strncpy is considered insecure. Does anybody have any sort of documentation on this or examples of an exploit using it?

  • rampion
    rampion about 15 years
    good point. So, even with strncpy, make sure the buffer ends with a '\0'.
  • ojrac
    ojrac about 15 years
    +1, but it's good to note that strncpy only insecure when you forget to manually add the null terminator. If you have trouble remembering to,consider a wrapper function, which always sets the final character to '\0' after calling strncpy.
  • RBerteig
    RBerteig about 15 years
    @ojrac, I think that the wrapper is named strncpy_s(), at least for users of Microsoft's C runtime. There's also _wcsncpy_s() for the wide-char enthusiasts.
  • Admin
    Admin almost 15 years
    @RBerteig, note that MS strncpy_s and company are not 1:1 strncpy replacements as they do not zero-fill the buffer. They are a better strcpy although IMHO strl* functions are more versatile and faster. @ojrac, it is still too prone to misuse, for one thing you have to remember both that and to copy (bufsize-1) instead of (bufsize) or have your "rm -Rf /a" turned into "rm -Rf /".
  • Billy ONeal
    Billy ONeal almost 14 years
    @jbcreix: strncpy is not guaranteed to fill the buffer with zeros either.
  • visual_learner
    visual_learner almost 14 years
    "NULL termination" isn't correct. ASCII character \0 is usually written "NUL" to avoid confusion with the NULL pointer.
  • Admin
    Admin almost 14 years
    @Billy ONeal, opengroup.org/onlinepubs/007908775/xsh/strncpy.html , opengroup.org/onlinepubs/009695399/functions/strncpy.html and the C1x draft disagree with you. Unless ANSI C says otherwise, not zero-filling is nonstandard behavior. Then again, Microsoft doesn't support C at all; all they have is a C++ compiler.
  • Sionide21
    Sionide21 almost 11 years
    That link is dead. Is it available somewhere else?
  • Tim
    Tim almost 11 years
    That particular exploit method isn't critical to this answer; you can find several equivalent vulnerabilities through Google. See, for example, Exploring Adjacent Memory Against strncpy.
  • Tushar
    Tushar about 10 years
    @Sionide21: I haved edited the answer but it's under reviews. Following is the link: blogs.msdn.com/b/oldnewthing/archive/2005/01/07/348437.aspx
  • AnT stands with Russia
    AnT stands with Russia over 9 years
    Same problem that in the other answers. strncpy is a conversion function, not a safe-string copying function. It converts zero-terminated strings to fixed-with strings. Fixed-with strings are not generally zero-terminated, which is why the result of strncpy is not supposed to be zero-terminated in general. Just because incompetent code writers often abuse strncpy for "safe string copying" in a basis for the claims of some "insecurity" inherent in strncpy.
  • Ben Voigt
    Ben Voigt over 9 years
    When people say "strncpy is insecure" what they mean is "It doesn't have a pit of success." Which is true.
  • Adrian McCarthy
    Adrian McCarthy over 8 years
    @Chris Lutz: The difference between NUL and NULL has nothing to do with potential confusion between the two. The ASCII null character predates the C macro NULL. In ASCII, control characters are conventionally abbreviated to two or three uppercase characters, so the abbreviation for the null character is NUL. And, in fact, the official Unicode name for U+0000 is "NULL" which coincidentally matches the common C macro.
  • chqrlie
    chqrlie over 5 years
    What does this answer add to the previous ones?
  • VonC
    VonC over 5 years
    @chqrlie Just an illustration than 9 years after the OP, those functions are still so dangerous (and the patch illustrates why) that they are banned from C codebase (like, here, the one from Git)
  • chqrlie
    chqrlie over 5 years
    strncpy is not better than strcpy. strlcpy is useful where it is available and easy to rewrite where it is not.
  • Admin
    Admin over 4 years
    Link is dead. Update?