Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Jul 1999 16:58:52 -0700
From:      Mike Smith <mike@smith.net.au>
To:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: OpenBSD's strlcpy(3) and strlcat(3) 
Message-ID:  <199907152358.QAA01894@dingo.cdrom.com>
In-Reply-To: Your message of "Thu, 15 Jul 1999 17:38:16 MDT." <Pine.BSF.3.96.990715173411.19105E-100000@anchovy.orem.iserver.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
> On Thu, 15 Jul 1999, Mike Smith wrote:
> 
> > Ugh.  Take the first example in the paper; it rewrites as
> > 
> > 	len = asprintf(&path, "%s/.foorc");
> > 
> > as opposed to
> > 
> > 	strlcat(path, homedir, sizeof(path));
> > 	strlcat(path, "/", sizeof(path));
> > 	strlcat(path, ".foord", sizeof(path));
> > 	len = strlen(path);
> > 
> > Yes, they're a better str*cat/cpy, but they're not the solution that 
> > they claim to be.
> 
> I don't think that anyone has intended them to be anything other than a
> better replacement for strcpy/strcat than strncpy/strncat (which they
> certainly are).  Sure, you could go around telling people "use snprintf
> instead" or "use asprintf instead", but is that the issue at hand?

In context, yes it is.

The paper talks about dealing with the construction of composite 
strings into static buffers, and points out that there's a real problem 
when you hit the edge of the buffer (overflow, truncation, etc.)

But they don't address the core of the problem, which is the use of a 
static buffer in the first place.  This and other habitual programming 
style items are what's at the real core of the "C is an insecure 
language" argument; people are so used to these idiomatic programming 
techniques they refuse to look for better solutions to the larger 
problem.

Going back to the example they gave, let's put it in context.  You 
probably have something like this:


{
	struct passwd *pw;
	char	buf[MAXPATHLEN];
	FILE	*fp;
	
	pw = getpwuid(getuid());
	strlcpy(buf, pw->dir, sizeof(buf));
	strlcat(buf, "/.appname/", sizeof(buf));
	strlcat(buf, conffilename, sizeof(buf));
	if (strlen(buf) >= sizeof(buf))
		return(error);
	fp = fopen(buf, "r");
	...

That works, as long as MAXPATHLEN is actually long enough.  In this 
particular case it will be (because fopen will fail otherwise), but 
there's no guarantee that you're going to know in advance.

OTOH, here it is with asprintf:

{
	struct passwd *pw;
	char	*buf;
	FILE	*fp;
	
	pw = getpwuid(getuid());
	if (asprintf(&buf, "%s/.appname/%s", pw->dir, conffilename) == -1)
		return(error);
	fp = fopen(buf, "r");
	free(buf);
	...

The latter has a few really clear advantages:

 - you can see what the string is meant to look like.
 - it doesn't matter how long any of the components are.
 - the constructed value is on the heap, so you can return it (just 
   imagine how much nicer ctime() would be if it did this).

-- 
\\  The mind's the standard       \\  Mike Smith
\\  of the man.                   \\  msmith@freebsd.org
\\    -- Joseph Merrick           \\  msmith@cdrom.com




To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199907152358.QAA01894>