Kernel subset design issues
ghudson at MIT.EDU
Mon Apr 25 19:46:57 EDT 2011
One of our promises for 1.10 is to make it easier to implement NFSv4
in kernels using our code. Typically a user-space daemon establishes
a GSS security context, then conveys that to the kernel which uses it
to wrap/unwrap/get_mic/verify_mic messages. I have some design issues
I'd like to discuss, in descending order of scope.
1. What to deliver
I'm envisioning that there will be a new directory
src/util/gss-kernel-lib. During "make all" nothing will happen there.
During "make check" the Makefile will copy some source and generated
headers to the current directory, build them with gcc
-I. -DKRB5_KERNEL, link them into a static library named libkgss.a,
and then compile and run some simple tests against it.
This will serve to identify the necessary files for a kernel subset
and to ensure that unwanted dependencies don't creep in. To make the
subset self-contained, I'll move code around and, very judiciously,
use #ifndef KRB5_KERNEL to excise unwanted dependencies from files.
2. The crypto library
To wrap/unwrap/get_mic/verify_mic, we need approximately ten files
from lib/gssapi/krb5 and lib/gssapi/generic, nothing from libkrb5, and
then basically all of libk5crypto. The string-to-key routines and
some surface-level APIs could be excised, but the core encryption and
checksumming code that remains is about 90% of the library. A kernel
integrator would probably want to replace the builtin crypto module
with a module using the kernel's native crypto primitives, and would
definitely want to replace the default PRNG implementation.
The simplest option for us is to include no libk5crypto stuff in
libkgss.a and just link against libk5crypto for tests. That doesn't
provide a lot of guidance to kernel integrators in the crypto area.
We could perhaps provide that guidance in the form of text rather than
build system stuff.
The most complicated option would be to copy in every necessary file
from libk5crypto, including the builtin crypto module and default
PRNG, and use that for testing. The identified set of files would
include a lot of stuff which a real kernel integration would want to
cut out, and util/gss-kernel-lib would become highly dependent on the
structure of libk5crypto. Also, because we have a vtable structure
for each enctype, the surgery necessary to excise string-to-key isn't
very pretty. (Perhaps there's a way to alter the structures to make
Basically, I'm open to ideas in this area.
3. Transporting the GSS security context
Solaris NFS uses a standard
gss_export_sec_context/gss_import_sec_context to transport the GSS
context into the kernel. The serialized GSS context includes a
serialized krb5 context which isn't actually needed by the crypto
routines. The upshot is that there are around 23 files from libkrb5
in the Solaris kernel, none of which have to do with wrapping and
Linux NFS exports a "lucid" sec context
(gss_krb5_export_lucid_sec_context), which is basically a
stripped-down krb5_gss_ctx_id_rec represented in native binary. The
Linux kernel code (which is only distantly based on MIT krb5) converts
that into its own internal context structure.
My preference here is to write code to convert a lucid sec context
into a krb5_gss_ctx_id_rec (relying on the unadvertised fact that
libk5crypto works with a null krb5_context) and include that in
4. k5-int.h and its dependencies
Like most code in our tree, the gss-krb5 code includes k5-int.h, which
relies on about 15 subsidiary headers, including some stuff decidedly
uninteresting to the kernel subset (k5-int-pkinit.h, port-sockets.h,
We can tolerate this, we can use #ifndef KRB5_KERNEL to pare down the
dependencies, or we can further decompose k5-int.h and make it so that
the files in the kernel subset can include only the parts of k5-int.h
5. IOV or not
krb5 1.7 added a bunch of IOV encryption code to gss-krb5. A bunch of
the associated utility functions live alongside non-IOV code in
util_crypt.c. My best understanding is that the IOV interfaces are
not needed in the kernel. I plan to create util_crypt_iov.c and move
the IOV code in there.
6. Nitty details
* The relevant parts of the gss-krb5 code use just three krb5_free_*
functions (krb5_free_data, krb5_free_checksum_contents, and
krb5_free_keyblock). My preference is to just duplicate these in
libkgss rather than mucking about with kfree.c, since their
implementations are short and stable. Another option is to try to
avoid using them, or use the private interfaces from libk5crypto
instead. Or kfree.c could be decomposed, but the decomposition into
"used by NFS kernel code" and "not used by NFS kernel code" isn't
very natural, and putting each function into a separate file would
be kind of awful.
* The gss-krb5 code uses krb5_gss_save_error_info() to save extended
error messages in a global table so that it can be retrieved by
display_status (which will be using a different krb5 context). We
could reduce the need for this by implementing a global
thread-specific krb5 context--something I've wanted to do for a
while--but then we'd just have that framework as an unwanted
dependency. For the moment I'm going to just use KRB5_KERNEL to
null out the definition of save_error_info(). A third option is to
decide that encryption functions never produce very interesting
extended error messages and stop calling save_error_info() in the
* One of the older DES signing algorithms uses a different ivec if the
mech used was gss_mech_krb5_old. gss_mech_krb5_old is defined in
gssapi_krb5.c, which is of course ruinous for limiting dependencies.
My preference is to duplicate the definition in libkgss.a.
We could also try to get rid of the dependency by adding a flag to
the context structure, which gets set at context creation time
(i.e. not in the kernel subset).
Of note: the lucid context structure doesn't contain information
about what mech was used. The Linux NFS code appears not to support
the gss_mech_krb5_old case (that is, it always uses a null IV).
More information about the krbdev