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