Linux 7.2 Kills strncpy: The Six-Year War on a Broken API
After 362 patches, the Linux kernel has completely excised strncpy, cementing strscpy as the modern standard for safe string copying.
The release of Linux Kernel 7.2 marks the end of an era—and the quiet victory of a six-year, 362-commit engineering campaign. With the final merges of the 7.2 cycle, the kernel has completely eliminated the strncpy() API from its codebase, removing the last architecture-specific implementations of the function.
For systems programmers, this is more than a routine cleanup. It is a case study in how API design dictates security. The deprecation of strncpy() and the rise of strscpy() represent a fundamental shift in how developers must handle bounded string copies in C. It proves that "safe" legacy APIs are often anything but, and that fixing API ergonomics is the only sustainable way to eliminate entire classes of memory safety bugs.
The Anatomy of a Broken API
To understand why the kernel spent six years purging strncpy(), we have to look at its history. The function was never actually designed to be a "safe" version of strcpy(). Instead, it was introduced in early Unix to write fixed-width directory entries, which did not require a trailing NUL terminator if the string filled the entire field.
When developers began using strncpy() as a security control to prevent buffer overflows, they inherited two severe architectural flaws:
- No Guaranteed NUL Termination: If the source string is equal to or longer than the destination buffer size (
n),strncpy()copies the bytes but does not write a trailing\0. Any subsequent string operations on the destination buffer will continue reading past its bounds until they hit a random NUL byte in memory, leading to classic information disclosure or crash vulnerabilities. - Mandatory Zero-Filling: If the source string is shorter than
n,strncpy()zero-fills the entire remainder of the destination buffer. While this prevents uninitialized memory leaks, it introduces a massive performance penalty when copying short strings into large buffers.
flowchart TD
strcpy[strcpy
No bounds checking] -->|Buffer Overflow Risk| strncpy[strncpy
Fixed width, zero-fills
No guaranteed NUL]
strncpy -->|BSD Alternative| strlcpy[strlcpy
Guaranteed NUL
Reads entire src, race prone]
strlcpy -->|Modern Kernel Standard| strscpy[strscpy
Guaranteed NUL
Returns count or -E2BIG
Safe & efficient]
strncpy -->|Modern Kernel Standard| strscpy
The Failed Successor: Why strlcpy Didn't Win
To address these flaws, the BSD project introduced strlcpy(). This variant guarantees NUL termination and only copies up to size - 1 bytes. However, strlcpy() introduced its own critical flaw: its return value is the length of the source string, not the number of bytes copied.
To return the length of the source, strlcpy() must run strlen() on the entire source string, even if it is only copying a fraction of it. This design choice introduces two major issues:
- Out-of-Bounds Reads: If the source string is untrusted and lacks a NUL terminator,
strlcpy()will merrily read past the end of the source buffer until it crashes or finds a\0. - Race Conditions: If another thread modifies the source string between the length calculation and the copy, the return value will not match the actual data copied.
Because of these issues, glibc maintainers historically resisted adding strlcpy(), and the Linux kernel community eventually sought a better alternative.
The Modern Standard: strscpy and Friends
Introduced to the kernel in 2015 by Chris Metcalf, strscpy() (string safe copy) solves the design flaws of both strncpy() and strlcpy().
Instead of returning the source length, strscpy() returns the number of bytes actually copied (excluding the trailing NUL). If the source string is truncated, it returns a negative error code (-E2BIG). It never reads past the destination buffer size, never over-reads an untrusted source, and does not waste CPU cycles zero-filling unused destination memory.
For developers refactoring legacy C code, the transition requires a shift in how return values are handled. Consider the legacy pattern:
// Legacy, unsafe strncpy pattern
char dest[32];
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // Mandatory manual termination
Under the modern kernel paradigm, this is replaced by strscpy(), which handles termination automatically and provides clean error propagation:
// Modern, safe strscpy pattern
char dest[32];
ssize_t bytes = strscpy(dest, src, sizeof(dest));
if (bytes == -E2BIG) {
// Handle truncation gracefully
pr_warn("String was truncated during copy\n");
}
The Specialized Toolbelt
Because string copying is not one-size-fits-all, the kernel has introduced specialized helpers to replace the remaining edge cases where strncpy()'s quirky behaviors were actually desired:
| Function | Use Case | Behavior |
|---|---|---|
strscpy() |
Standard NUL-terminated copy | Guarantees NUL termination; returns bytes copied or -E2BIG. |
strscpy_pad() |
NUL-terminated copy with padding | Guarantees NUL termination and zero-fills the remainder of the destination. |
strtomem_pad() |
Non-NUL-terminated fixed-width copy | Copies a string to a fixed-width memory destination and pads with zeroes, without requiring a NUL terminator. |
memcpy_and_pad() |
Bounded copy with explicit padding | Copies a known size and fills the remaining destination space with a specified padding byte. |
memcpy() |
Known-length memory copies | Used when both source and destination sizes are strictly known and bounded. |
The Pragmatic Takeaway
Eliminating strncpy() from a project as massive as the Linux kernel is a testament to the importance of API ergonomics. If an API makes it easy to write insecure code, developers will eventually write insecure code—no matter how many code reviews or static analysis tools you throw at them.
If you are maintaining user-space C or C++ applications, you should treat strncpy() as a code smell. While strscpy() is a kernel-specific API, you can easily implement its semantics in user-space or adopt modern equivalents that enforce strict bounds checking and guaranteed termination. The lesson from Linux 7.2 is clear: stop trying to wrap bad APIs in boilerplate, and start replacing them at the root.
Sources & further reading
- Linux Eliminates the Strncpy API After Six Years of Work, 360 Patches — phoronix.com
- Deprecated Interfaces, Language Features, Attributes, and Conventions — The Linux Kernel 5.10.0-rc1+ documentation — infradead.org
- Ushering out strlcpy() [LWN.net] — lwn.net
- c++ - Why is strncpy insecure? - Stack Overflow — stackoverflow.com
- The Linux Kernel API — The Linux Kernel documentation — docs.kernel.org
Priya covers AI frameworks, developer productivity tooling, and the startup ecosystem across South and Southeast Asia, bringing a researcher's rigour and a practitioner's empathy to every story. She is deeply sceptical of benchmarks and asks hard questions so her readers don't have to.
Discussion 0
No comments yet
Be the first to weigh in.