On Tuesday, February 11, 2003, at 09:54 PM, kevindat_private wrote: > On Tue, Feb 11, 2003 at 11:01:25AM -0800, Kim Reece wrote: >> >> Perhaps an acknowledgement system of some type? ie. having >> parameters for >> "die" or "don't die" or "die if they don't check it", then a function >> the >> user of the library would call to say "return code checked, >> acknowledge so >> I can use the results". Basically a taint system. > > The Unix signal()/sigaction() mechanism provides some inspiration here, > where you have these possibilities with SIG_DFL, SIG_IGN and a handler. > A callback function for string function errors achieves much of the > desired result. > > A caveat - I'd better admit that I haven't looked at the current > proposed library, > so I don't even know its API. I've just been following the discussion > as it's happened here. > Please apply grains of salt accordingly. Fair enough. I've been keeping pretty quiet, letting John field the mails both privately and on the list, but at this point, it feels to me like we're getting to the point of beating a dead horse. I think the discussion has been useful and helped John and I solidify a solution for the error handling problem. One point that I don't think has been made to date is that the vast majority of errors that the library can throw are programming errors--errors that should never occur in production level code. There are exceptions, of course. Most notably, dynamically growing a string could yield an out of memory error. Let's take a quick look at the possible errors in the version that has been released: 1. Expected a safestr_t and got a NULL instead 2. Expected a safestr_t and got something that isn't a safestr_t (which could potentially even cause a read access violation or unaligned data access) 3. Attempting to modify an immutable string 4. Attempting to resize a non-resizable string 5. Out of memory attempting to resize a string 6. Could not open /dev/urandom (or create a crypto context on Windows) 7. Formatting string errors (including misuse of format modifiers; overflowing int on width, precision, or C99 argument specifier; or using %n) 8. Possible double free attempt in safestr_free()/safestr_release() 9. Index out of bounds in safestr_charat()/safestr_setcharat() So there are nine basic errors, at least eight of which can be considered programming errors (out of memory being the straggler here). Arguably, #3, #4, #7, and #9 (perhaps also #8, but that's a bit more of a stretch) could signal a possible attack. For any of the errors possibly thrown when an attack happens, what are you going to do programmatically to defend against or recover from the attack? There's really not much you can do. Not safely anyway because the integrity of your application has been compromised, and you have no idea to what extent. We're back to one possible error that you might be able to do something about, and that's this out of memory problem (persistent little bugger, ain't it?) My personal feeling is that the default behavior of the library should be to abort on any one of these errors. However, it is reasonable to provide a callback mechanism for anybody that does want to make use of it. This callback should receive an error code, the problem string, and the function that's throwing the error. If the callback returns, return an error code to the caller. My strong advice would be for any callback to print an appropriate message, maybe make a log entry or something (though the ability to do so reliably at this point is shaky at best), and abort. It would seem reasonable to handle out of memory conditions in an alternate manner, but you can already do this (mostly--you still can't return an error code and avoid the abort yet) using safestr_setmemfns() and providing a replacement for malloc()/realloc() that handle the out of memory condition (maybe by freeing some reserved memory or something). To sum up: At this point, we do plan to add a callback mechanism for errors. The default callback if none is specified will simply print an error message and abort, much like what already happens at present. If a callback is set and it returns, an error code will be returned from the function that threw the error, leaving it up to the caller to deal with, though the caller will not be given any details of what type of error occurred. It will be up to the callback function to make that information available, possibly by some kind of errno type global variable. > Calls to the various string routines share a lot of common error > conditions, > so much of that can be handled by the callback function, > particularly those parts which are outside the scope of the string > manipulation. > There would also be benefit of removing a lot of the noise from the > code - > the error-return checking that Dana mentioned - so it becomes more > readable. > > The callback function should probably take a few parameters: > - an error code > - perhaps a reference to the string function and the arguments given > to it > - a user supplied argument. My usual practice is a (void *). > Its return value, seen by the string function, would indicate such > things as > whether to retry the operation, or fail and pass the error back to the > original call. > > The user-supplied argument is intentionally versatile, being weakly > typed. > It could be as simple as a flag to indicate a global error condition, > or as complex as a structure pointer holding state information. > While this weak typing is normally seen as lower-level programming > security, > it would be near impossible in many languages to retain the > versatility otherwise. > An alternative could be to have the user define the type of the > parameter > but this only allows that single type within its scope > and it would also have to be defined before the declaration of the > string functions > (ie before the include file), which separates it from where it's used. > > The level of security can the be set by the user. > A simplistic approach would be to call the function and let it > terminate > the process on any error: > > (void) somestringfunc(str, STRING_DEFAULT_ERROR, NULL); > > The semantics of STRING_DEFAULT_ERROR might include some generic > operation before exit(), > perhaps indicated by the user argument, such as printing an error. > Anything more substantial (and maybe even this) is better managed by a > handler. > > The typical use would be where you have error handling managed in a > fairly general way: > > string_error_result_t > handler(int error, string_function_t func, void *arg) > { > string_error_result_t result; > > /* code dependent on the arguments and required error processing */ > return result; > } > > . > . > arg = ...; > (void) somestringfunc(str1, handler, (void *) &arg); > if (anotherstringfunc(str1, str2, handler, (void *) &arg) == > STRING_ERROR_NONE) > (void) somestringfunc(str2, handler, NULL); > . > . > > Finally, STRING_FAIL_ERROR could be used when the caller wants to do > all checking > (or do no checking at all, when it is known there will be no errors). > A NULL callback function would do the same thing. > This would normally be the only case where the function call starts to > disappear > under the noise as it does with the current string functions: > > switch (somestringfunc(str, STRING_FAIL_ERROR, NULL)) > { > case STRING_ERROR_NONE: > break; > > case STRING_ERROR_this: > case STRING_ERROR_that: > /* whatever */ > > default: > /* unknown or unmanaged error */ > } > > (void) anotherstringfunc(str1, str2, NULL, NULL); > > > Whilst all the above examples are in C, there is nothing particularly > fundamental > that requires this. For languages that implement exception handling > natively, > it would be worth investigating that whole approach. > > It's tempting to implement the existing string functions with macros > because those that add to strings all "succeed" anyway: > > #define strcpy(d, s) ((void) safestrcpy(d, s, STRING_FAIL_ERROR, > NULL), d) > > but be aware of the usual pitfalls: > > strcpy(*pps++, something); /* char **pps; */ > strcpy(func(), something); /* where func() has side effects */ > > Kevin
This archive was generated by hypermail 2b30 : Wed Feb 12 2003 - 13:59:58 PST