Submitted By: Robert Connolly (ashes) Date: 2006-08-15 Initial Package Version: 2.4 Upstream Status: Rejected Upstream http://sources.redhat.com/ml/libc-alpha/2000-08/msg00052.html Origin: OpenBSD, then see the url above, the ported to Owl/Openwall. http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/glibc/\ glibc-2.3.5-openbsd-strlcpy-strlcat.diff Then I retrieved the latest copies of strlcat.c and strlcpy.c from OpenBSD-cvs, which had trivial changes. Description: http://www.courtesan.com/todd/papers/strlcpy.html diff -Naur glibc-2.4.orig/manual/strlcpy.3 glibc-2.4/manual/strlcpy.3 --- glibc-2.4.orig/manual/strlcpy.3 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.4/manual/strlcpy.3 2005-08-06 03:24:19.000000000 +0000 @@ -0,0 +1,186 @@ +.\" $OpenBSD: strlcpy.3,v 1.18 2005/08/06 03:24:19 jaredy Exp $ +.\" +.\" Copyright (c) 1998, 2000 Todd C. Miller +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd June 22, 1998 +.Dt STRLCPY 3 +.Os +.Sh NAME +.Nm strlcpy , +.Nm strlcat +.Nd size-bounded string copying and concatenation +.Sh SYNOPSIS +.Fd #include +.Ft size_t +.Fn strlcpy "char *dst" "const char *src" "size_t size" +.Ft size_t +.Fn strlcat "char *dst" "const char *src" "size_t size" +.Sh DESCRIPTION +The +.Fn strlcpy +and +.Fn strlcat +functions copy and concatenate strings respectively. +They are designed +to be safer, more consistent, and less error prone replacements for +.Xr strncpy 3 +and +.Xr strncat 3 . +Unlike those functions, +.Fn strlcpy +and +.Fn strlcat +take the full size of the buffer (not just the length) and guarantee to +NUL-terminate the result (as long as +.Fa size +is larger than 0 or, in the case of +.Fn strlcat , +as long as there is at least one byte free in +.Fa dst ) . +Note that a byte for the NUL should be included in +.Fa size . +Also note that +.Fn strlcpy +and +.Fn strlcat +only operate on true +.Dq C +strings. +This means that for +.Fn strlcpy +.Fa src +must be NUL-terminated and for +.Fn strlcat +both +.Fa src +and +.Fa dst +must be NUL-terminated. +.Pp +The +.Fn strlcpy +function copies up to +.Fa size +- 1 characters from the NUL-terminated string +.Fa src +to +.Fa dst , +NUL-terminating the result. +.Pp +The +.Fn strlcat +function appends the NUL-terminated string +.Fa src +to the end of +.Fa dst . +It will append at most +.Fa size +- strlen(dst) - 1 bytes, NUL-terminating the result. +.Sh RETURN VALUES +The +.Fn strlcpy +and +.Fn strlcat +functions return the total length of the string they tried to create. +For +.Fn strlcpy +that means the length of +.Fa src . +For +.Fn strlcat +that means the initial length of +.Fa dst +plus +the length of +.Fa src . +While this may seem somewhat confusing, it was done to make +truncation detection simple. +.Pp +Note, however, that if +.Fn strlcat +traverses +.Fa size +characters without finding a NUL, the length of the string is considered +to be +.Fa size +and the destination string will not be NUL-terminated (since there was +no space for the NUL). +This keeps +.Fn strlcat +from running off the end of a string. +In practice this should not happen (as it means that either +.Fa size +is incorrect or that +.Fa dst +is not a proper +.Dq C +string). +The check exists to prevent potential security problems in incorrect code. +.Sh EXAMPLES +The following code fragment illustrates the simple case: +.Bd -literal -offset indent +char *s, *p, buf[BUFSIZ]; + +\&... + +(void)strlcpy(buf, s, sizeof(buf)); +(void)strlcat(buf, p, sizeof(buf)); +.Ed +.Pp +To detect truncation, perhaps while building a pathname, something +like the following might be used: +.Bd -literal -offset indent +char *dir, *file, pname[MAXPATHLEN]; + +\&... + +if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname)) + goto toolong; +if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname)) + goto toolong; +.Ed +.Pp +Since it is known how many characters were copied the first time, things +can be sped up a bit by using a copy instead of an append: +.Bd -literal -offset indent +char *dir, *file, pname[MAXPATHLEN]; +size_t n; + +\&... + +n = strlcpy(pname, dir, sizeof(pname)); +if (n >= sizeof(pname)) + goto toolong; +if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n) + goto toolong; +.Ed +.Pp +However, one may question the validity of such optimizations, as they +defeat the whole purpose of +.Fn strlcpy +and +.Fn strlcat . +As a matter of fact, the first version of this manual page got it wrong. +.Sh SEE ALSO +.Xr snprintf 3 , +.Xr strncat 3 , +.Xr strncpy 3 +.Sh HISTORY +The +.Fn strlcpy +and +.Fn strlcat +functions first appeared in +.Ox 2.4 . diff -Naur glibc-2.4.orig/string/Makefile glibc-2.4/string/Makefile --- glibc-2.4.orig/string/Makefile 2006-01-10 00:11:53.000000000 +0000 +++ glibc-2.4/string/Makefile 2006-08-16 02:37:07.000000000 +0000 @@ -40,7 +40,13 @@ addsep replace) \ envz basename \ strcoll_l strxfrm_l string-inlines memrchr \ - xpg-strerror + xpg-strerror \ + strlcat strlcpy + +# These routines will be omitted from the libc shared object. +# Instead the static object files will be included in a special archive +# linked against when the shared library will be used. +static-only-routines = strlcat strlcpy # Gcc internally generates calls to unbounded memcpy and memset # for -fbounded-pointer compiles. Glibc uses memchr for explicit checks. diff -Naur glibc-2.4.orig/string/string.h glibc-2.4/string/string.h --- glibc-2.4.orig/string/string.h 2004-10-18 04:17:12.000000000 +0000 +++ glibc-2.4/string/string.h 2006-08-16 02:37:07.000000000 +0000 @@ -348,6 +348,24 @@ extern char *strsep (char **__restrict __stringp, __const char *__restrict __delim) __THROW __nonnull ((1, 2)); + +/* + * Appends __src to string __dst of size __n (unlike strncat, __n is the + * full size of __dst, not space left). At most __n-1 characters + * will be copied. Always NUL terminates (unless __n <= strlen(__dst)). + * Returns strlen(__src) + MIN(__n, strlen(initial __dst)). + * If retval >= __n, truncation occurred. + */ +extern size_t strlcat (char *__dst, __const char *__src, size_t __n) + __THROW __nonnull ((1, 2)); + +/* + * Copy __src to string __dst of size __n. At most __n-1 characters + * will be copied. Always NUL terminates (unless __n == 0). + * Returns strlen(__src); if retval >= __n, truncation occurred. + */ +extern size_t strlcpy (char *__dst, __const char *__src, size_t __n) + __THROW __nonnull ((1, 2)); #endif #ifdef __USE_GNU diff -Naur glibc-2.4.orig/string/strlcat.c glibc-2.4/string/strlcat.c --- glibc-2.4.orig/string/strlcat.c 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.4/string/strlcat.c 2006-08-16 02:37:07.000000000 +0000 @@ -0,0 +1,55 @@ +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff -Naur glibc-2.4.orig/string/strlcpy.c glibc-2.4/string/strlcpy.c --- glibc-2.4.orig/string/strlcpy.c 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.4/string/strlcpy.c 2006-08-16 02:37:07.000000000 +0000 @@ -0,0 +1,51 @@ +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +}