Re: KITTEN BOF at IETF 60?
Ken Raeburn <[email protected]> Tue, 23 Mar 2004 14:10:41 -0500
| Newsgroups | gmane.ietf.cat |
|---|---|
| Message-ID | <[email protected]> |
Martin Rex <[email protected]> writes: >> - No guidance concerning thread support. > > Multi-threading is an extremely platform specific mess and thread support > will implementation specific anyway. GSS-API v2 does *NOT* cover > threads at all, and it is quite good that it doesn't even try to > (because it would almost certainly have failed). Perhaps... I'd rather be convinced, though. :-) > The discussion about multi-threading with GSS-API came up a few times > on CAT before GSS-API v2 was completed, but most of the participants > agreed that it would be a too radical change for a mature API and > better be saved for a GSS-API v3 revision that could decide to > break with interoperability. The apparently most often mentioned > lack was an initialization and a final cleanup call. That does make sense. > The problems that I have encountered with multithreading on various > platforms are: > > - on most Unix/Posix platforms single-threaded objects/shared libs > can *NOT* be used/linked with multi-threaded objects/shared libs Huh. I'd gotten the impression that code compiled for a multithreaded environment, but not doing thread stuff itself, was generally safe to use in a single-threaded executable (with code compiled for single-threaded execution). It's just an impression, nothing solid to back it up, but I haven't run into counterexamples yet either. (Which may tell you something about how much actual thread programming I've done.) > - some Unix/Posix platforms offer two different incompatible threading > models and code compiled for one cannot be used together with code > compiled for the other (Reliant Unix 5.45 with DCE- vs Unix98-threads) I think it could be argued that they should be treated as two different execution environments, platforms, configurations, whatever label you want to use. On IRIX, you wouldn't expect O32 and N32 code to work together. On Solaris, you wouldn't expect 32- and 64-bit code to work together. I think the same could be said about threading system options when they can't interoperate in a single process. > - Win32 has a serious deficiency with cleaning up thread-local storage, > since it lacks a destructor in TlsAlloc(). Hooking the THREAD_DETACH > event in DllMain() might be a workaround, but you have to put your > code into a DLL for this to work--but what about cleanup when > UnloadLibrary() is used before the threads terminate ... Yep, currently I'm expecting to implement a TLS layer for Windows which catches both thread termination and library unloading, and frees the appropriate data. Not pretty. > - some platforms are still stuck on old draft4 Posix threads > (IBM's OS/390 Open Edition alias z/OS, and OS/400) I don't think any threaded-environment specification for GSS-API should be at a level where it would care about this. Only the general model and available functionality should matter. E.g., is it possible to guarantee that either multiple simultaneous accesses to this object are safe or the library can enforce serialization of the accesses, so that the application code needn't care which is the case? > To offer such a functionality, an implementation would either use > a global locking or a handle-specific locking itself, and it would > have to always use it, even if the application did serialize or > wasn't multithreaded at all. Yes, though in some single-threaded environments that can be optimized somewhat (e.g., use weak references and check for null pointers; stub functions that always return success indications but do no work). > In the POSIX thread spec there is a rather low upper limit on the number > of Mutexes that a threads implementation must be able to support. I'd be surprised if a shim layer couldn't be implemented within the library that relies only on one or two mutexes and condition variables. It wouldn't be efficient, or pretty, but if the implementation does impose such serious restrictions, you can expect to make some sacrifices. > If a mechanism wanted to offer such functionality, then it would be > appropriate if the mechanism offered special locking calls that > would lock operations on the handle and can be used by the > application. Similar to GetDC()/ReleaseDC() on Microsoft Windows platforms. Except that the goal, I think, is to allow parallel execution within the mechanism when the implementation can allow it, rather than to give the application a way of preventing parallel execution regardless of the safety of the implementation. > The more common situation than two independent threads calling > gss_get_mic() on the same context would be two independent threads > for each direction of the communication (incoming/outgoing) so that > one thread calls gss_get_mic() on the same context handle on which > the second thread calls gss_verify_mic() (analogous with wrap/unwrap). Ah, yes, that's probably a better example. > Btw. have you checked the constraints of OpenSSL when calling > SSL_Read and SSL_Write on the same SSL handle in two independent > threads (I haven't)? Poking around a little, I found http://www.mail-archive.com/[email protected]/msg34106.html which suggests that SSL_Write may do some renegotiation, involving reading from the socket, so they're not safe to combine that way. > A portable application will assume a non-threadsafe gssapi mechanism > and therefore have to serialize *all* gssapi calls. With mechanisms that can involve non-trivial delays in acquiring credentials or whatnot, that's a rather unappealing situation. > I hardly use const even today. I certainly didn't use it back then. > The GSS-API header file which we use for our application doesn't > have const anywhere, probably because it was nailed down early 1996 :) So, you're not even using the header file in the C-bindings spec? Are you still arguing that the spec is fine as is? :-) > One of the situations where OIDs might be initially dynamic is > plug-n-play multimechanism schemes where the glue layer figures > out OIDs and OID_sets at runtime. But as there is no (more) > gss_release_oid() call, the OID needs to exhibit "const" behaviour > once it has been returned to the application caller via any of > the gssapi calls. Sounds like a good use for phrases like "MUST" and "implementation-defined behavior", instead of "should". > For our application we're using our own header file (one single header > file for *ALL* of our platforms). Hardly any platform that we use > for building our code comes with a gssapi mechanism on-board, and > neither do we install one. Ahh... > Our application explicitly does NOT use the X/Open stuff, since that > is a royal PITA, and unfortunately on 64-bit platforms tend to be > incompatible the OID/OID_set "fallback definitions" in the > gssapi v2 sample header file. And still you're happy with the current C bindings? >> - Is an implementation allowed to define any of these functions as >> macros as well (a la C '89, which generally allows it but requires >> that an addressable function be available as well). >> >> For example: >> #define gss_wrap(a,b,c,d,e,f,g) \ >> ({ /* statement expression - gcc extension */ \ >> gss_ctx_id_t _ctx = (b); /* no multiple evaluation */ \ >> (_ctx->ops->wrap(a,_ctx,c,d,e,f,g)); \ >> }) > > YUCK! Yeah, well.... Perhaps a better example would be a macro expansion to invoke a special compiler support function that causes a trap into shared library support code, with the shared library number and function table index number loaded into special registers. It could save code space and stack space compared to calling another function linked into each executable which does the trap. This might be realistic, on a platform like PalmOS, where both code and stack space are at a premium. Not pretty, but there are valid reasons for it. > Besides that wouldn't work with binary plug'n'play mechanisms > (using shared libraries) it is also distasteful. Sure, in this case I was looking at the API, not the ABI, and assuming that the implementor doesn't care about ABI portability. Actually, if you were doing plug-and-play loadable *mechanisms*, rather than swappable complete implementations, I would kind of expect one common implementation technique would be for the main GSSAPI implementation (mainly a glue layer, called directly by the application) to supply a context which has a table of operations and a handle on a security context supplied by the mechanism actually in use. After all, if the mechanisms are allowed to keep the security context opaque, the glue layer needs something additional to track which mechanism is in use for a given security context. > I consider every code seriously broken which reveals internal implementation > detail in the API header file or which performs recursion through its external > programming API so that inside the function you cannot immediately distinguish > a genuine call from the application from an internal use or recursion. Distateful, sure, but I'm not sure I'd agree with "broken", unless you are trying to conform to some ABI. And I don't think it's good enough reason to prohibit an implementor from choosing to do things that way. >> - The description of equality comparisons in section B.3 makes me >> shudder. I'm not even sure what it means. As far as I can tell, if >> your machine lets you have two objects (pointers, integers, floats) >> that compare equal with "==" despite having some bits that are not >> identical, then you have to fix up those bits to always be equal. > > B.3 says: > For binary portability, additional constraints are required. The > following is an attempt at defining platform-independent constraints. > > Why does this make you shudder? The decription that follows this is > more-or-less the assumptions that must be met so that the *independent* > header files of the application programmer and the gssapi mechanism > programmer will smoothly interoperate when the two binaries > (exe-application and shared lib-mechanism) meet in the wild. What's wrong with, "if you want to check for equality, use =="? Why does memcmp have to be applicable to the storage holding the pointer/arithmetic values? (This == vs memcmp stuff has nothing to do with the contents of the object referenced by the handle.) >> - If you want to make recommendations about ABI compatibility, how >> about suggesting *either* pointer or arithmetic type for handles, >> and not giving the implementation the choice. Not only is it valid >> for pointers and arithmetic types to be passed and returned >> differently, there is at least one platform where pointers and >> numbers *are* returned differently. Also, floating-point values are >> "arithmetic", and are often passed differently from both integers >> and pointers. > > It really doesn't matter how it is passed. > > It is about interoperability when the two binaries (exe-app and > shared lib-mechansim) have been *independently* built with differing > definitions for e.g. gss_ctx_id_t. > > So even if the application treats it as a pointer and the gssapi > mechanism actually uses an "int" they both should interoperate! It has to be passed by the caller in the same place that the callee is going to look for it. The C type (integral vs floating vs pointer) can change that location. If the caller and callee disagree, the value will not be passed properly on some platforms. > Actually I'm using OM_uint32 everywhere in the header and my application > code, but I do *NOT* use the X/Open definitions or header files anywhere > -- actually the X/Open definitions would cause serious incompatibilities > on some platforms... And you nicely sidestep my whole issue on namespaces... :-) > I think that a GSS-API v2 spec that wants to advance to draft standard > (which may well be independent of KITTEN going for GSS-API v3), > then the refined spec should clearly outline that channel bindings > are optional for the gssapi mechanism to implement and optional > for the application to use and it should give a warning what > mechanisms should do if one peer supplied/supports channel bindings > and the other doesn't... (in order to document existing practice). For a standard, it should be clear and concise (even if clearly "implementation-defined", i.e., unuseable in portable apps), or removed. > The issue of multithreading came up several times on CAT, but was never > thoroughly discussed because it was considered out-of-scope for v2 > and there was little experience with multi-threading issues (but > a lot of known pitfalls). I should try to dig up some of those old discussions.... > Ted Ts'o mentioned once that the MIT Kerberos codebase was not written > with multi-threading in mind and that he was not convinced that the > code could be made thread-safe with only a small amount of changes, > but rather require serious and tough work. Some of the work (adding a context we can hang data off of that might get modified) was done years ago. Some other work I'm doing now.... > Even with the libc loading problem solved on a few platforms, > there still is the issue of traditional > extern int errno; > vs > extern int *___errno(); > #define errno (*(___errno())) > > as a difference between single and multi-threaded code and > this is probably an issue for multi-threaded apps using > a gssapi mechanism that was compiled single-threaded. As I indicated above, I think this implies that single-threaded and multi-threaded should be treated as two different environments, and the GSSAPI code (along with lots of other code) built for each (and sparcv7 vs sparcv9, or o32 vs n32 vs n64, etc). For a given environment, if it doesn't support threads, we're done. If an environment does support threads ... then the question becomes whether such environments have enough in common that we can say some general things about how the implementation ought to behave. Ken -++**==--++**==--++**==--++**==--++**==--++**==--++**== This message was posted through the Stanford campus mailing list server. If you wish to unsubscribe from this mailing list, send the message body of "unsubscribe ietf-cat-wg" to [email protected]