Re: strlcpy() or strscpy()?
On 1/29/19 3:35 PM, Theo de Raadt wrote: > Martijn van Duren wrote: > >> I think the others have given a decent explanation, but I would like to >> elaborate a little furter. > > I strongly agree with your points, but a few comments. > >> OK, so strscpy won't read any more data from src than count bytes, which >> could save you from reading from the end of the world, where strlcpy >> does assume that src is a NUL-terminated string. > > In C, a string is a NUL-terminated byte sequence. > > If it isn't NUL-terminated, then it isn't a string. > > The language feature "char []" does this, and the string-function subset > of the language RELY upon this. strlcpy follows that same pattern. > > We don't need to say "C string", it is clear enough to say "string". > >> src is clearly not a C-string, since it's not NUL-terminated, but >> there's no problem, since strscpy doesn't throw us over the edge of the >> world. Right? > > Oh my god, strlen also fails. > > Because the object isn't a string. > > That much is clear. > >> The problem is that you don't know what comes after src. It could be >> sensitive information that's now being made available to an attacker, it >> could introduce byte-sequences that completely blow up your terminal. >> You just can't tell for sure. With strlcpy chances are greater that you >> hit a page that's not mapped readable and you generate a SEGFAULT. >> Like Joel said in his talk, it's better to crash and fix the bug. > > Indeed. Most OpenBSD security changes have focused on converting subtle > failure conditions into quick & hard failures, rather than allowing code > to continue running after creating the first instance of damage. > >> Note that I'm not familiar enough with the kernel to make any statement >> on whether on not things work identically there. > > Same thing in the kernel. An aggressive over-access is likely to run > into an unmapped page of memory, and kaboom you crash, which is good because > now you know of a bug you didn't know previously. (1) the bug is less easily > be exploited by an attacker since the common case crashes instead of leaving > a damage artifact in memory, and (2) you know before the attacker, and (3) > it is a priority for repair. > >> If you want to be 100% secure you'd need to keep track of both the src >> length (note that's the length of the string and not of the allocated >> memory) and the destination buffer size and built a set of string >> manipulation functions around that. But that would be a lot more tedious >> to use and one could just as easily overlook to change the length >> attribute upon change, which brings you back to square one. > > The strlcpy paper described this as a design decision. Easy for people > to incorporate the overflow-protection. > > Overflow-detection and handling is another problem. strlcpy also makes > this easy, but a glance at our whole source tree demonstrates how > un-urgent the extended software development community takes that > problem, meaning we seldom receive diffs to add checks. > > As to strlcpy walking the whole string and determining the required > length, that's the same behaviour as snprintf. So strlcpy is mergely > copying the interface of an existing function in the standard. > > The enemy of the good is the perfect, and that enemy foams at the mouth > about imperfection and then turns around and doesn't fix any software. > >> I'm not certain what the author tries to say with "the implementation >> is robust to the string changing out from underneath it", so I won't >> comment on that part. > > It must be grabbing the big string lock. > I did a bit of digging for shits and giggles and found the following: The Linux kernel does contain a version of strlcpy, but it is a bit different from our strlcpy: /** * strlcpy - Copy a C-string into a sized buffer * @dest: Where to copy the string to * @src: Where to copy the string from * @size: size of destination buffer * * Compatible with ``*BSD``: the result is always a valid * NUL-terminated string that fits in the buffer (unless, * of course, the buffer size is zero). It does not pad * out the result like strncpy() does. */ size_t strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); if (size) { size_t len = (ret >= size) ? size - 1 : ret; memcpy(dest, src, len); dest[len] = '\0'; } return ret; } So Linux first does a whole walk over the string to find the length and then does a full copy via memcpy. Then we have strscpy[0], which walks src one word (long) at a time and checks for NUL as it goes along. I can't find any locking, nor can I ascribe any other security measure to it compared to our strlcpy. >From this I can only guess that their statement that their strlcpy is less secure is based around TOCTOU. But I can't see how changing your string in the middle of any operation is going to end well. As
Re: strlcpy() or strscpy()?
Martijn van Duren wrote: > I think the others have given a decent explanation, but I would like to > elaborate a little furter. I strongly agree with your points, but a few comments. > OK, so strscpy won't read any more data from src than count bytes, which > could save you from reading from the end of the world, where strlcpy > does assume that src is a NUL-terminated string. In C, a string is a NUL-terminated byte sequence. If it isn't NUL-terminated, then it isn't a string. The language feature "char []" does this, and the string-function subset of the language RELY upon this. strlcpy follows that same pattern. We don't need to say "C string", it is clear enough to say "string". > src is clearly not a C-string, since it's not NUL-terminated, but > there's no problem, since strscpy doesn't throw us over the edge of the > world. Right? Oh my god, strlen also fails. Because the object isn't a string. That much is clear. > The problem is that you don't know what comes after src. It could be > sensitive information that's now being made available to an attacker, it > could introduce byte-sequences that completely blow up your terminal. > You just can't tell for sure. With strlcpy chances are greater that you > hit a page that's not mapped readable and you generate a SEGFAULT. > Like Joel said in his talk, it's better to crash and fix the bug. Indeed. Most OpenBSD security changes have focused on converting subtle failure conditions into quick & hard failures, rather than allowing code to continue running after creating the first instance of damage. > Note that I'm not familiar enough with the kernel to make any statement > on whether on not things work identically there. Same thing in the kernel. An aggressive over-access is likely to run into an unmapped page of memory, and kaboom you crash, which is good because now you know of a bug you didn't know previously. (1) the bug is less easily be exploited by an attacker since the common case crashes instead of leaving a damage artifact in memory, and (2) you know before the attacker, and (3) it is a priority for repair. > If you want to be 100% secure you'd need to keep track of both the src > length (note that's the length of the string and not of the allocated > memory) and the destination buffer size and built a set of string > manipulation functions around that. But that would be a lot more tedious > to use and one could just as easily overlook to change the length > attribute upon change, which brings you back to square one. The strlcpy paper described this as a design decision. Easy for people to incorporate the overflow-protection. Overflow-detection and handling is another problem. strlcpy also makes this easy, but a glance at our whole source tree demonstrates how un-urgent the extended software development community takes that problem, meaning we seldom receive diffs to add checks. As to strlcpy walking the whole string and determining the required length, that's the same behaviour as snprintf. So strlcpy is mergely copying the interface of an existing function in the standard. The enemy of the good is the perfect, and that enemy foams at the mouth about imperfection and then turns around and doesn't fix any software. > I'm not certain what the author tries to say with "the implementation > is robust to the string changing out from underneath it", so I won't > comment on that part. It must be grabbing the big string lock.
Re: strlcpy() or strscpy()?
I think the others have given a decent explanation, but I would like to elaborate a little furter. The Linux documentation says the following: Preferred to strlcpy since the API doesn't require reading memory from the src string beyond the specified "count" bytes, and since the return value is easier to error-check than strlcpy's. In addition, the implementation is robust to the string changing out from underneath it, unlike the current strlcpy implementation. OK, so strscpy won't read any more data from src than count bytes, which could save you from reading from the end of the world, where strlcpy does assume that src is a NUL-terminated string. So it's not 100% identical to the wrapper around strlcpy. But here also comes a wrong sense of security. Consider the following C code: #include #include char * crapcopy(char *src) { static char dst[1048576]; /* something big -> 1MB*/ strlcpy(dst, src, sizeof(dst)); return dst; } void func(void) { char src[2]; src[0] = 'a'; src[1] = 'b'; printf("%s\n", crapcopy(src)); } src is clearly not a C-string, since it's not NUL-terminated, but there's no problem, since strscpy doesn't throw us over the edge of the world. Right? The problem is that you don't know what comes after src. It could be sensitive information that's now being made available to an attacker, it could introduce byte-sequences that completely blow up your terminal. You just can't tell for sure. With strlcpy chances are greater that you hit a page that's not mapped readable and you generate a SEGFAULT. Like Joel said in his talk, it's better to crash and fix the bug. Note that I'm not familiar enough with the kernel to make any statement on whether on not things work identically there. If you want to be 100% secure you'd need to keep track of both the src length (note that's the length of the string and not of the allocated memory) and the destination buffer size and built a set of string manipulation functions around that. But that would be a lot more tedious to use and one could just as easily overlook to change the length attribute upon change, which brings you back to square one. If documentation states that it requires a NUL-terminated string to function just make damn sure that thing is NUL-terminated, which can best be done by building it with functions that guarantee to NUL- terminate their return string. I'm not certain what the author tries to say with "the implementation is robust to the string changing out from underneath it", so I won't comment on that part. martijn@ On 1/27/19 7:07 AM, 0sjfoij...@firemail.cc wrote: > Recently on LCA2019, Joel Sing made a presentation about "Security > Vulnerability Mitigations"[1] > (very good, btw). He suggests function strlcpy(3) as a secure API. > In the same conference, though, Kees Cook ("Making C Less Dangerous in the > Linux kernel"[2]), > recommends strscpy() as more secure. So, my question is: what's the best to > use? > > Thanks in advance. > > > [1] https://youtube.com/watch?v=9-uNC4-RbQM > [2] https://youtube.com/watch?v=FY9SbqTO5GQ >
Re: strlcpy() or strscpy()?
On Sun, Jan 27, 2019 at 01:07:05AM -0500, 0sjfoij...@firemail.cc wrote: > Recently on LCA2019, Joel Sing made a presentation about "Security > Vulnerability Mitigations"[1] > (very good, btw). He suggests function strlcpy(3) as a secure API. > In the same conference, though, Kees Cook ("Making C Less Dangerous in the > Linux kernel"[2]), > recommends strscpy() as more secure. So, my question is: what's the best to > use? > If anything, strscpy() made things more INsecure, by adding another confusing variation on a well-defined API that has proven itself. strscpy reeks of "Not Invented Here", "Misplaced Hubris" and "Design by committee" syndrome, which happens so very often in Linux-land. Their only saving grace is darwinian: there are so many lemmings over there that ludicrous ideas tend to get replaced by better ideas over time.
Re: strlcpy() or strscpy()?
On Sun, Jan 27, 2019 at 01:07:05AM -0500, 0sjfoij...@firemail.cc wrote: > Recently on LCA2019, Joel Sing made a presentation about "Security > Vulnerability Mitigations"[1] > (very good, btw). He suggests function strlcpy(3) as a secure API. > In the same conference, though, Kees Cook ("Making C Less Dangerous in the > Linux kernel"[2]), > recommends strscpy() as more secure. So, my question is: what's the best to > use? > if i understand correctly, strscpy() works just like strlcpy(): size_t strlcpy(char *dst, const char *src, size_t dstsize); ssize_t strscpy(char *dest, const char *src, size_t count); with the only difference being that strlcpy() returns an unsigned size_t which would be the size it would have written, then strscpy() returns an ssize_t which returns the size or -E2BIG in case of an overflow. quite frankly, i think the claim that strscpy() is safer, easier or that it makes overflow easier to detect is bullshit for lack of a better word given that they both work very similar: if (strlcpy(dest, src, sizeof dest) >= sizeof dest) { // overflow } if (strscpy(dest, src, sizeof dest) == -E2BIG) { // overflow } and that strscpy() is essentially strlcpy() in NIH disguise: ssize_t strscpy(char *dest, const char *src, size_t count) { ssize_t ret; if ((ret = strlcpy(dest, src, count)) >= count) return -E2BIG; return ret; } just my opinion -- Gilles Chehade @poolpOrg https://www.poolp.org tip me: https://paypal.me/poolpOrg
Re: strlcpy() or strscpy()?
0sjfoij...@firemail.cc wrote: > Recently on LCA2019, Joel Sing made a presentation about "Security > Vulnerability Mitigations"[1] > (very good, btw). He suggests function strlcpy(3) as a secure API. > In the same conference, though, Kees Cook ("Making C Less Dangerous in > the Linux kernel"[2]), > recommends strscpy() as more secure. So, my question is: what's the > best to use? > > Thanks in advance. > > > [1] https://youtube.com/watch?v=9-uNC4-RbQM > [2] https://youtube.com/watch?v=FY9SbqTO5GQ Take note: The return value is the number of characters copied (without the trailing NUL byte) - unless the string would not fit into dest, in which case the return value is -E2BIG. 1) It is a linux kernel API only, it does not show up anywhere in userland 2) As it is, it will never go into the standard C library, because that return-value scheme is outside of scope, in particular for a string function strlcpy has significant deployment, and noone is worried about it being being "insecure". The NIH is obviously very strong in linux land.
strlcpy() or strscpy()?
Recently on LCA2019, Joel Sing made a presentation about "Security Vulnerability Mitigations"[1] (very good, btw). He suggests function strlcpy(3) as a secure API. In the same conference, though, Kees Cook ("Making C Less Dangerous in the Linux kernel"[2]), recommends strscpy() as more secure. So, my question is: what's the best to use? Thanks in advance. [1] https://youtube.com/watch?v=9-uNC4-RbQM [2] https://youtube.com/watch?v=FY9SbqTO5GQ