Welcome!

Linux Authors: Katharine Hadow, Hovhannes Avoyan, Anatoly Krivitsky, Pat Romanski, Suresh Krishna Madhuvarsu

Related Topics: Linux

Linux: Article

Variadic Functions: How They Contribute To Security Vulnerabilities and How To Fix Them

Variadic functions are implemented using either the ANSI C stdarg approach or, historically, the UNIX System V vararg approach

One solution that is supported by existing C language standards is for the C language compiler to pass a byte count. The VAX standard calling sequence (partially implemented in its hardware instructions) did pass a count of the number of long words making up the argument list. This was carried over into Alpha, and HP VMS for Alpha still does this.

If byte count were passed, the va_arg() macro (which currently returns the next argument and increments the argument pointer based on the size of the argument) could also decrement the count and force a runtime-constraint violation when a variadic function attempts to access more arguments than have actually been provided.

While the C Standard allows compiler implementations to pass a byte count for variadic functions and not for normal functions, most implementations do not provide a different calling sequence for variadic functions. A common reason to do so is to preserve compatibility between normal and variadic calls.

Unfortunately, it's unreasonable to modify the C language specification to require a byte count, as this change would break binary compatibility between existing applications and libraries. However, it might be possible to introduce a new syntax that could be used to enable the compiler to pass a byte count.

So, for example, instead of:

int printf(const char *format, ...) { }

we might have:

int safe_printf(const char *format, argc+...); { }

or some other, similar syntax.

Type Safety
Knowing the number of arguments does not eliminate the possibility of format string vulnerabilities. For example, the types of those arguments would still not be known, possibly causing confusion if an integer is interpreted as, say, a pointer. However, this information is useful in decreasing the number of such vulnerabilities, as well as increasing the complexity of exploiting those that do exist.

It may be possible to add type safety to variadic functions by placing argument list signatures into symbol tables, for example. It is well within the state of the art to generate code that creates a list of argument types and to generate versions of variadic functions that examine the expected argument type and the actual argument type and generate a runtime error if it finds an unsafe or insecure mismatch. The biggest drawback of this approach is that it might introduce considerable overhead in processing variadic function calls.

Summary and Conclusion
The current implementation of variadic functions in the C programming language is error prone and a major factor in format string vulnerabilities in C and C++. Changes are possible (but in some cases unlikely) within the current constraints of the C language specification. Requiring a stdarg's variant that requires a compiler implementation to provide a byte count is a possible mitigation for format string exploits, but it does not address type safety concerns. A more comprehensive solution that addresses type safety concerns should be researched. In the meantime, programmers should take care that untrusted user input is not incorporated into format specifications for formatted I/O functions and that other uses of variadic functions cannot be used to compromise system security. Better implementations for the average() function, for example, include:

  1. Giving the number of arguments followed by the values average(3, 5, -1, 2)
  2. Giving the number of arguments followed by an array pointer average(3, a)
The first of these implementations is the "poor man's" equivalent to having the compiler automatically pass the argument count (but requires additional programming that may also be erroneous).

Acknowledgments
I would like to acknowledge the contributions of my coworkers, in particular Corey Cohen and Hal Burch, who originally suggested the alternative vararg syntax, and Pamela Curtis, Ken MacInnis, Art Manion, and Jeff Havrilla for their review comments. I would also like to acknowledge the contributions of my fellow members of the SC22 WG14 C standard language committee, including Randy Meyers, John Levine, Martyn Lovell, and Dave Prosser.

More Stories By Robert Seacord

Robert C. Seacord is a senior vulnerability analyst at the CERT/Coordination Center (CERT/CC) at the Software Engineering Institute (SEI) in Pittsburgh, PA, and author of Secure Coding in C and C++ (Addison-Wesley, 2005). An eclectic technologist, Robert is coauthor of two previous books, Building Systems from Commercial Components (Addison-Wesley, 2002) and Modernizing Legacy Systems (Addison-Wesley, 2003).

Comments (1) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
LinuxWorld News Desk 12/06/05 04:18:44 PM EST

LinuxWorld Feature - Variadic Functions: How They Contribute To Security Vulnerabilities and How To Fix Them. C/C++ language variadic functions are functions that accept a variable number of arguments. Variadic functions are implemented using either the ANSI C stdarg approach or, historically, the UNIX System V vararg approach. Both approaches require that the contract between the developer and user of the variadic function not be violated by the user.