Beware of buffer overruns (overflows), where an input value or copied string exceeds the allocated buffer space. Never use gets(), and employ functions such as scanf(), sprintf(), strcpy(), and strcat() with caution (e.g., guarding their use with if
statements that prevent buffer overruns).
Buffer overruns allow techniques such as stack crashing (also known as stack smashing), whereby a malicious user employs a buffer overrun to place carefully coded bytes into a stack frame in order to force the privileged program to execute arbitrary code. (Several online sources explain the details of stack crashing; see also [Erickson, 2008] and [Anley, 2007].) Buffer overruns are probably the single most common source of security breaches on computer systems, as evidenced by the frequency of advisories posted by CERT (http://www.cert.org/) and to Bugtraq (http://www.securityfocus.com/). Buffer overruns are particularly dangerous in network servers, since they leave a system open to remote attack from anywhere on a network.
In order to make stack crashing more difficult—in particular, to make such attacks much more time-consuming when conducted remotely against network servers—from kernel 2.6.12 onward, Linux implements address-space randomization. This technique randomly varies the location of the stack over an 8 MB range at the top of virtual memory. In addition, the locations of memory mappings may also be randomized, if the soft RLIMIT_STACK
limit is not infinite and the Linux-specific /proc/sys/vm/legacy_va_layout
file contains the value 0.
More recent x86-32 architectures provide hardware support for marking page tables as NX (“no execute”). This feature is used to prevent execution of program code on the stack, thus making stack crashing more difficult.
There are safe alternatives to many of the functions mentioned above—for example, snprintf(), strncpy(), and strncat()—that allow the caller to specify the maximum number of characters that should be copied. These functions take the specified maximum into account in order to avoid overrunning the target buffer. In general, these alternatives are preferable, but must still be handled with care. In particular, note the following points:
With most of these functions, if the specified maximum is reached, then a truncated version of the source string is placed in the target buffer. Since such a truncated string may be meaningless in terms of the semantics of the program, the caller must check if truncation occurred (e.g., using the return value from snprintf()), and take appropriate action if it has.
Using strncpy() can carry a performance impact. If, in the call strncpy(s1, s2, n), the string pointed to by s2 is less than n bytes in length, then padding null bytes are written to s1 to ensure that n bytes in total are written.
If the maximum size value given to strncpy() is not long enough to permit the inclusion of the terminating null character, then the target string is not null-terminated.
Some UNIX implementations provide the strlcpy() function, which, given a length argument n, copies at most n - 1 bytes to the destination buffer and always appends a null character at the end of the buffer. However, this function is not specified in SUSv3 and is not implemented in glibc. Furthermore, in cases where the caller is not carefully checking string lengths, this function only substitutes one problem (buffer overflows) for another (silently discarding data).