is krb5_cc_initialize() thread safe

Greg Hudson ghudson at mit.edu
Sat Feb 22 03:04:24 EST 2025


On 2/20/25 19:41, Olga Kornievskaia wrote:
> Does this sound like there might be a (solvable) problem in the
> krb5_cc_initiatize() that can guarantee that multiple threads can call
> it simultaneously (on as you noted their own pointer of the
> krb5_ccache structure that they have gotten from doing
> krb5_cc_resolve() and both threads would get a non-error return from
> the function?

Maybe, but (1) it would be awkward, and (2) there are better solutions 
on the gssd end.

Elaborating on (1): POSIX allows you to advisory-lock a file but not a 
pathname.  krb5_cc_initialize() wants to replace the cache file, not 
truncate it, so that it doesn't invalidate iterations over the previous 
generation of the cache.  Without adding a second persistent filesystem 
artifact to hang advisory locks onto, you can't lock around a file 
replacement.  So we would be trying to work around races like:

   T1: unlink
   T1: open-exclusive (success)
   T1: lock new file
   T2: unlink
   T1: writes header (to a no-longer-linked file), unlocks, and returns
   T1 caller: thinks initialization is done, but the file doesn't exist!
   T2: locks file, writes header, unlocks file, and returns

Elaborating on (2): gssd does krb5_get_init_creds_keytab() to get a TGT 
into memory, then krb5_cc_resolve(), krb5_cc_initialize(), and 
krb5_cc_store_cred(), similar to how kinit worked about fifteen years 
ago.  According to the historical semantics of the ccache interface, 
there is inherently a window between the last two steps of this sequence 
where the cache exists but is useless because it contains no TGT.

The sequence used by kinit -k since krb5-1.8 is: krb5_cc_resolve(), 
krb5_get_init_creds_opt_set_out_ccache(), krb5_get_init_creds_keytab(). 
(No krb5_cc_initialize() or krb5_cc_store_cred() calls; that is done by 
krb5_get_init_creds_keytab().)  In krb5-1.20 or later, that will 
automatically use the atomic cache replacement mechanism I described in 
my first reply.  This method also correctly saves some FAST-related 
cache config entries that otherwise get lost.

It might also be possible to use gss_acquire_cred_from() and client 
keytab support to get rid of the whole process of explicitly acquiring 
credentials.  But that would be a more expansive change.

> And I'm also wondering what about other krb5_* functions are they
> "safe" under concurrency or should gssd be doing any krb* api call
> under a lock?

I don't think you need to embark on a project of adding mutex locking 
around libkrb5 API calls.  This is a very specific concurrency issue 
arising from the historic semantics of the libkrb5 credential cache API.


More information about the krbdev mailing list