Skip to content

gp_creds: fix use-after-free in gp_count_tickets() - #133

Open
prabhakarpujeri wants to merge 1 commit into
gssapi:mainfrom
prabhakarpujeri:fixes
Open

gp_creds: fix use-after-free in gp_count_tickets()#133
prabhakarpujeri wants to merge 1 commit into
gssapi:mainfrom
prabhakarpujeri:fixes

Conversation

@prabhakarpujeri

Copy link
Copy Markdown

The counting loop in gp_count_tickets() calls krb5_free_cred_contents(&creds) and increments the counter even when krb5_cc_next_cred() has already failed — including KRB5_CC_END, where it then continues iterating.

  • Empty ccache: free of an uninitialized krb5_creds.
  • Otherwise: the last credential's contents get freed a second time, and *ccsum comes out one too high.

Only free and count after a successful fetch, and leave the loop at KRB5_CC_END.

Built clean with --disable-public-libraries etc. default options (-Wall -Wextra quiet), and the counting behavior was traced for the empty-ccache, zero-ticket and multi-ticket cases against the MIT Kerberos semantics of krb5_cc_next_cred() (KRB5_CC_END is the normal end-of-cache signal and must not count nor free).

@simo5 simo5 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nitpick but otherwise ok

Comment thread src/gp_creds.c Outdated
}

do {
for (;;) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we are going to switch to a for loop, then please use:

for (err = 0; err == 0;
     err = krb5_cc_next_cred(context, ccache, &cursor, &creds)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact we can actually write this as:

for (err = 0; err == 0;
     err = krb5_cc_next_cred(context, ccache, &cursor, &creds)) {
    if (err == 0) {
        krb5_free_cred_contents(context, &creds);
        (*ccsum)++;
    }
}
if (err != KRB5_CC_END) {
    ret_min = err;
    ret_maj = GSS_S_FAILURE;
    goto done;
}

^ This is my preferred and more understandable form.

The loop over the ccache calls krb5_free_cred_contents() and
increments the counter even when krb5_cc_next_cred() has already
returned KRB5_CC_END.  On an empty cache this frees an uninitialised
krb5_creds, and after N tickets it frees the last credential's contents
a second time and counts one entry too many.

Only free and count on a successful fetch, and leave the loop when the
end of the cache is reached.

Signed-off-by: Prabhakar Pujeri <prabhakar.pujeri@dell.com>
@prabhakarpujeri

Copy link
Copy Markdown
Author

Thanks Simo — applied exactly that form in e45faca (amended): the loop initializer/step drives krb5_cc_next_cred(), the body only frees+counts on success, and the KRB5_CC_END / error check sits after the loop with the existing TODO comment kept. Clean build with -Wall -Wextra (warnings-as-if-clean).

@simo5

simo5 commented Sep 3, 2026

Copy link
Copy Markdown
Member

Looks like this change still has some issues, please test locally

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants