From ccf6ae7e4fab9a1041aed9c491079d8f784769e5 Mon Sep 17 00:00:00 2001 From: Prabhakar Pujeri Date: Sun, 30 Aug 2026 20:23:57 +0530 Subject: [PATCH] gp_creds: fix use-after-free in gp_count_tickets() The original do-while pattern calls krb5_free_cred_contents() on the krb5_creds buffer even when krb5_cc_next_cred() reports KRB5_CC_END, i.e. after the iterator already returned without writing the buffer: the terminal iteration frees either freed or stale contents. Reshape as a while loop whose condition performs the iterator call so the body only runs on success, keep error handling after the loop, and terminate the cursor on the mid-iteration error path (the earlier goto-done skipped krb5_cc_end_seq_get, leaking the cursor). Signed-off-by: Prabhakar Pujeri --- src/gp_creds.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/gp_creds.c b/src/gp_creds.c index 17855b8ec..052248100 100644 --- a/src/gp_creds.c +++ b/src/gp_creds.c @@ -1105,21 +1105,20 @@ uint32_t gp_count_tickets(uint32_t *min, gss_cred_id_t cred, uint32_t *ccsum) goto done; } - do { - err = krb5_cc_next_cred(context, ccache, &cursor, &creds); - if (err != 0 && err != KRB5_CC_END) { - ret_min = err; - ret_maj = GSS_S_FAILURE; - goto done; - } - + while ((err = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) { krb5_free_cred_contents(context, &creds); /* TODO: Should we do a real checksum over all creds->ticket data and * flags in future ? */ (*ccsum)++; - - } while (err == 0); + } + if (err != KRB5_CC_END) { + ret_min = err; + ret_maj = GSS_S_FAILURE; + /* do not leak the cursor when an iteration error occurs */ + krb5_cc_end_seq_get(context, ccache, &cursor); + goto done; + } err = krb5_cc_end_seq_get(context, ccache, &cursor); if (err != 0) {