Blame SOURCES/krb5-krad-remote.patch

8874ae
From a8551b609fd50458ca3c06a9dd345b6cdf18689b Mon Sep 17 00:00:00 2001
8874ae
From: Greg Hudson <ghudson@mit.edu>
8874ae
Date: Tue, 9 Nov 2021 13:00:43 -0500
8874ae
Subject: [PATCH 1/2] Avoid use after free during libkrad cleanup
8874ae
8874ae
libkrad client requests contain a list of references to remotes, with
8874ae
no back-references or reference counts.  To prevent accesses to
8874ae
dangling references during cleanup, cancel all requests on all remotes
8874ae
before freeing any remotes.
8874ae
8874ae
Remove the code for aging out unused servers.  This code was fairly
8874ae
safe as all requests referencing a remote should have completed or
8874ae
timed out during an hour of disuse, but in the current design we have
8874ae
no way to guarantee or check that.  The set of addresses we send
8874ae
RADIUS requests to will generally be small, so aging out servers is
8874ae
unnecessary.
8874ae
8874ae
ticket: 9035 (new)
8874ae
---
8874ae
 src/lib/krad/client.c   | 42 ++++++++++++++---------------------------
8874ae
 src/lib/krad/internal.h |  4 ++++
8874ae
 src/lib/krad/remote.c   | 11 ++++++++---
8874ae
 3 files changed, 26 insertions(+), 31 deletions(-)
8874ae
8874ae
diff --git a/src/lib/krad/client.c b/src/lib/krad/client.c
8874ae
index 6365dd1c6..810940afc 100644
8874ae
--- a/src/lib/krad/client.c
8874ae
+++ b/src/lib/krad/client.c
8874ae
@@ -64,7 +64,6 @@ struct request_st {
8874ae
 
8874ae
 struct server_st {
8874ae
     krad_remote *serv;
8874ae
-    time_t last;
8874ae
     K5_LIST_ENTRY(server_st) list;
8874ae
 };
8874ae
 
8874ae
@@ -81,15 +80,10 @@ get_server(krad_client *rc, const struct addrinfo *ai, const char *secret,
8874ae
            krad_remote **out)
8874ae
 {
8874ae
     krb5_error_code retval;
8874ae
-    time_t currtime;
8874ae
     server *srv;
8874ae
 
8874ae
-    if (time(&currtime) == (time_t)-1)
8874ae
-        return errno;
8874ae
-
8874ae
     K5_LIST_FOREACH(srv, &rc->servers, list) {
8874ae
         if (kr_remote_equals(srv->serv, ai, secret)) {
8874ae
-            srv->last = currtime;
8874ae
             *out = srv->serv;
8874ae
             return 0;
8874ae
         }
8874ae
@@ -98,7 +92,6 @@ get_server(krad_client *rc, const struct addrinfo *ai, const char *secret,
8874ae
     srv = calloc(1, sizeof(server));
8874ae
     if (srv == NULL)
8874ae
         return ENOMEM;
8874ae
-    srv->last = currtime;
8874ae
 
8874ae
     retval = kr_remote_new(rc->kctx, rc->vctx, ai, secret, &srv->serv);
8874ae
     if (retval != 0) {
8874ae
@@ -173,28 +166,12 @@ request_new(krad_client *rc, krad_code code, const krad_attrset *attrs,
8874ae
     return 0;
8874ae
 }
8874ae
 
8874ae
-/* Close remotes that haven't been used in a while. */
8874ae
-static void
8874ae
-age(struct server_head *head, time_t currtime)
8874ae
-{
8874ae
-    server *srv, *tmp;
8874ae
-
8874ae
-    K5_LIST_FOREACH_SAFE(srv, head, list, tmp) {
8874ae
-        if (currtime == (time_t)-1 || currtime - srv->last > 60 * 60) {
8874ae
-            K5_LIST_REMOVE(srv, list);
8874ae
-            kr_remote_free(srv->serv);
8874ae
-            free(srv);
8874ae
-        }
8874ae
-    }
8874ae
-}
8874ae
-
8874ae
 /* Handle a response from a server (or related errors). */
8874ae
 static void
8874ae
 on_response(krb5_error_code retval, const krad_packet *reqp,
8874ae
             const krad_packet *rspp, void *data)
8874ae
 {
8874ae
     request *req = data;
8874ae
-    time_t currtime;
8874ae
     size_t i;
8874ae
 
8874ae
     /* Do nothing if we are already completed. */
8874ae
@@ -221,10 +198,6 @@ on_response(krb5_error_code retval, const krad_packet *reqp,
8874ae
     for (i = 0; req->remotes[i].remote != NULL; i++)
8874ae
         kr_remote_cancel(req->remotes[i].remote, req->remotes[i].packet);
8874ae
 
8874ae
-    /* Age out servers that haven't been used in a while. */
8874ae
-    if (time(&currtime) != (time_t)-1)
8874ae
-        age(&req->rc->servers, currtime);
8874ae
-
8874ae
     request_free(req);
8874ae
 }
8874ae
 
8874ae
@@ -247,10 +220,23 @@ krad_client_new(krb5_context kctx, verto_ctx *vctx, krad_client **out)
8874ae
 void
8874ae
 krad_client_free(krad_client *rc)
8874ae
 {
8874ae
+    server *srv;
8874ae
+
8874ae
     if (rc == NULL)
8874ae
         return;
8874ae
 
8874ae
-    age(&rc->servers, -1);
8874ae
+    /* Cancel all requests before freeing any remotes, since each request's
8874ae
+     * callback data may contain references to multiple remotes. */
8874ae
+    K5_LIST_FOREACH(srv, &rc->servers, list)
8874ae
+        kr_remote_cancel_all(srv->serv);
8874ae
+
8874ae
+    while (!K5_LIST_EMPTY(&rc->servers)) {
8874ae
+        srv = K5_LIST_FIRST(&rc->servers);
8874ae
+        K5_LIST_REMOVE(srv, list);
8874ae
+        kr_remote_free(srv->serv);
8874ae
+        free(srv);
8874ae
+    }
8874ae
+
8874ae
     free(rc);
8874ae
 }
8874ae
 
8874ae
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
8874ae
index 223ffd730..fa012db78 100644
8874ae
--- a/src/lib/krad/internal.h
8874ae
+++ b/src/lib/krad/internal.h
8874ae
@@ -120,6 +120,10 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
8874ae
 void
8874ae
 kr_remote_cancel(krad_remote *rr, const krad_packet *pkt);
8874ae
 
8874ae
+/* Cancel all requests awaiting responses. */
8874ae
+void
8874ae
+kr_remote_cancel_all(krad_remote *rr);
8874ae
+
8874ae
 /* Determine if this remote object refers to the remote resource identified
8874ae
  * by the addrinfo struct and the secret. */
8874ae
 krb5_boolean
8874ae
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
8874ae
index c8912892c..01a5fd2a4 100644
8874ae
--- a/src/lib/krad/remote.c
8874ae
+++ b/src/lib/krad/remote.c
8874ae
@@ -452,15 +452,20 @@ error:
8874ae
     return retval;
8874ae
 }
8874ae
 
8874ae
+void
8874ae
+kr_remote_cancel_all(krad_remote *rr)
8874ae
+{
8874ae
+    while (!K5_TAILQ_EMPTY(&rr->list))
8874ae
+        request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
8874ae
+}
8874ae
+
8874ae
 void
8874ae
 kr_remote_free(krad_remote *rr)
8874ae
 {
8874ae
     if (rr == NULL)
8874ae
         return;
8874ae
 
8874ae
-    while (!K5_TAILQ_EMPTY(&rr->list))
8874ae
-        request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
8874ae
-
8874ae
+    kr_remote_cancel_all(rr);
8874ae
     free(rr->secret);
8874ae
     if (rr->info != NULL)
8874ae
         free(rr->info->ai_addr);
8874ae
-- 
8874ae
2.35.3
8874ae