8 ms·
On the matter of strlcpy/strlcat acceptance by industry
- bitwize 13y agoStrlcpy and strlcat are stupid. Strcpy_s and strcat_s for the win :) They have much better error semantics, do the right thing upon failure (set dst[0] to '\0' if dst is not NULL and return an error code), and if you are working with C++ in Visual Studio, come with template specializations that can infer the length of the destination string. Which is really handy when the compiler substitutes strcpy and strcat calls with calls to strcpy_s and strcat_s with the appropriate implied length :)
- BudVVeezer 13y agoI am entirely uncertain of why this was downmodded. The _s functions are part of the C standard (Annex K), and truly are better replacements for their counterparts. It's unfortunate that the glibc maintainers have shown so little interest in implementing this (optional, to be fair) part of the standard.
- tobiasu 13y agoBecause the argument why they are "stupid" is missing entirely. Much of the second paragraph was edited in later.
- anon1385 13y agoFor a bit of historical context, this is Drepper's 'rationale' for not accepting a patch for strlcpy in glibc: http://www.sourceware.org/ml/libc-alpha/2000-08/msg00053.html http://www.sourceware.org/ml/libc-alpha/2000-08/msg00053.htm...
- sitharus 13y agoAh, there's some classic Drepper. It's so easy when you get to vet every line of source and never have to worry about inexperienced or careless programmers. Personally I much prefer APIs that will fail safe until you know you need the performance of a less safe one, and can spend the time auditing the code.
- saurik 13y agoThese APIs do not "fail safe"; as Kaz Kylheku points out in his reply to Ulrich on that list: > These words make sense. The problem with strlcat and strlcpy is that they assume that it's okay to arbitrarily discard data for the sake of preventing a buffer overflow. The buffer overflow may be prevented, but because data may have been discarded, the program is still incorrect. This is roughly analogous to clamping floating point overflow to DBL_MAX and merrily continuing in the calculation. ;) This is still a bug in your program, and it can still specifically be a security risk; if you want to cap a buffer, you need to fail the operation, not just silently discard some of the data. Further down-thread, here is Ulrich's (I will argue 100% correct) rant: > Dammit, it is not safe. It hides bugs in programs. If a string is too long for an allocated memory block the copying must not simply silently stop. Instead the program must reallocate or signal an error. I can construct you cases where the use of these stupid functions is creating new security problem. I realize it is fun (and sadly part of the zeitgeist at this point) to rag on Ulrich, but a lot of the things he's said over the years have been quite insightful, and you should at least read the full conversation before judging him.
- anon4 13y agoIsn't the point that strlcpy/cat are a better alternative to strncpy/cat, since the latter don't let you know at all that you didn't copy the entire string? And of course, past simple use cases, one would write one's own string library based on strlcpy/cat (for whatever cases in which it's not ok to include string length in the string struct).
- tobiasu 13y agostrl* fail just like any other C function in libc. They return, like snprintf(), the total length of the string and let the programmer deal with it. strlcpy(buf, s, sizeof(buf)) >= sizeof(buf) Rocket science. Ulrichs reputation is well deserved, he worked very hard on it.
- saurik 13y agoIf you are going to do that check, there is almost no value to using this function as you can do a similar check before copying the string. (The only benefit you get is that if you don't know the length of the source string you save having to first calculate it; but that's a performance optimization, not a fundamentally different paradigm.) The thing is, though: no one actually checks that return value, as this idea that using this API is what makes things secure has become zeitgeist. This post from OpenBSD is even making this mistake: they care only that people are using the API, not that they are using it correctly (despite pointing out the truncation issue at the end, they are just analyzing the usage, not the correctness). Just using this API is not a magic bullet: if you are using the API incorrectly, your program is still incorrect, and if you are using it correctly you can just use strcpy correctly. If you don't believe me, this is a really depressing search to perform: site:opensource.apple.com "strlcpy" -"strlcpy.c" -"strlcpy.s" -"strlcpy.3" -"strlcpy.h" OpenSSH doesn't even check strlcpy correctly... 317 /* No MIN_SIZEOF here - we absolutely *must not* truncate the 318 * username (XXX - so check for trunc!) */ 319 strlcpy(li->username, pw->pw_name, sizeof(li->username)); Yeah, that's great: we "absolutely must not" do something, but it's marked as a XXX?!?!?
- liw 13y agoThe non-standard strlcpy can easily be replaced with the standard snprintf. Both can, and almost certainly should, be replaced by a library that takes care of memory allocation for strings. Even a simple one will obliterate all of the problems that the usual style of C string handling has. (http://blog.liw.fi/posts/strncpy/ http://blog.liw.fi/posts/strncpy/ is my rant about this. Others have made the point better, of course.)
- ef47d35620c1 13y agoI agree. C++ solved this problem many years ago. The solution is standard and safe to use everywhere on all platforms. std::string
- nly 13y agoExactly, and it's actually MORE efficient than raw C string handling. Even in C the solution is to give up and use a string handling library that will do a reallocation on append, not risk truncation.
- simias 13y agoThese days if you write C you probably want to be in control of your allocations (and avoid as many as possible). At least that's what I do. There are no excuses for not including strl* functions in all standard C libraries, it's just NIH that causes the status quo. strcpy and friends are broken because they are C string functions that can generate invalid C strings and fail the Principle of Least Astonishment. The strl* variants are safer, easier to debug (it's easier to catch a bogus truncation than a missing \0 that might still execute properly by chance on certain systems/builds but not others) and only requires a couple instructions on top of the existing string copy functions. I have yet to hear a reasonable argument about why they shouldn't be included (no, "horribly inefficient BSD crap" is not a reasonable argument).
- byuu 13y agostrl(cpy|cat)() is quite dangerous to just use blindly as a full replacement for other (mem|str)*(cpy|cat) functions. strlcpy's return value is the length of the source string. So say you have a big 20MB XML document, and as you are scanning along, you use strlcpy() to store a node name or value into another string. Even though you only ask it to copy five bytes, it goes ahead and runs over the rest of the 20MB document simply for a return value you don't (in this case) care about. If you keep doing this over the entire document, your parser will end up with quadratic overhead. strlcat() has the same overhead issue, and its return value is downright cryptic: it is strlen(source) + min(length, strlen(target)). When it tries to compute strlen(), ignoring your requested length parameter, this means it will access out-of-bounds memory if that string is not properly null-terminated. And if you're absolutely paranoid about security, these functions not having both source size and target size parameters gives you a second way to go out-of-bounds. Overall, they're okay functions, but you can easily do a lot better. And since these aren't universally available, if you're going to declare your own cpy/cat functions, you may as well use a better implementation than strl.
- clarry 13y ago> strl(cpy|cat)() is quite dangerous to just use blindly Very true; people have caused serious issues by blindly doing things (supposedly making things secure or else), without bothering to understand what they're doing. However, for the specific (and reasonably common) scenario of dealing with proper C strings, the strl* functions are very simple and easy to use correctly, and their use is easy to audit. > So say you have a big 20MB XML document, and as you are scanning along, you use strlcpy() to store a node name or value into another string. [..] If you keep doing this over the entire document, your parser will end up with quadratic overhead. Right. It is going to be ridiculously slow (and that should be obvious). But this isn't the common scenario that strl* family of functions were designed for (and which a lot of people get wrong with standard C string functions). But chances are in code like this C strings' shortcomings would be problematic anyway. > strlcat() [..] its return value is downright cryptic: it is strlen(source) + min(length, strlen(target)). Sorry but that is just wrong. > When it tries to compute strlen(), ignoring your requested length parameter, this means it will access out-of-bounds memory if that string is not properly null-terminated. It's not "requested length", it's "this many bytes fit in my buffer". These functions are not supposed to validate your input any more than are they supposed to check the validity of your pointers, intent, etc. If you're passing a pointer to something that is not a string (if you don't have a NUL terminator, your array by definition does not contain a string), you have a problem that you shouldn't hope string handling functions to magically cope with. > if you're absolutely paranoid about security, these functions not having both source size and target size parameters gives you a second way to go out-of-bounds. Target size ought to be enough for simple code dealing with actual strings. But if what you're dealing with isn't a string (and you need extra reassurances because you're not sure what it is), then how are you going to compute the source size? But if you can just compute the source size, then you can make sure what you have is a real string.
- jheriko 13y agosomething i find more important than how much people use strlcpy, snprintf etc in terms of safety and easy of use of strings in C is the lack of good implementation of library functions that give you the string length upfront so you can safely make an allocation of the right size to use such a function with.... coupling that with the fantastic level of brokeness of wchar_t*/wcs functions on the Apple platforms and the poor consistency of the Android NDK (%S, %ls... can't remember) and Microsoft's general lack of respect for the standard and desire to encourage their own brand of 'safe' functions and deprecation I find working with strings in a useful way in C to be an enormous pain when it really shouldn't be. This should be embarassing when 'script kiddie' languages like Python, Ruby, JavaScript and co. do a fantastically better job. It has nothing to do with the level of abstraction and everything to do with poor implementation of the standard library on /every platform/. And I am supposed to trust 3rd party libraries when these giants make mistakes with both trivial, yet highly important functionality? It makes me cynical that they want to force me to use their NSStrings, Java string or Platform::String^ crap, which I really don't like to trust because they are bad in their own ways too... how can I trust these people with my strings? C and C++ are ridiculously cross platform and utilitarian, but this area is definitely one of the weakest imo :/ Still, I don't advocate rolling your own, but making things work safely and nicely across platforms is a pain in the arse
- tedunangst 13y agoWhat makes python strings fantastic and java strings crap?
- jheriko 13y agoi think java strings are pretty fantastic too... its the C string library function implementations which are crap. i don't like introducing any dependency when I shouldn't have to - using Java strings on Android is not something I've yet had to do but I suspect I will if I want good working functionality because the wcs* functions in the C stdlib in the NDK are crap. there are a number of performance and aesthetic reasons for not wanting to use java strings as well but they are largely irrelevant imo...
- amadvance 13y agoUsing strlcpy is like suppressing the "Division By Zero" exception and have divisions to return a fake value just to let the program run. In some case this could be even useful, but it's for legacy and sloppy programs that no one bother to really fix. For anything that requires some minimal level of quality the best option is to make the program to intentionally crash if a buffer overflow condition is detect. Exactly like a "Division By Zero".
- clarry 13y agoFor anything that requires some minimal level of robustness, the best option is not to make the program crash when a string is too long to fit in a buffer. This is not a buffer overflow condition. This is not at all like Division By Zero. EDIT: In your world the kernel could panic because someone tried to open() too long a filename. Or should the application trying to open the file crash instead? And an IRC server would crash because my client sent a message with 513 characters. I would rather detect these conditions and do the right thing.
- peterwwillis 13y agoSounds a lot like Theo is making the assumption that most programmers care about security, when in fact, they're probably primarily interested in creating code that works, and making it secure later. It doesn't matter what function you use to copy strings. Hell, you can use strcpy in a way that avoids buffer overflows! If your application is poorly designed, it will be insecure. In this case what we're talking is not doing bounds checking on input before copying data, which will always end up fucking you in one way or another, regardless of what function you use. Going on and on over this function vs that function is a distraction from the bigger problem, which is the overall poor design of many applications.
- clarry 13y ago> Theo is making the assumption that most programmers care about security, when in fact, they're probably primarily interested in creating code that works, and making it secure later. Insecure software is broken software; it doesn't work correctly (unless insecurity is an intended feature, such as in a backdoor). > It doesn't matter what function you use to copy strings. Technically you're right, you can even roll your own loop. However, the purpose of library functions is to make your (and your users' & co-developers') life easier. The strl* functions provide a simple idiom that just works, and it takes less effort than doing arithmetic prior to strcpy/cat calls. It makes it easy for everyone to check that it does indeed work. > In this case what we're talking is not doing bounds checking on input before copying data, which will always end up fucking you in one way or another, regardless of what function you use. The strl* functions are all about doing bounds checking in a simple and compact way while copying data, and they inform you in case the input was too large. They're all about replacing broken (or entirely missing!) hand-rolled bounds checking that you'd write before every strcpy/strcat. Why don't you try audit code that uses strlcat & strlcpy? Grep for these and check that every invocation is correct. Now do the same for code using strcat, strncpy, and strcpy. Check all the arithmetic (which may take up goodness knows how many lines, spread all over the place, in loops, etc.). After a few hundred of these, you should begin to understand why strlcpy and strlcat exist. People have done such massive audits before. And misuse of the standard string functions has indeed caused many many bugs. The secure alternatives weren't invented just for the heck of it; there's actual history behind it.
- eliteraspberrie 13y agoYou probably all know about the mainstream users of these functions, like the Linux kernel, or MacOS, or the other BSD's, and Solaris. In fact the Linux kernel uses both strcpy and strlcpy -- strcpy is used more often. Sometimes strlcpy makes more sense than strcpy, other times not. It's not a popularity contest.
- nly 13y agoEverything about this post by deraadt is wrong. First of all, all of those software projects rolling their own implementation should consider libbsd (installed on my system as a dependency of the Samba client libs, so it should be on most desktop Linux distros already) http://libbsd.freedesktop.org/wiki/ http://libbsd.freedesktop.org/wiki/ Secondly, it's fallacious to point out that lots of people already use these functions and therefore it must be sane and should be encouraged. People used gets() for decades. https://en.wikipedia.org/wiki/Argumentum_ad_populum https://en.wikipedia.org/wiki/Argumentum_ad_populum Thirdly, strlcat and srlcpy are awful. The fact that people have already moved from awful to maybe slightly less awful variants actually means they have some will to improve their code, which should be encouraged. strl* should not be encouraged. You should be strung up (pun intended) if you're not using a modern string handling library in 2014.
- sounds 13y agoPlease add links/references to your preferred string handling library of 2014.
- yarou 13y agoAgain, it's a matter of how you treat strings. Using the standard library functions to deal with strings is lazy, and eventually will cause problems(tm) in the future. It's better to be proactive about it and roll your own functions to deal with it. At worst, you've wasted extra time reimplementing a library function.