From 038793c3083f44c4fb62626c12f80c80147029cf Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@cryptomilk.org>
Date: Fri, 11 Oct 2024 12:45:13 +0200
Subject: [PATCH] Fix unlikely password change leak

In kpasswd_sendto_msg_callback(), if getsockname() does not reveal the
local address, a copy of the first local address's contents is made
and never freed.  Instead of making an allocated copy of the address
contents, make a shallow copy of the whole address.  Delay freeing the
address array until the end of the function so that alias pointer made
by the shallow copy remains valid.

[ghudson@mit.edu: further simplified code; rewrote commit message]
---
 src/lib/krb5/os/changepw.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
index c592325..9cae409 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -115,6 +115,7 @@ kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message)
     struct sendto_callback_context      *ctx = data;
     GETSOCKNAME_ARG3_TYPE               addrlen;
     krb5_data                           output;
+    krb5_address                        **addrs = NULL;
 
     memset (message, 0, sizeof(krb5_data));
 
@@ -143,20 +144,10 @@ kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message)
         local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr);
         local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr;
     } else {
-        krb5_address **addrs;
-
         code = krb5_os_localaddr(ctx->context, &addrs);
         if (code)
             goto cleanup;
-
-        local_kaddr.magic = addrs[0]->magic;
-        local_kaddr.addrtype = addrs[0]->addrtype;
-        local_kaddr.length = addrs[0]->length;
-        local_kaddr.contents = k5memdup(addrs[0]->contents, addrs[0]->length,
-                                        &code);
-        krb5_free_addresses(ctx->context, addrs);
-        if (local_kaddr.contents == NULL)
-            goto cleanup;
+        local_kaddr = *addrs[0];
     }
 
 
@@ -193,6 +184,7 @@ kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message)
     message->data = output.data;
 
 cleanup:
+    krb5_free_addresses(ctx->context, addrs);
     return code;
 }
 
-- 
2.43.0

