Thread safety issue in krb5_verify_init_creds() when passing ccache pointer to null?
Thomas Sondergaard
thomas at sondergaard.cc
Thu May 27 04:52:52 EDT 2021
Hi,
I have a multithreaded application that calls krb5_verify_init_creds() from
multiple threads. Each thread uses its own krb5_context. The code invoked
in each thread looks like something like this:
...
krb5_ccache cc = nullptr;
const auto err = krb5_verify_init_creds(context, &creds,
server_princ, kt, &cc, &opts);
krb5_principal princ;
krb5_cc_get_principal(context, &princ);
...
krb5_cc_close(context, cc);
The program occasionally crashes in the call to krb5_cc_get_principal. I
took a look at krb5_verify_init_creds() and believe I can see that when the
ccache argument is a pointer to null, it hits this code in get_vfy_cred(),
where ccache_arg is my cc above:
if (ccache_arg != NULL && ccache != NULL) {
if (*ccache_arg == NULL) {
ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc);
if (ret)
goto cleanup;
ret = krb5_cc_initialize(context, retcc, creds->client);
if (ret)
goto cleanup;
ret = copy_creds_except(context, ccache, retcc, creds->server);
if (ret)
goto cleanup;
*ccache_arg = retcc;
retcc = NULL;
} else {
ret = copy_creds_except(context, ccache, *ccache_arg, server);
}
}
If I understand this correctly I get a ticket cache "MEMORY:rd_req2", which
is local to the process. So when this function is called from multiple
threads with ccache being a pointer with the value NULL the threads will
stomp on the same ticket cache. Is this correct?
I had a look at the bug history too and found
https://krbdev.mit.edu/rt/Ticket/Display.html?id=3089. This ticket refers
to a thread safety issue related to another ticket cache "MEMORY:rd_req"
that krb5_verify_init_creds() used to use, but which has since been changed
to use krb5_cc_new_unique() in commit 17d690492927ad.
Shouldn't the ticket cache "MEMORY:rd_req2" in get_vfy_cred() be changed to
use krb5_cc_new_unique() too?
https://web.mit.edu/kerberos/krb5-1.18/doc/appdev/refs/api/krb5_verify_init_creds.html
doesn't say anything about who owns the ccache that
krb5_verify_init_creds() creates and returns. What is the proper protocol
for the caller when they are done with the ticket cache? Should they call
krb5_cc_close(context, cc); or krb5_cc_destroy(context, cc)? Will calling
just krb5_cc_close(context, cc) on a ccache created with
krb5_cc_new_unique() cause it to be leaked or will it automatically be
destroyed when all references to it have been closed?
Best regards,
Thomas
More information about the krbdev
mailing list