import CS krb5-1.21.1-3.el9

This commit is contained in:
eabdullin 2024-09-30 15:45:23 +00:00
parent 05e056e440
commit e057897bbe
9 changed files with 12280 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
From 347079e258e6ded99d8dda162cafaf133b982ab9 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 27 Oct 2023 00:44:53 -0400
Subject: [PATCH] End connection on KDC_ERR_SVC_UNAVAILABLE
In sendto_kdc.c:service_fds(), if a message handler indicates that a
message should be discarded, kill the connection so we don't continue
waiting on it for more data.
ticket: 7899
(cherry picked from commit ca80f64c786341d5871ae1de18142e62af64f7b9)
---
src/lib/krb5/os/sendto_kdc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 0f4bf23a95..262edf09b4 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -1440,7 +1440,10 @@ service_fds(krb5_context context, struct select_state *selstate,
if (msg_handler != NULL) {
krb5_data reply = make_data(state->in.buf, state->in.pos);
- stop = (msg_handler(context, &reply, msg_handler_data) != 0);
+ if (!msg_handler(context, &reply, msg_handler_data)) {
+ kill_conn(context, state, selstate);
+ stop = 0;
+ }
}
if (stop) {
--
2.44.0

View File

@ -0,0 +1,226 @@
From d71ebaef4619d6281551793c297caed7a025a909 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 26 Oct 2023 14:20:34 -0400
Subject: [PATCH] Add request_timeout configuration parameter
Add a parameter to limit the total amount of time taken for a KDC or
password change request.
ticket: 9106 (new)
(cherry picked from commit 802318cda963456b3ed7856c836e89da891483be)
---
doc/admin/conf_files/krb5_conf.rst | 9 ++++++
src/include/k5-int.h | 2 ++
src/lib/krb5/krb/init_ctx.c | 14 +++++++-
src/lib/krb5/os/sendto_kdc.c | 51 ++++++++++++++++++++----------
4 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index a33711d918..65fb592d98 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -356,6 +356,15 @@ The libdefaults section may contain any of the following relations:
(:ref:`duration` string.) Sets the default renewable lifetime
for initial ticket requests. The default value is 0.
+**request_timeout**
+ (:ref:`duration` string.) Sets the maximum total time for KDC or
+ password change requests. This timeout does not affect the
+ intervals between requests, so setting a low timeout may result in
+ fewer requests being attempted and/or some servers not being
+ contacted. A value of 0 indicates no specific maximum, in which
+ case requests will time out if no server responds after several
+ tries. The default value is 0. (New in release 1.22.)
+
**spake_preauth_groups**
A whitespace or comma-separated list of words which specifies the
groups allowed for SPAKE preauthentication. The possible values
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index b3e07945c1..69d6a6f569 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -296,6 +296,7 @@ typedef unsigned char u_char;
#define KRB5_CONF_SPAKE_PREAUTH_INDICATOR "spake_preauth_indicator"
#define KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE "spake_preauth_kdc_challenge"
#define KRB5_CONF_SPAKE_PREAUTH_GROUPS "spake_preauth_groups"
+#define KRB5_CONF_REQUEST_TIMEOUT "request_timeout"
#define KRB5_CONF_TICKET_LIFETIME "ticket_lifetime"
#define KRB5_CONF_UDP_PREFERENCE_LIMIT "udp_preference_limit"
#define KRB5_CONF_UNLOCKITER "unlockiter"
@@ -1200,6 +1201,7 @@ struct _krb5_context {
kdb5_dal_handle *dal_handle;
/* allowable clock skew */
krb5_deltat clockskew;
+ krb5_deltat req_timeout;
krb5_flags kdc_default_options;
krb5_flags library_options;
krb5_boolean profile_secure;
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index 2b5abcd817..582a2945ff 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -157,7 +157,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
krb5_context ctx = 0;
krb5_error_code retval;
int tmp;
- char *plugin_dir = NULL;
+ char *plugin_dir = NULL, *timeout_str = NULL;
/* Verify some assumptions. If the assumptions hold and the
compiler is optimizing, this should result in no code being
@@ -240,6 +240,17 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
get_integer(ctx, KRB5_CONF_CLOCKSKEW, DEFAULT_CLOCKSKEW, &tmp);
ctx->clockskew = tmp;
+ retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
+ KRB5_CONF_REQUEST_TIMEOUT, NULL, NULL,
+ &timeout_str);
+ if (retval)
+ goto cleanup;
+ if (timeout_str != NULL) {
+ retval = krb5_string_to_deltat(timeout_str, &ctx->req_timeout);
+ if (retval)
+ goto cleanup;
+ }
+
get_integer(ctx, KRB5_CONF_KDC_DEFAULT_OPTIONS, KDC_OPT_RENEWABLE_OK,
&tmp);
ctx->kdc_default_options = tmp;
@@ -281,6 +292,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
cleanup:
profile_release_string(plugin_dir);
+ profile_release_string(timeout_str);
krb5_free_context(ctx);
return retval;
}
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 262edf09b4..98247a1089 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -1395,34 +1395,41 @@ get_endtime(time_ms endtime, struct conn_state *conns)
static krb5_boolean
service_fds(krb5_context context, struct select_state *selstate,
- time_ms interval, struct conn_state *conns,
+ time_ms interval, time_ms timeout, struct conn_state *conns,
struct select_state *seltemp, const krb5_data *realm,
int (*msg_handler)(krb5_context, const krb5_data *, void *),
void *msg_handler_data, struct conn_state **winner_out)
{
int e, selret = 0;
- time_ms endtime;
+ time_ms curtime, interval_end, endtime;
struct conn_state *state;
*winner_out = NULL;
- e = get_curtime_ms(&endtime);
+ e = get_curtime_ms(&curtime);
if (e)
return TRUE;
- endtime += interval;
+ interval_end = curtime + interval;
e = 0;
while (selstate->nfds > 0) {
- e = cm_select_or_poll(selstate, get_endtime(endtime, conns),
- seltemp, &selret);
+ endtime = get_endtime(interval_end, conns);
+ /* Don't wait longer than the whole request should last. */
+ if (timeout && endtime > timeout)
+ endtime = timeout;
+ e = cm_select_or_poll(selstate, endtime, seltemp, &selret);
if (e == EINTR)
continue;
if (e != 0)
break;
- if (selret == 0)
- /* Timeout, return to caller. */
+ if (selret == 0) {
+ /* We timed out. Stop if we hit the overall request timeout. */
+ if (timeout && (get_curtime_ms(&curtime) || curtime >= timeout))
+ return TRUE;
+ /* Otherwise return to the caller to send the next request. */
return FALSE;
+ }
/* Got something on a socket, process it. */
for (state = conns; state != NULL; state = state->next) {
@@ -1495,7 +1502,7 @@ k5_sendto(krb5_context context, const krb5_data *message,
void *msg_handler_data)
{
int pass;
- time_ms delay;
+ time_ms delay, timeout = 0;
krb5_error_code retval;
struct conn_state *conns = NULL, *state, **tailptr, *next, *winner;
size_t s;
@@ -1505,6 +1512,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
*reply = empty_data();
+ if (context->req_timeout) {
+ retval = get_curtime_ms(&timeout);
+ if (retval)
+ return retval;
+ timeout += 1000 * context->req_timeout;
+ }
+
/* One for use here, listing all our fds in use, and one for
* temporary use in service_fds, for the fds of interest. */
sel_state = malloc(2 * sizeof(*sel_state));
@@ -1532,8 +1546,9 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
- done = service_fds(context, sel_state, 1000, conns, seltemp,
- realm, msg_handler, msg_handler_data, &winner);
+ done = service_fds(context, sel_state, 1000, timeout, conns,
+ seltemp, realm, msg_handler, msg_handler_data,
+ &winner);
}
}
@@ -1545,13 +1560,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
- done = service_fds(context, sel_state, 1000, conns, seltemp,
+ done = service_fds(context, sel_state, 1000, timeout, conns, seltemp,
realm, msg_handler, msg_handler_data, &winner);
}
/* Wait for two seconds at the end of the first pass. */
if (!done) {
- done = service_fds(context, sel_state, 2000, conns, seltemp,
+ done = service_fds(context, sel_state, 2000, timeout, conns, seltemp,
realm, msg_handler, msg_handler_data, &winner);
}
@@ -1562,15 +1577,17 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
- done = service_fds(context, sel_state, 1000, conns, seltemp,
- realm, msg_handler, msg_handler_data, &winner);
+ done = service_fds(context, sel_state, 1000, timeout, conns,
+ seltemp, realm, msg_handler, msg_handler_data,
+ &winner);
if (sel_state->nfds == 0)
break;
}
/* Wait for the delay backoff at the end of this pass. */
if (!done) {
- done = service_fds(context, sel_state, delay, conns, seltemp,
- realm, msg_handler, msg_handler_data, &winner);
+ done = service_fds(context, sel_state, delay, timeout, conns,
+ seltemp, realm, msg_handler, msg_handler_data,
+ &winner);
}
if (sel_state->nfds == 0)
break;
--
2.44.0

View File

@ -0,0 +1,138 @@
From 0bf66d2018db92c95d3bab54a62f6a3265ceb158 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 26 Oct 2023 16:26:42 -0400
Subject: [PATCH] Wait indefinitely on KDC TCP connections
When making a KDC or password change request, wait indefinitely
(limited only by request_timeout if set) once a KDC has accepted a TCP
connection.
ticket: 9105 (new)
(cherry picked from commit 6436a3808061da787a43c6810f5f0370cdfb6e36)
---
doc/admin/conf_files/krb5_conf.rst | 2 +-
src/lib/krb5/os/sendto_kdc.c | 50 ++++++++++++++++--------------
2 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 65fb592d98..b7284c47df 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -357,7 +357,7 @@ The libdefaults section may contain any of the following relations:
for initial ticket requests. The default value is 0.
**request_timeout**
- (:ref:`duration` string.) Sets the maximum total time for KDC or
+ (:ref:`duration` string.) Sets the maximum total time for KDC and
password change requests. This timeout does not affect the
intervals between requests, so setting a low timeout may result in
fewer requests being attempted and/or some servers not being
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 98247a1089..924f5b2d26 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -134,7 +134,6 @@ struct conn_state {
krb5_data callback_buffer;
size_t server_index;
struct conn_state *next;
- time_ms endtime;
krb5_boolean defer;
struct {
const char *uri_path;
@@ -344,15 +343,19 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
struct select_state *out, int *sret)
{
#ifndef USE_POLL
- struct timeval tv;
+ struct timeval tv, *tvp;
#endif
krb5_error_code retval;
time_ms curtime, interval;
- retval = get_curtime_ms(&curtime);
- if (retval != 0)
- return retval;
- interval = (curtime < endtime) ? endtime - curtime : 0;
+ if (endtime != 0) {
+ retval = get_curtime_ms(&curtime);
+ if (retval != 0)
+ return retval;
+ interval = (curtime < endtime) ? endtime - curtime : 0;
+ } else {
+ interval = -1;
+ }
/* We don't need a separate copy of the selstate for poll, but use one for
* consistency with how we use select. */
@@ -361,9 +364,14 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
#ifdef USE_POLL
*sret = poll(out->fds, out->nfds, interval);
#else
- tv.tv_sec = interval / 1000;
- tv.tv_usec = interval % 1000 * 1000;
- *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv);
+ if (interval != -1) {
+ tv.tv_sec = interval / 1000;
+ tv.tv_usec = interval % 1000 * 1000;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+ *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, tvp);
#endif
return (*sret < 0) ? SOCKET_ERRNO : 0;
@@ -1099,11 +1107,6 @@ service_tcp_connect(krb5_context context, const krb5_data *realm,
}
conn->state = WRITING;
-
- /* Record this connection's timeout for service_fds. */
- if (get_curtime_ms(&conn->endtime) == 0)
- conn->endtime += 10000;
-
return conn->service_write(context, realm, conn, selstate);
}
@@ -1378,19 +1381,18 @@ kill_conn:
return FALSE;
}
-/* Return the maximum of endtime and the endtime fields of all currently active
- * TCP connections. */
-static time_ms
-get_endtime(time_ms endtime, struct conn_state *conns)
+/* Return true if conns contains any states with connected TCP sockets. */
+static krb5_boolean
+any_tcp_connections(struct conn_state *conns)
{
struct conn_state *state;
for (state = conns; state != NULL; state = state->next) {
- if ((state->state == READING || state->state == WRITING) &&
- state->endtime > endtime)
- endtime = state->endtime;
+ if (state->addr.transport != UDP &&
+ (state->state == READING || state->state == WRITING))
+ return TRUE;
}
- return endtime;
+ return FALSE;
}
static krb5_boolean
@@ -1413,9 +1415,9 @@ service_fds(krb5_context context, struct select_state *selstate,
e = 0;
while (selstate->nfds > 0) {
- endtime = get_endtime(interval_end, conns);
+ endtime = any_tcp_connections(conns) ? 0 : interval_end;
/* Don't wait longer than the whole request should last. */
- if (timeout && endtime > timeout)
+ if (timeout && (!endtime || endtime > timeout))
endtime = timeout;
e = cm_select_or_poll(selstate, endtime, seltemp, &selret);
if (e == EINTR)
--
2.44.0

View File

@ -0,0 +1,381 @@
From 0cb2e6c09fee3863c16664bf180e773f662cd313 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Steffen=20Kie=C3=9F?=
<steffen.kiess@cis.iti.uni-stuttgart.de>
Date: Tue, 13 Feb 2024 18:39:27 +0100
Subject: [PATCH] Avoid strict-prototype compiler errors
Commit 4b9d7f7c107f01a61600fddcd8cde3812d0366a2 added the
-Werror=strict-prototypes parameter to the build process, but left
behind 28 function definitions using "()" instead of "(void)". Most
of these definitions could not cause compiler errors for various
reasons (such as an accompanying prototype), but a few could cause
errors in gcc depending on the build configuration.
For consistency and safety, add "(void)" to all 28 definitions.
[ghudson@mit.edu: rewrote commit message]
(cherry picked from commit 3ae9244cd021a75eba909d872a92c25db490714d)
---
src/clients/kcpytkt/kcpytkt.c | 2 +-
src/clients/kdeltkt/kdeltkt.c | 2 +-
src/clients/kinit/kinit.c | 4 ++--
src/clients/kinit/kinit_kdb.c | 2 +-
src/clients/klist/klist.c | 4 ++--
src/kadmin/cli/kadmin.c | 2 +-
src/kadmin/dbutil/kdb5_util.c | 4 ++--
src/kdc/main.c | 2 +-
src/kprop/kpropd.c | 4 ++--
src/lib/crypto/builtin/enc_provider/aes.c | 2 +-
src/lib/crypto/openssl/hmac.c | 2 +-
src/lib/krb5/ccache/t_memory.c | 4 ++--
src/lib/krb5/ccache/t_stdio.c | 4 ++--
src/plugins/kdb/db2/libdb2/btree/bt_debug.c | 2 +-
src/plugins/kdb/db2/libdb2/btree/bt_open.c | 4 ++--
src/plugins/kdb/db2/libdb2/hash/dbm.c | 2 +-
src/plugins/kdb/db2/libdb2/test/btree.tests/main.c | 2 +-
src/plugins/kdb/db2/libdb2/test/dbtest.c | 2 +-
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 2 +-
src/plugins/tls/k5tls/openssl.c | 2 +-
src/tests/asn.1/make-vectors.c | 2 +-
21 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/src/clients/kcpytkt/kcpytkt.c b/src/clients/kcpytkt/kcpytkt.c
index 0b8802261e..f1d50e5de0 100644
--- a/src/clients/kcpytkt/kcpytkt.c
+++ b/src/clients/kcpytkt/kcpytkt.c
@@ -10,7 +10,7 @@ static char *prog;
static int quiet = 0;
static void
-xusage()
+xusage(void)
{
fprintf(stderr, "xusage: %s [-c from_ccache] [-e etype] [-f flags] "
"dest_ccache service1 service2 ...\n", prog);
diff --git a/src/clients/kdeltkt/kdeltkt.c b/src/clients/kdeltkt/kdeltkt.c
index cd0bf637db..66a32a8bd3 100644
--- a/src/clients/kdeltkt/kdeltkt.c
+++ b/src/clients/kdeltkt/kdeltkt.c
@@ -10,7 +10,7 @@ static char *prog;
static int quiet = 0;
static void
-xusage()
+xusage(void)
{
fprintf(stderr, "xusage: %s [-c ccache] [-e etype] [-f flags] service1 "
"service2 ...\n", prog);
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 7a33ffae59..b27b723f2d 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -55,7 +55,7 @@ get_name_from_os(void)
#else /* HAVE_PWD_H */
#ifdef _WIN32
static char *
-get_name_from_os()
+get_name_from_os(void)
{
static char name[1024];
DWORD name_size = sizeof(name);
@@ -69,7 +69,7 @@ get_name_from_os()
}
#else /* _WIN32 */
static char *
-get_name_from_os()
+get_name_from_os(void)
{
return NULL;
}
diff --git a/src/clients/kinit/kinit_kdb.c b/src/clients/kinit/kinit_kdb.c
index fbd174bf0c..4e7cd50169 100644
--- a/src/clients/kinit/kinit_kdb.c
+++ b/src/clients/kinit/kinit_kdb.c
@@ -69,7 +69,7 @@ kinit_kdb_init(krb5_context *pcontext, char *realm)
}
void
-kinit_kdb_fini()
+kinit_kdb_fini(void)
{
kadm5_destroy(server_handle);
}
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index c797b1698f..27cf0ee11b 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -359,7 +359,7 @@ do_keytab(const char *name)
}
static void
-list_all_ccaches()
+list_all_ccaches(void)
{
krb5_error_code ret;
krb5_ccache cache;
@@ -451,7 +451,7 @@ show_all_ccaches(void)
}
static void
-do_ccache()
+do_ccache(void)
{
krb5_error_code ret;
krb5_ccache cache;
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
index 23b64b0f58..c1256f7708 100644
--- a/src/kadmin/cli/kadmin.c
+++ b/src/kadmin/cli/kadmin.c
@@ -607,7 +607,7 @@ kadmin_startup(int argc, char *argv[], char **request_out, char ***args_out)
}
int
-quit()
+quit(void)
{
kadm5_ret_t retval;
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
index 55d529fa4c..b9b61e3f91 100644
--- a/src/kadmin/dbutil/kdb5_util.c
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -367,7 +367,7 @@ main(int argc, char *argv[])
* program is run).
*/
static int
-open_db_and_mkey()
+open_db_and_mkey(void)
{
krb5_error_code retval;
krb5_data scratch, pwd, seed;
@@ -489,7 +489,7 @@ open_db_and_mkey()
#endif
int
-quit()
+quit(void)
{
krb5_error_code retval;
static krb5_boolean finished = 0;
diff --git a/src/kdc/main.c b/src/kdc/main.c
index b43fe9a082..2dfad5673f 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -854,7 +854,7 @@ write_pid_file(const char *path)
}
static void
-finish_realms()
+finish_realms(void)
{
int i;
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
index f883ae2df8..fbb8e37ae9 100644
--- a/src/kprop/kpropd.c
+++ b/src/kprop/kpropd.c
@@ -376,7 +376,7 @@ get_wildcard_addr(struct addrinfo **res)
}
static void
-do_standalone()
+do_standalone(void)
{
struct sockaddr_in frominet;
struct addrinfo *res;
@@ -639,7 +639,7 @@ full_resync(CLIENT *clnt)
* Returns non-zero on failure due to errors.
*/
krb5_error_code
-do_iprop()
+do_iprop(void)
{
kadm5_ret_t retval;
krb5_principal iprop_svc_principal = NULL;
diff --git a/src/lib/crypto/builtin/enc_provider/aes.c b/src/lib/crypto/builtin/enc_provider/aes.c
index 7fa9449797..39e2a84005 100644
--- a/src/lib/crypto/builtin/enc_provider/aes.c
+++ b/src/lib/crypto/builtin/enc_provider/aes.c
@@ -69,7 +69,7 @@ void k5_iEnc256_CBC(struct aes_data *data);
void k5_iDec256_CBC(struct aes_data *data);
static krb5_boolean
-aesni_supported_by_cpu()
+aesni_supported_by_cpu(void)
{
unsigned int a, b, c, d;
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index 25a419d73a..32dec3022e 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -71,7 +71,7 @@
#define HMAC_CTX_new compat_hmac_ctx_new
static HMAC_CTX *
-compat_hmac_ctx_new()
+compat_hmac_ctx_new(void)
{
HMAC_CTX *ctx;
diff --git a/src/lib/krb5/ccache/t_memory.c b/src/lib/krb5/ccache/t_memory.c
index 6d103a00d1..0f94e823cb 100644
--- a/src/lib/krb5/ccache/t_memory.c
+++ b/src/lib/krb5/ccache/t_memory.c
@@ -85,7 +85,7 @@ krb5_creds test_creds = {
};
void
-init_test_cred()
+init_test_cred(void)
{
test_creds.client = (krb5_principal) malloc(sizeof(krb5_data *)*3);
test_creds.client[0] = &client1;
@@ -104,7 +104,7 @@ init_test_cred()
};
void
-mcc_test()
+mcc_test(void)
{
krb5_ccache id;
krb5_creds creds;
diff --git a/src/lib/krb5/ccache/t_stdio.c b/src/lib/krb5/ccache/t_stdio.c
index 15185e301c..06a9c2dea1 100644
--- a/src/lib/krb5/ccache/t_stdio.c
+++ b/src/lib/krb5/ccache/t_stdio.c
@@ -98,7 +98,7 @@ krb5_creds test_creds = {
};
void
-init_test_cred()
+init_test_cred(void)
{
test_creds.client = (krb5_principal) malloc(sizeof(krb5_data *)*3);
test_creds.client[0] = &client1;
@@ -118,7 +118,7 @@ init_test_cred()
int flags = 0;
void
-scc_test()
+scc_test(void)
{
krb5_ccache id;
krb5_creds creds;
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_debug.c b/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
index bc71076a35..5a955e09be 100644
--- a/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
@@ -56,7 +56,7 @@ static FILE *tracefp;
* initialize debugging.
*/
static void
-__bt_dinit()
+__bt_dinit(void)
{
static int first = 1;
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
index a2910422eb..ef7515c3d4 100644
--- a/src/plugins/kdb/db2/libdb2/btree/bt_open.c
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
@@ -391,7 +391,7 @@ nroot(BTREE *t)
}
static int
-tmp()
+tmp(void)
{
#ifdef SIG_BLOCK
sigset_t set, oset;
@@ -438,7 +438,7 @@ tmp()
}
static int
-byteorder()
+byteorder(void)
{
u_int32_t x;
u_char *p;
diff --git a/src/plugins/kdb/db2/libdb2/hash/dbm.c b/src/plugins/kdb/db2/libdb2/hash/dbm.c
index 2dca256dc3..e643634433 100644
--- a/src/plugins/kdb/db2/libdb2/hash/dbm.c
+++ b/src/plugins/kdb/db2/libdb2/hash/dbm.c
@@ -143,7 +143,7 @@ kdb2_store(datum key, datum dat)
}
static void
-no_open_db()
+no_open_db(void)
{
(void)fprintf(stderr, "dbm: no open database.\n");
}
diff --git a/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c b/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
index 088f903231..eec843d4db 100644
--- a/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
+++ b/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
@@ -908,7 +908,7 @@ keydata(key, data)
}
void
-usage()
+usage(void)
{
(void)fprintf(stderr,
"usage: %s [-bdluw] [-c cache] [-i file] [-p page] [file]\n",
diff --git a/src/plugins/kdb/db2/libdb2/test/dbtest.c b/src/plugins/kdb/db2/libdb2/test/dbtest.c
index 04bf34b90d..a2866b4412 100644
--- a/src/plugins/kdb/db2/libdb2/test/dbtest.c
+++ b/src/plugins/kdb/db2/libdb2/test/dbtest.c
@@ -792,7 +792,7 @@ xmalloc(char *text, size_t len)
}
void
-usage()
+usage(void)
{
(void)fprintf(stderr,
"usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 6d96499d77..af3fa9ee8b 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -3090,7 +3090,7 @@ cleanup:
}
int
-pkinit_openssl_init()
+pkinit_openssl_init(void)
{
/* Initialize OpenSSL. */
ERR_load_crypto_strings();
diff --git a/src/plugins/tls/k5tls/openssl.c b/src/plugins/tls/k5tls/openssl.c
index 99fda7ffcd..aab67c01cb 100644
--- a/src/plugins/tls/k5tls/openssl.c
+++ b/src/plugins/tls/k5tls/openssl.c
@@ -49,7 +49,7 @@ static int ex_handle_id = -1;
MAKE_INIT_FUNCTION(init_openssl);
int
-init_openssl()
+init_openssl(void)
{
SSL_library_init();
SSL_load_error_strings();
diff --git a/src/tests/asn.1/make-vectors.c b/src/tests/asn.1/make-vectors.c
index 2fc85466bb..6f2b7dd021 100644
--- a/src/tests/asn.1/make-vectors.c
+++ b/src/tests/asn.1/make-vectors.c
@@ -224,7 +224,7 @@ printbuf(void)
}
int
-main()
+main(void)
{
/* Initialize values which can't use static initializers. */
asn_long2INTEGER(&otp_format, 2); /* Alphanumeric */
--
2.44.0

View File

@ -0,0 +1,42 @@
From f54763bc90df9c76c69ee9a837cf856bcf93e633 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 5 Mar 2024 17:38:49 -0500
Subject: [PATCH] Fix leak in KDC NDR encoding
If the KDC tries to encode a principal containing encode invalid UTF-8
sequences for inclusion in a PAC delegation info buffer, it will leak
a small amount of memory in enc_wchar_pointer() before failing. Fix
the leak.
ticket: 9115 (new)
tags: pullup
target_version: 1.21-next
(cherry picked from commit 7d0d85bf99caf60c0afd4dcf91b0c4c683b983fe)
---
src/kdc/ndr.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/kdc/ndr.c b/src/kdc/ndr.c
index 48395abe52..d438408ee2 100644
--- a/src/kdc/ndr.c
+++ b/src/kdc/ndr.c
@@ -96,14 +96,13 @@ enc_wchar_pointer(const char *utf8, struct encoded_wchars *encoded_out)
size_t utf16len, num_wchars;
uint8_t *utf16;
- k5_buf_init_dynamic(&b);
-
ret = k5_utf8_to_utf16le(utf8, &utf16, &utf16len);
if (ret)
return ret;
num_wchars = utf16len / 2;
+ k5_buf_init_dynamic(&b);
k5_buf_add_uint32_le(&b, num_wchars + 1);
k5_buf_add_uint32_le(&b, 0);
k5_buf_add_uint32_le(&b, num_wchars);
--
2.44.0

View File

@ -0,0 +1,206 @@
From d230c72573430803c569817a71b79be8656fa6c5 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 5 Mar 2024 19:53:07 -0500
Subject: [PATCH] Fix two unlikely memory leaks
In gss_krb5int_make_seal_token_v3(), one of the bounds checks (which
could probably never be triggered) leaks plain.data. Fix this leak
and use current practices for cleanup throughout the function.
In xmt_rmtcallres() (unused within the tree and likely elsewhere),
store port_ptr into crp->port_ptr as soon as it is allocated;
otherwise it could leak if the subsequent xdr_u_int32() operation
fails.
(cherry picked from commit c5f9c816107f70139de11b38aa02db2f1774ee0d)
---
src/lib/gssapi/krb5/k5sealv3.c | 56 +++++++++++++++-------------------
src/lib/rpc/pmap_rmt.c | 10 +++---
2 files changed, 29 insertions(+), 37 deletions(-)
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
index 3b4f8cb837..e881eee835 100644
--- a/src/lib/gssapi/krb5/k5sealv3.c
+++ b/src/lib/gssapi/krb5/k5sealv3.c
@@ -65,7 +65,7 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
int conf_req_flag, int toktype)
{
size_t bufsize = 16;
- unsigned char *outbuf = 0;
+ unsigned char *outbuf = NULL;
krb5_error_code err;
int key_usage;
unsigned char acceptor_flag;
@@ -75,9 +75,13 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
#endif
size_t ec;
unsigned short tok_id;
- krb5_checksum sum;
+ krb5_checksum sum = { 0 };
krb5_key key;
krb5_cksumtype cksumtype;
+ krb5_data plain = empty_data();
+
+ token->value = NULL;
+ token->length = 0;
acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
key_usage = (toktype == KG_TOK_WRAP_MSG
@@ -107,14 +111,15 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
#endif
if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
- krb5_data plain;
krb5_enc_data cipher;
size_t ec_max;
size_t encrypt_size;
/* 300: Adds some slop. */
- if (SIZE_MAX - 300 < message->length)
- return ENOMEM;
+ if (SIZE_MAX - 300 < message->length) {
+ err = ENOMEM;
+ goto cleanup;
+ }
ec_max = SIZE_MAX - message->length - 300;
if (ec_max > 0xffff)
ec_max = 0xffff;
@@ -126,20 +131,20 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
#endif
err = alloc_data(&plain, message->length + 16 + ec);
if (err)
- return err;
+ goto cleanup;
/* Get size of ciphertext. */
encrypt_size = krb5_encrypt_size(plain.length, key->keyblock.enctype);
if (encrypt_size > SIZE_MAX / 2) {
err = ENOMEM;
- goto error;
+ goto cleanup;
}
bufsize = 16 + encrypt_size;
/* Allocate space for header plus encrypted data. */
outbuf = gssalloc_malloc(bufsize);
if (outbuf == NULL) {
- free(plain.data);
- return ENOMEM;
+ err = ENOMEM;
+ goto cleanup;
}
/* TOK_ID */
@@ -164,11 +169,8 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
cipher.ciphertext.length = bufsize - 16;
cipher.enctype = key->keyblock.enctype;
err = krb5_k_encrypt(context, key, key_usage, 0, &plain, &cipher);
- zap(plain.data, plain.length);
- free(plain.data);
- plain.data = 0;
if (err)
- goto error;
+ goto cleanup;
/* Now that we know we're returning a valid token.... */
ctx->seq_send++;
@@ -181,7 +183,6 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
/* If the rotate fails, don't worry about it. */
#endif
} else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
- krb5_data plain;
size_t cksumsize;
/* Here, message is the application-supplied data; message2 is
@@ -193,21 +194,19 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
wrap_with_checksum:
err = alloc_data(&plain, message->length + 16);
if (err)
- return err;
+ goto cleanup;
err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
if (err)
- goto error;
+ goto cleanup;
assert(cksumsize <= 0xffff);
bufsize = 16 + message2->length + cksumsize;
outbuf = gssalloc_malloc(bufsize);
if (outbuf == NULL) {
- free(plain.data);
- plain.data = 0;
err = ENOMEM;
- goto error;
+ goto cleanup;
}
/* TOK_ID */
@@ -239,23 +238,15 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
if (message2->length)
memcpy(outbuf + 16, message2->value, message2->length);
- sum.contents = outbuf + 16 + message2->length;
- sum.length = cksumsize;
-
err = krb5_k_make_checksum(context, cksumtype, key,
key_usage, &plain, &sum);
- zap(plain.data, plain.length);
- free(plain.data);
- plain.data = 0;
if (err) {
zap(outbuf,bufsize);
- goto error;
+ goto cleanup;
}
if (sum.length != cksumsize)
abort();
memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
- krb5_free_checksum_contents(context, &sum);
- sum.contents = 0;
/* Now that we know we're actually generating the token... */
ctx->seq_send++;
@@ -285,12 +276,13 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
token->value = outbuf;
token->length = bufsize;
- return 0;
+ outbuf = NULL;
+ err = 0;
-error:
+cleanup:
+ krb5_free_checksum_contents(context, &sum);
+ zapfree(plain.data, plain.length);
gssalloc_free(outbuf);
- token->value = NULL;
- token->length = 0;
return err;
}
diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c
index 434e4eea65..f55ca46c60 100644
--- a/src/lib/rpc/pmap_rmt.c
+++ b/src/lib/rpc/pmap_rmt.c
@@ -161,12 +161,12 @@ xdr_rmtcallres(
caddr_t port_ptr;
port_ptr = (caddr_t)(void *)crp->port_ptr;
- if (xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
- (xdrproc_t)xdr_u_int32) &&
- xdr_u_int32(xdrs, &crp->resultslen)) {
- crp->port_ptr = (uint32_t *)(void *)port_ptr;
+ if (!xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
+ (xdrproc_t)xdr_u_int32))
+ return (FALSE);
+ crp->port_ptr = (uint32_t *)(void *)port_ptr;
+ if (xdr_u_int32(xdrs, &crp->resultslen))
return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
- }
return (FALSE);
}
--
2.44.0

View File

@ -0,0 +1,535 @@
From 28009fda028c489ae38902b2c513c4208889f043 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 14 Jun 2024 10:56:12 -0400
Subject: [PATCH] Fix vulnerabilities in GSS message token handling
In gss_krb5int_unseal_token_v3() and gss_krb5int_unseal_v3_iov(),
verify the Extra Count field of CFX wrap tokens against the encrypted
header. Reported by Jacob Champion.
In gss_krb5int_unseal_token_v3(), check for a decrypted plaintext
length too short to contain the encrypted header and extra count
bytes. Reported by Jacob Champion.
In kg_unseal_iov_token(), separately track the header IOV length and
complete token length when parsing the token's ASN.1 wrapper. This
fix contains modified versions of functions from k5-der.h and
util_token.c; this duplication will be cleaned up in a future commit.
CVE-2024-37370:
In MIT krb5 release 1.3 and later, an attacker can modify the
plaintext Extra Count field of a confidential GSS krb5 wrap token,
causing the unwrapped token to appear truncated to the application.
CVE-2024-37371:
In MIT krb5 release 1.3 and later, an attacker can cause invalid
memory reads by sending message tokens with invalid length fields.
ticket: 9128 (new)
tags: pullup
target_version: 1.21-next
(cherry picked from commit b0a2f8a5365f2eec3e27d78907de9f9d2c80505a)
---
src/lib/gssapi/krb5/k5sealv3.c | 5 +
src/lib/gssapi/krb5/k5sealv3iov.c | 3 +-
src/lib/gssapi/krb5/k5unsealiov.c | 80 +++++++++-
src/tests/gssapi/t_invalid.c | 233 +++++++++++++++++++++++++-----
4 files changed, 275 insertions(+), 46 deletions(-)
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
index e881eee835..d3210c1107 100644
--- a/src/lib/gssapi/krb5/k5sealv3.c
+++ b/src/lib/gssapi/krb5/k5sealv3.c
@@ -400,10 +400,15 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr,
/* Don't use bodysize here! Use the fact that
cipher.ciphertext.length has been adjusted to the
correct length. */
+ if (plain.length < 16 + ec) {
+ free(plain.data);
+ goto defective;
+ }
althdr = (unsigned char *)plain.data + plain.length - 16;
if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
|| althdr[2] != ptr[2]
|| althdr[3] != ptr[3]
+ || load_16_be(althdr+4) != ec
|| memcmp(althdr+8, ptr+8, 8)) {
free(plain.data);
goto defective;
diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c
index 333ee124dd..f8e90c35b4 100644
--- a/src/lib/gssapi/krb5/k5sealv3iov.c
+++ b/src/lib/gssapi/krb5/k5sealv3iov.c
@@ -402,9 +402,10 @@ gss_krb5int_unseal_v3_iov(krb5_context context,
if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
|| althdr[2] != ptr[2]
|| althdr[3] != ptr[3]
+ || load_16_be(althdr + 4) != ec
|| memcmp(althdr + 8, ptr + 8, 8) != 0) {
*minor_status = 0;
- return GSS_S_BAD_SIG;
+ return GSS_S_DEFECTIVE_TOKEN;
}
} else {
/* Verify checksum: note EC is checksum size here, not padding */
diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
index 3ce2a90ce9..6a6585d9af 100644
--- a/src/lib/gssapi/krb5/k5unsealiov.c
+++ b/src/lib/gssapi/krb5/k5unsealiov.c
@@ -25,6 +25,7 @@
*/
#include "k5-int.h"
+#include "k5-der.h"
#include "gssapiP_krb5.h"
static OM_uint32
@@ -247,6 +248,73 @@ cleanup:
return retval;
}
+/* Similar to k5_der_get_value(), but output an unchecked content length
+ * instead of a k5input containing the contents. */
+static inline bool
+get_der_tag(struct k5input *in, uint8_t idbyte, size_t *len_out)
+{
+ uint8_t lenbyte, i;
+ size_t len;
+
+ /* Do nothing if in is empty or the next byte doesn't match idbyte. */
+ if (in->status || in->len == 0 || *in->ptr != idbyte)
+ return false;
+
+ /* Advance past the identifier byte and decode the length. */
+ (void)k5_input_get_byte(in);
+ lenbyte = k5_input_get_byte(in);
+ if (lenbyte < 128) {
+ len = lenbyte;
+ } else {
+ len = 0;
+ for (i = 0; i < (lenbyte & 0x7F); i++) {
+ if (len > (SIZE_MAX >> 8)) {
+ k5_input_set_status(in, EOVERFLOW);
+ return false;
+ }
+ len = (len << 8) | k5_input_get_byte(in);
+ }
+ }
+
+ if (in->status)
+ return false;
+
+ *len_out = len;
+ return true;
+}
+
+/*
+ * Similar to g_verify_token_header() without toktype or flags, but do not read
+ * more than *header_len bytes of ASN.1 wrapper, and on output set *header_len
+ * to the remaining number of header bytes. Verify the outer DER tag's length
+ * against token_len, which may be larger (but not smaller) than *header_len.
+ */
+static gss_int32
+verify_detached_wrapper(const gss_OID_desc *mech, size_t *header_len,
+ uint8_t **header_in, size_t token_len)
+{
+ struct k5input in, mech_der;
+ gss_OID_desc toid;
+ size_t len;
+
+ k5_input_init(&in, *header_in, *header_len);
+
+ if (get_der_tag(&in, 0x60, &len)) {
+ if (len != token_len - (in.ptr - *header_in))
+ return G_BAD_TOK_HEADER;
+ if (!k5_der_get_value(&in, 0x06, &mech_der))
+ return G_BAD_TOK_HEADER;
+ toid.elements = (uint8_t *)mech_der.ptr;
+ toid.length = mech_der.len;
+ if (!g_OID_equal(&toid, mech))
+ return G_WRONG_MECH;
+ }
+
+ *header_in = (uint8_t *)in.ptr;
+ *header_len = in.len;
+ return 0;
+}
+
/*
* Caller must provide TOKEN | DATA | PADDING | TRAILER, except
* for DCE in which case it can just provide TOKEN | DATA (must
@@ -267,8 +335,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
gss_iov_buffer_t header;
gss_iov_buffer_t padding;
gss_iov_buffer_t trailer;
- size_t input_length;
- unsigned int bodysize;
+ size_t input_length, hlen;
int toktype2;
header = kg_locate_header_iov(iov, iov_count, toktype);
@@ -298,15 +365,14 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
input_length += trailer->buffer.length;
}
- code = g_verify_token_header(ctx->mech_used,
- &bodysize, &ptr, -1,
- input_length, 0);
+ hlen = header->buffer.length;
+ code = verify_detached_wrapper(ctx->mech_used, &hlen, &ptr, input_length);
if (code != 0) {
*minor_status = code;
return GSS_S_DEFECTIVE_TOKEN;
}
- if (bodysize < 2) {
+ if (hlen < 2) {
*minor_status = (OM_uint32)G_BAD_TOK_HEADER;
return GSS_S_DEFECTIVE_TOKEN;
}
@@ -314,7 +380,7 @@ kg_unseal_iov_token(OM_uint32 *minor_status,
toktype2 = load_16_be(ptr);
ptr += 2;
- bodysize -= 2;
+ hlen -= 2;
switch (toktype2) {
case KG2_TOK_MIC_MSG:
diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
index e08c0039f8..a052b8ab6e 100644
--- a/src/tests/gssapi/t_invalid.c
+++ b/src/tests/gssapi/t_invalid.c
@@ -36,31 +36,41 @@
*
* 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a
* null pointer dereference. (The token must use SEAL_ALG_NONE or it will
- * be rejected.)
+ * be rejected.) This vulnerability also applies to IOV unwrap.
*
- * 2. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
+ * 2. A CFX wrap token with a different value of EC between the plaintext and
+ * encrypted copies will be erroneously accepted, which allows a message
+ * truncation attack. This vulnerability also applies to IOV unwrap.
+ *
+ * 3. A CFX wrap token with a plaintext length fewer than 16 bytes causes an
+ * access before the beginning of the input buffer, possibly leading to a
+ * crash.
+ *
+ * 4. A CFX wrap token with a plaintext EC value greater than the plaintext
+ * length - 16 causes an integer underflow when computing the result length,
+ * likely causing a crash.
+ *
+ * 5. An IOV unwrap operation will overrun the header buffer if an ASN.1
+ * wrapper longer than the header buffer is present.
+ *
+ * 6. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1
* header causes an input buffer overrun, usually leading to either a segv
* or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or
- * sequence number values.
+ * sequence number values. This vulnerability also applies to IOV unwrap.
*
- * 3. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
+ * 7. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1
* header causes an integer underflow when computing the ciphertext length,
* leading to an allocation error on 32-bit platforms or a segv on 64-bit
* platforms. A pre-CFX MIC token of this size causes an input buffer
* overrun when comparing the checksum, perhaps leading to a segv.
*
- * 4. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
+ * 8. A pre-CFX wrap token with fewer than conflen + padlen bytes in the
* ciphertext (where padlen is the last byte of the decrypted ciphertext)
* causes an integer underflow when computing the original message length,
* leading to an allocation error.
*
- * 5. In the mechglue, truncated encapsulation in the initial context token can
+ * 9. In the mechglue, truncated encapsulation in the initial context token can
* cause input buffer overruns in gss_accept_sec_context().
- *
- * Vulnerabilities #1 and #2 also apply to IOV unwrap, although tokens with
- * fewer than 16 bytes after the ASN.1 header will be rejected.
- * Vulnerabilities #2 and #5 can only be robustly detected using a
- * memory-checking environment such as valgrind.
*/
#include "k5-int.h"
@@ -97,17 +107,25 @@ struct test {
}
};
-/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */
+static void *
+ealloc(size_t len)
+{
+ void *ptr = calloc(len, 1);
+
+ if (ptr == NULL)
+ abort();
+ return ptr;
+}
+
+/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.
+ * The context takes ownership of subkey. */
static gss_ctx_id_t
-make_fake_cfx_context(void)
+make_fake_cfx_context(krb5_key subkey)
{
gss_union_ctx_id_t uctx;
krb5_gss_ctx_id_t kgctx;
- krb5_keyblock kb;
- kgctx = calloc(1, sizeof(*kgctx));
- if (kgctx == NULL)
- abort();
+ kgctx = ealloc(sizeof(*kgctx));
kgctx->established = 1;
kgctx->proto = 1;
if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
@@ -116,15 +134,10 @@ make_fake_cfx_context(void)
kgctx->sealalg = -1;
kgctx->signalg = -1;
- kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
- kb.length = 16;
- kb.contents = (unsigned char *)"1234567887654321";
- if (krb5_k_create_key(NULL, &kb, &kgctx->subkey) != 0)
- abort();
+ kgctx->subkey = subkey;
+ kgctx->cksumtype = CKSUMTYPE_HMAC_SHA1_96_AES128;
- uctx = calloc(1, sizeof(*uctx));
- if (uctx == NULL)
- abort();
+ uctx = ealloc(sizeof(*uctx));
uctx->mech_type = &mech_krb5;
uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
return (gss_ctx_id_t)uctx;
@@ -138,9 +151,7 @@ make_fake_context(const struct test *test)
krb5_gss_ctx_id_t kgctx;
krb5_keyblock kb;
- kgctx = calloc(1, sizeof(*kgctx));
- if (kgctx == NULL)
- abort();
+ kgctx = ealloc(sizeof(*kgctx));
kgctx->established = 1;
if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
abort();
@@ -162,9 +173,7 @@ make_fake_context(const struct test *test)
if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0)
abort();
- uctx = calloc(1, sizeof(*uctx));
- if (uctx == NULL)
- abort();
+ uctx = ealloc(sizeof(*uctx));
uctx->mech_type = &mech_krb5;
uctx->internal_ctx_id = (gss_ctx_id_t)kgctx;
return (gss_ctx_id_t)uctx;
@@ -194,9 +203,7 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out)
assert(mech_krb5.length == 9);
assert(len + 11 < 128);
- wrapped = malloc(len + 13);
- if (wrapped == NULL)
- abort();
+ wrapped = ealloc(len + 13);
wrapped[0] = 0x60;
wrapped[1] = len + 11;
wrapped[2] = 0x06;
@@ -207,6 +214,18 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out)
out->value = wrapped;
}
+/* Create a 16-byte header for a CFX confidential wrap token to be processed by
+ * the fake CFX context. */
+static void
+write_cfx_header(uint16_t ec, uint8_t *out)
+{
+ memset(out, 0, 16);
+ store_16_be(KG2_TOK_WRAP_MSG, out);
+ out[2] = FLAG_WRAP_CONFIDENTIAL;
+ out[3] = 0xFF;
+ store_16_be(ec, out + 4);
+}
+
/* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with
* regular and IOV unwrap. */
static void
@@ -238,6 +257,134 @@ test_bogus_1964_token(gss_ctx_id_t ctx)
free(in.value);
}
+static void
+test_cfx_altered_ec(gss_ctx_id_t ctx, krb5_key subkey)
+{
+ OM_uint32 major, minor;
+ uint8_t tokbuf[128], plainbuf[24];
+ krb5_data plain;
+ krb5_enc_data cipher;
+ gss_buffer_desc in, out;
+ gss_iov_buffer_desc iov[2];
+
+ /* Construct a header with a plaintext EC value of 3. */
+ write_cfx_header(3, tokbuf);
+
+ /* Encrypt a plaintext and a copy of the header with the EC value 0. */
+ memcpy(plainbuf, "truncate", 8);
+ memcpy(plainbuf + 8, tokbuf, 16);
+ store_16_be(0, plainbuf + 12);
+ plain = make_data(plainbuf, 24);
+ cipher.ciphertext.data = (char *)tokbuf + 16;
+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
+ cipher.enctype = subkey->keyblock.enctype;
+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
+ &plain, &cipher) != 0)
+ abort();
+
+ /* Verify that the token is rejected by gss_unwrap(). */
+ in.value = tokbuf;
+ in.length = 16 + cipher.ciphertext.length;
+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
+ if (major != GSS_S_DEFECTIVE_TOKEN)
+ abort();
+ (void)gss_release_buffer(&minor, &out);
+
+ /* Verify that the token is rejected by gss_unwrap_iov(). */
+ iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
+ iov[0].buffer = in;
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
+ if (major != GSS_S_DEFECTIVE_TOKEN)
+ abort();
+}
+
+static void
+test_cfx_short_plaintext(gss_ctx_id_t ctx, krb5_key subkey)
+{
+ OM_uint32 major, minor;
+ uint8_t tokbuf[128], zerobyte = 0;
+ krb5_data plain;
+ krb5_enc_data cipher;
+ gss_buffer_desc in, out;
+
+ write_cfx_header(0, tokbuf);
+
+ /* Encrypt a single byte, with no copy of the header. */
+ plain = make_data(&zerobyte, 1);
+ cipher.ciphertext.data = (char *)tokbuf + 16;
+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
+ cipher.enctype = subkey->keyblock.enctype;
+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
+ &plain, &cipher) != 0)
+ abort();
+
+ /* Verify that the token is rejected by gss_unwrap(). */
+ in.value = tokbuf;
+ in.length = 16 + cipher.ciphertext.length;
+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
+ if (major != GSS_S_DEFECTIVE_TOKEN)
+ abort();
+ (void)gss_release_buffer(&minor, &out);
+}
+
+static void
+test_cfx_large_ec(gss_ctx_id_t ctx, krb5_key subkey)
+{
+ OM_uint32 major, minor;
+ uint8_t tokbuf[128] = { 0 }, plainbuf[20];
+ krb5_data plain;
+ krb5_enc_data cipher;
+ gss_buffer_desc in, out;
+
+ /* Construct a header with an EC value of 5. */
+ write_cfx_header(5, tokbuf);
+
+ /* Encrypt a 4-byte plaintext plus the header. */
+ memcpy(plainbuf, "abcd", 4);
+ memcpy(plainbuf + 4, tokbuf, 16);
+ plain = make_data(plainbuf, 20);
+ cipher.ciphertext.data = (char *)tokbuf + 16;
+ cipher.ciphertext.length = sizeof(tokbuf) - 16;
+ cipher.enctype = subkey->keyblock.enctype;
+ if (krb5_k_encrypt(NULL, subkey, KG_USAGE_INITIATOR_SEAL, NULL,
+ &plain, &cipher) != 0)
+ abort();
+
+ /* Verify that the token is rejected by gss_unwrap(). */
+ in.value = tokbuf;
+ in.length = 16 + cipher.ciphertext.length;
+ major = gss_unwrap(&minor, ctx, &in, &out, NULL, NULL);
+ if (major != GSS_S_DEFECTIVE_TOKEN)
+ abort();
+ (void)gss_release_buffer(&minor, &out);
+}
+
+static void
+test_iov_large_asn1_wrapper(gss_ctx_id_t ctx)
+{
+ OM_uint32 minor, major;
+ uint8_t databuf[10] = { 0 };
+ gss_iov_buffer_desc iov[2];
+
+ /*
+ * In this IOV array, the header contains a DER tag with a dangling eight
+ * bytes of length field. The data IOV indicates a total token length
+ * sufficient to contain the length bytes.
+ */
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = ealloc(2);
+ iov[0].buffer.length = 2;
+ memcpy(iov[0].buffer.value, "\x60\x88", 2);
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.value = databuf;
+ iov[1].buffer.length = 10;
+ major = gss_unwrap_iov(&minor, ctx, NULL, NULL, iov, 2);
+ if (major != GSS_S_DEFECTIVE_TOKEN)
+ abort();
+ free(iov[0].buffer.value);
+}
+
/* Process wrap and MIC tokens with incomplete headers. */
static void
test_short_header(gss_ctx_id_t ctx)
@@ -387,9 +534,7 @@ try_accept(void *value, size_t len)
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
/* Copy the provided value to make input overruns more obvious. */
- in.value = malloc(len);
- if (in.value == NULL)
- abort();
+ in.value = ealloc(len);
memcpy(in.value, value, len);
in.length = len;
(void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
@@ -424,11 +569,23 @@ test_short_encapsulation(void)
int
main(int argc, char **argv)
{
+ krb5_keyblock kb;
+ krb5_key cfx_subkey;
gss_ctx_id_t ctx;
size_t i;
- ctx = make_fake_cfx_context();
+ kb.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ kb.length = 16;
+ kb.contents = (unsigned char *)"1234567887654321";
+ if (krb5_k_create_key(NULL, &kb, &cfx_subkey) != 0)
+ abort();
+
+ ctx = make_fake_cfx_context(cfx_subkey);
test_bogus_1964_token(ctx);
+ test_cfx_altered_ec(ctx, cfx_subkey);
+ test_cfx_short_plaintext(ctx, cfx_subkey);
+ test_cfx_large_ec(ctx, cfx_subkey);
+ test_iov_large_asn1_wrapper(ctx);
free_fake_context(ctx);
for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
--
2.45.1

View File

@ -34,7 +34,7 @@
#
# baserelease is what we have standardized across Fedora and what
# rpmdev-bumpspec knows how to handle.
%global baserelease 1
%global baserelease 3
# This should be e.g. beta1 or %%nil
%global pre_release %nil
@ -98,6 +98,14 @@ Patch0012: 0012-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch
Patch0013: 0013-downstream-Make-PKINIT-CMS-SHA-1-signature-verificat.patch
Patch0014: 0014-Enable-PKINIT-if-at-least-one-group-is-available.patch
Patch0015: 0015-Fix-double-free-in-KDC-TGS-processing.patch
Patch0016: 0016-Eliminate-old-style-function-declarations.patch
Patch0017: 0017-End-connection-on-KDC_ERR_SVC_UNAVAILABLE.patch
Patch0018: 0018-Add-request_timeout-configuration-parameter.patch
Patch0019: 0019-Wait-indefinitely-on-KDC-TCP-connections.patch
Patch0020: 0020-Avoid-strict-prototype-compiler-errors.patch
Patch0021: 0021-Fix-leak-in-KDC-NDR-encoding.patch
Patch0022: 0022-Fix-two-unlikely-memory-leaks.patch
Patch0023: 0023-Fix-vulnerabilities-in-GSS-message-token-handling.patch
License: MIT
URL: https://web.mit.edu/kerberos/www/
@ -662,6 +670,21 @@ exit 0
%{_libdir}/libkadm5srv_mit.so.*
%changelog
* Fri Jul 05 2024 Julien Rische <jrische@redhat.com> - 1.21.1-3
- CVE-2024-37370 CVE-2024-37371
Fix vulnerabilities in GSS message token handling
Resolves: RHEL-45402 RHEL-45392
* Wed Mar 20 2024 Julien Rische <jrische@redhat.com> - 1.21.1-2
- Fix memory leak in GSSAPI interface
Resolves: RHEL-27251
- Fix memory leak in PMAP RPC interface
Resolves: RHEL-27245
- Fix memory leak in failing UTF-8 to UTF-16 re-encoding for PAC
Resolves: RHEL-27253
- Make TCP waiting time configurable
Resolves: RHEL-17132
* Tue Aug 08 2023 Julien Rische <jrische@redhat.com> - 1.21.1-1
- New upstream version (1.21.1)
- Fix double-free in KDC TGS processing (CVE-2023-39975)