Pete Wilson : Consultant Software Engineer

Lowell MA   978.454.4547   pete at pwilson dot net    April 2008

 Home/Resume  
 Sample code 
 Experimental 
 SNMP 
 CGI notes 
 CSS notes 
 Standards 
 Books 
  Virus Alerts  

st4ncpy4() and st4ncat4(): safer, consistent string copy and concatenation

I adapted the discussion here, heavily condensed, from the paper by Todd C. Miller and Theo de Raadt.


Overview

Successful buffer-overflow attacks continue. For years I've used the length-bounded functions strncpy() and strncat() as a defense, but they're just too porous and error-fertile to do the job. Miller and de Raadt present an alternate, intuitive, and consistent API for safe string copies.

Three Issues

Three problems arise when strncpy() and strncat() are used as "safe" versions of strcpy() and strcat():

The safe way to use strncpy(): pass in one less than the size of the destination string, then terminate that string by hand.

NUL termination: Both functions deal with NUL termination and the length parameter in different, non-intuitive, and confusing ways. It's common to trust that strncpy() NUL-terminates its destination. That's true, but only if the length of the source string is less than the length parameter. And that's a problem when I copy a string to another: the destination terminator can be overwritten and the destination left unterminated.

Truncation: Neither function provides an easy way to detect truncation.

Zero fill: strncpy() takes a performance hit when it zero-fills the remainder of the destination string.

The confusion around the length parameters and the related issue of NUL termination is the most important issue. When I look at some of my early source files I find security holes from misuse of strncat() and strncpy(). I often misunderstood these functions.

The most common mistake I make with strncat() is to use an incorrect length parameter. strncat() guarantees to NUL-terminate the destination, but I need to take care to avoid the off-by-one problem: I mustn't count the space for the NUL in the length calculation. It's not the size of the destination string itself, but rather the amount of space available. I almost always have to compute that value; sometimes I do it incorrectly.

How do st4ncpy() and st4ncat() help things?

Recently I've been using and recommending the functions st4ncpy() and st4ncat(). They present a consistent, unambiguous API to help me write bulletproof code.

NUL termination: Each function guarantees to NUL-terminate its destination string for all strings where the given size is non-zero. Each function takes the full size of the destination string as a length parameter. Usually, it's easy to tell the compiler to compute this value from the sizeof operator.

Truncation: Each function returns the total length of the string it tried to create. For st4ncpy() it's just the length of the source. For st4ncat() it's the length of the destination (before concatenation) plus the length of the source.

To check for truncation, the programmer needs to verify only that the return value is less than the size parameter. If truncation did occur, the number of bytes needed to store the entire string is now known and the programmer can allocate the space to re-copy the strings.

Zero fill: Neither function zero-fills its destination string, apart from the terminating NUL.