Kernel subset design issues

ghudson@MIT.EDU 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
it prettier.)

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
unwrapping messages.

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,
krb5/preauth_plugin.h, etc.).

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
they need.

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
  wrap/unwrap/get_mic/verify_mic code.

* 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 mailing list