Integer overflow in glibc strncat
sourceware.org
sourceware.org
https://sourceware.org/glibc/wiki/GlibcGit
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86...
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86...
It's been too long since I've done any assembly programming, but this really doesn't appear to have good documentation for maintainability; or anything resembling sufficient documentation at all.
/* Inline corresponding strlen file, temporary until new strcpy
implementation gets merged. */
git blame reveals this is from March 2013. "Temporary" indeed...Temporary code is usually poorly documented, poorly designed, deeply coupled, ugly code. Those are all the exact qualities that make it harder to change than high quality code.
Unless you work very hard, the natural tendency is for all good code (which is correspondingly easy to change) to eventually be replaced with worse code that is harder to replace.
Natural selection applies to code too and, unfortunately, the qualities that lead to longevity are often exactly opposite of the ones that lead to good code.
Also note that SIZE_MAX is an unreasonable input, one would even say it violates preconditions.
The C standard does not place any upper bound on the value of strncat()'s size argument, so an strncat implementation has to work as described for all large values of the argument. It's a bug of the implementation if it doesn't, not a violated precondition.
(Reasoning about C programs has been my day job for several years. Contrary to what many think, it is possible, it only needs that the rules be set in advance and respected.)
Annex K adds rsize_t, RSIZE_MAX, and friends, which restrict inputs to reasonable values. Unfortunately, it doesn't retcon the old functions like strncpy, and worse, no one actually implements it.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms6...
Quite a few recent practical attacks chained what looked like mostly harmless vulnerabilities taken individually.
That, and programs shouldn't be using strncpy or strncat anyway, at least 99% of the time.
strncpy() does that but strncat() does not.
strncat(s1,s2,size) is usually wrong for a different reason: the size argument specifies how many bytes to copy from s2 to the end of s1 (not including the trailing NULL). This means to not buffer overflow your s1 you need to call it like this
strncat(s1, s2, sizeof(s1) - strlen(s1) - 1);
...Which of course everyone forgets. strlcat() is a nice replacement because it does that calculation for you, so you can just do: strlcat(s1, s2, sizeof(s1));
and you won't buffer overflow your s1.That's why it's usually better to just use memcpy or memmove instead.
(1.) The function is supposed to append a string to another, not paste a byte range into another one, leaving extra bytes at the end untouched. Thus the functional result in the test code is correct (i.e. contains the concatenated string with for the usual definition of NUL-terminated strings.)
(2.) The strncat man page (and similarly the C99 standard) says: "[...] the size of dest must be at least strlen(dest)+n+1." It does not specify what happens to unused bytes at the end. It would be incorrect if the function would ever touch more than `strlen(dest)+n+1` bytes in dest, but it doesn't. Supplying a proper value for n in the code (e.g. `strlen(s2)`) shows that it wouldn't overrun the buffer.
Thus supplying SIZE_MAX for `n` would be a bad idea (because the function could overwrite random memory locations) and would probably be incorrect in most cases (e.g. on amd64 with SIZE_MAX=2^64-1 it would only be correct for the null pointer.)
Copying less would obviously be incorrect. I couldn't reproduce that though. (The more case even appears on Ubuntu with eglibc on both x86 and amd64.)
Also, this is probably still a bug and not the anticipated behaviour. (As in: whoever wrote that didn't think of those cases and the overflow happens by mistake.)
No, the standard does not say that. It (both C99 and C11) says, verbatim: "the maximum number of characters that can end up in the array pointed to by s1 is strlen(s1)+n+1." If the manpage on your system says that, that's a fairly serious deficiency in the manpage.
The standard also says "characters that follow it [a null character] are not appended", so copying extra bytes is explicitly not correct.
char buf[100]; buf[0] = '\0'; strcat(buf, "Hello"); strcat(buf, " "); strcat(buf, "World"); strcat(buf, "!\n");
The inefficiency is that each time you do strcat, the existing characters of the string are iterated. So something like a common sequence of building a string by appending little pieces has quadratic inefficiency.
Some programmers consider strncpy() to be inefficient and error prone. If the programmer knows (i.e., includes code to test!) that the size of dest is greater than the length of src, then strcpy() can be used.
One valid (and intended) use of strncpy() is to copy a C string to a fixed-length buffer while ensuring both that the buffer is not overflowed and that unused bytes in the target buffer are zeroed out.