Re: strcpy versus strncpy

Andy Church (achurch@DRAGONFIRE.NET)
Mon, 02 Mar 1998 22:54:02 -0500 (EST)

Morten Welinder <terra@diku.dk> writes:

>A recent article on BugTraq suggested that using strcpy should
>almost always be considered a bug. That's not right. It is,
>in fact, the wrong way around: strncpy is almost always a bug.

I agree with you in part and disagree with you in part. I agree that
using strcpy should not automatically be considered a bug, and in fact, I
have tried to make that argument myself a few times, with varying levels of
success. However, your claims fail to convince me that the very same
argument does not apply to strncpy. You claim, in summary (to avoid a long
quote):

1. Different size buffers can result in different strings when dealing with
a long file name.

2. Such different strings will have different meanings with respect to the
filesystem.

3. Assumptions should not be made about the size of an object.

The first two are arguably true; it is trivial to create an example in
which a long filename gets truncated so that it refers to a different file.
However, filename buffers are hardly the only place where strncpy/snprintf
are used; for example, in my IRC services program, only a couple out of
dozens of such calls are used with filename buffers (most of the rest deal
with message and identifier length).

Which brings me to your third point. I can agree with it as written
(both here and in the original message); however, I find it a rather weak
claim. Assumptions are generally bad, yes; however, in many cases, the
issue is not making an assumption, but setting a limit. And I _do_ believe
that setting limits is a good thing. Suppose, for example, that you could
create filenames of any length in a filesystem. The following script:

----------------
#!/bin/sh
a="`yes | dd bs=1024 count=1024`" # Create a 1048576-byte variable
i=0
while touch /tmp/$a$i ; do
i=`expr $i + 1`
done
----------------

would happily fill up whatever filesystem /tmp happened to be on. Disk
quotas wouldn't block it--/tmp is owned by root, and filenames are stored
in the directory file, not separately (at least in the Linux ext2
filesystem; I don't know about others). If your file quota was too low to
prevent filling up the filesystem, you could just lengthen the filename.
Or suppose your SMTP server happily accepted strings of any length on its
input, terminated by <CR><LF>. Here's a nifty little memory eater:

----------------
#!/bin/sh
a="dd if=/dev/zero bs=1024 count=1024`" # 1MB of nulls
while true ; do
echo $a | nc victim 25 &
sleep 10 # Give the data a chance to get out
done
----------------

(use netcat instead of telnet to avoid telnet's problem with quitting on
EOF). Granted, this attack would take a huge amount of bandwidth, but you
get the idea.

Moreover, truncation is not, by itself, a bug; it's simply the way a
particular program works. The fact that a program does not do what may
seem intuitive does not mean the program is buggy; for example, I seriously
doubt many people would consider gcc to be buggy solely on the basis that
it fails to compile the following one-line program:

----------------
int main() { puts(NameOfThisProgram); return 0; }
----------------

even though the intention is obvious. (Yes, this is a farfetched example,
but the point is there.) There may of course be other bugs triggered by
truncation, such as symlink-following, but those are bugs on their own.

So, where you have limits, strncpy/snprintf are generally to be
preferred. Where you allocate string buffers dynamically, strcpy/sprintf
will do fine. Neither is a bug in and of itself. And, of course, neither
is a panacea; it's still necessary to write code carefully.

--Andy Church | If Bell Atlantic really is the heart
achurch@dragonfire.net | of communication, then it desperately
www.dragonfire.net/~achurch/ | needs a quadruple bypass.