From: | Arlene Berry <aberry@likewise.com> |
To: | "krb5-bugs@mit.edu" <krb5-bugs@mit.edu> |
Subject: | concurrency issue between krb5_cc_retrieve_cred and krb5_cc_store_cred |
Date: | Fri, 22 Jul 2011 23:44:10 +0000 |
Below is the description as it was originally posted to the krbdev mailing list on 2009/5/4 by Kyle. I cannot find any evidence that an issue was ever filed or that it was fixed. We currently have a couple of #ifdefs which disable the code that turns off KRB5_TC_OPENCLOSE in our local source. The demonstration code uses the same krb5_context for two threads but I'm not convinced that was the case for the actual problem. If it wasn't, then making the MAYBE_OPEN and MAYBE_CLOSE macros in cc_file.c smart enough to temporarily switch the cache from ro to rw might be enough to fix it.
The file descriptor for file based credentials caches is opened in
O_RDONLY or O_RDWR depending on the operation. krb5_cc_store_cred
requires the file to be opened in O_RDWR mode.
The file credential cache has a flag, KRB5_TC_OPENCLOSE, that causes the
credentials cache to be reopened for every element operation. As an
optimization, krb5_cc_retrieve_cred_seq turns off that flag for the
duration of the function:
static krb5_error_code
krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id,
krb5_flags whichfields, krb5_creds *mcreds,
krb5_creds *creds, int nktypes, krb5_enctype *ktypes)
{
...
if (oflags & KRB5_TC_OPENCLOSE)
(void) krb5_cc_set_flags(context, id, oflags & ~KRB5_TC_OPENCLOSE);
...
if (oflags & KRB5_TC_OPENCLOSE)
krb5_cc_set_flags(context, id, oflags);
}
When krb5_fcc_set_flags turns off KRB5_TC_OPENCLOSE, it opens the file
in read only mode. If krb5_cc_store_cred is called at that point, it
will reuse the existing read only file descriptor. When
krb5_cc_store_cred tries to write, it will get EBADF. That error will
then get translated to KRB5_FCC_INTERNAL. So krb5_cc_store_cred only
works when KRB5_TC_OPENCLOSE is on (so the file can be opened in read
write mode).
krb5_cc_retrieve_cred_seq does not lock the cache file for the entire
operation (only for each individual seek and read). This means there is
a race condition between krb5_cc_store_cred and krb5_cc_retrieve_cred.
The attached program illustrates the failure. On my test machine, it
fails on loop 500 or so.
I am using Kerberos 1.6.3, but I don't see anything that would fix this
in the krb5-1-7 branch of your svn.
The file descriptor for file based credentials caches is opened in
O_RDONLY or O_RDWR depending on the operation. krb5_cc_store_cred
requires the file to be opened in O_RDWR mode.
The file credential cache has a flag, KRB5_TC_OPENCLOSE, that causes the
credentials cache to be reopened for every element operation. As an
optimization, krb5_cc_retrieve_cred_seq turns off that flag for the
duration of the function:
static krb5_error_code
krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id,
krb5_flags whichfields, krb5_creds *mcreds,
krb5_creds *creds, int nktypes, krb5_enctype *ktypes)
{
...
if (oflags & KRB5_TC_OPENCLOSE)
(void) krb5_cc_set_flags(context, id, oflags & ~KRB5_TC_OPENCLOSE);
...
if (oflags & KRB5_TC_OPENCLOSE)
krb5_cc_set_flags(context, id, oflags);
}
When krb5_fcc_set_flags turns off KRB5_TC_OPENCLOSE, it opens the file
in read only mode. If krb5_cc_store_cred is called at that point, it
will reuse the existing read only file descriptor. When
krb5_cc_store_cred tries to write, it will get EBADF. That error will
then get translated to KRB5_FCC_INTERNAL. So krb5_cc_store_cred only
works when KRB5_TC_OPENCLOSE is on (so the file can be opened in read
write mode).
krb5_cc_retrieve_cred_seq does not lock the cache file for the entire
operation (only for each individual seek and read). This means there is
a race condition between krb5_cc_store_cred and krb5_cc_retrieve_cred.
The attached program illustrates the failure. On my test machine, it
fails on loop 500 or so.
I am using Kerberos 1.6.3, but I don't see anything that would fix this
in the krb5-1-7 branch of your svn.
Message body is not shown because sender requested not to inline it.