diff -Nru krb5-1.12+dfsg/debian/changelog krb5-1.12+dfsg/debian/changelog --- krb5-1.12+dfsg/debian/changelog 2015-11-11 14:10:37.000000000 +0000 +++ krb5-1.12+dfsg/debian/changelog 2019-01-09 21:12:14.000000000 +0000 @@ -1,3 +1,51 @@ +krb5 (1.12+dfsg-2ubuntu5.4) trusty-security; urgency=medium + + * SECURITY UPDATE: DoS (out-of-bounds read) via a crafted string + - debian/patches/CVE-2015-8629.patch: Verify decode kadmin C strings + - CVE-2015-8629 + * SECURITY UPDATE: DoS (NULL pointer dereference) by specifying KADM5_POLICY + with a NULL policy name + - debian/patches/CVE-2015-8630.patch: Check for null kadm5 policy name + - CVE-2015-8630 + * SECURITY UPDATE: DoS (memory consumption) via a request specifying a NULL + principal name + - debian/patches/CVE-2015-8631.patch: Fix leaks in kadmin server stubs + - CVE-2015-8631 + * SECURITY UPDATE: DoS (NULL pointer dereference) via a crafted request to + modify a principal + - debian/patches/CVE-2016-3119.patch: Fix LDAP null dereference on + empty arg + - CVE-2016-3119 + * SECURITY UPDATE: DoS (NULL pointer dereference) via an S4U2Self request + - debian/patches/CVE-2016-3120.patch: Fix S4U2Self KDC crash when anon + is restricted + - CVE-2016-3120 + * SECURITY UPDATE: KDC assertion failure + - debian/patches/CVE-2017-11368-1.patch: Prevent KDC unset status + assertion failures + - debian/patches/CVE-2017-11368-2.patch: Simplify KDC status assignment + - CVE-2017-11368 + * SECURITY UPDATE: Double free vulnerability + - debian/patches/CVE-2017-11462.patch: Preserve GSS context on init/accept + failure + - CVE-2017-11462 + * SECURITY UPDATE: Authenticated kadmin with permission to add principals + to an LDAP Kerberos can DoS or bypass DN container check. + - debian/patches/CVE-2018-5729-CVE-2018-5730.patch: Fix flaws in LDAP DN + checking + - CVE-2018-5729 + - CVE-2018-5730 + + -- Eduardo Barretto Wed, 09 Jan 2019 14:01:22 -0200 + +krb5 (1.12+dfsg-2ubuntu5.3) trusty; urgency=medium + + * d/p/upstream/0001-Add-SPNEGO-special-case-for-NTLMSSP-MechListMIC.patch: + Cherry-pick from upstream to add SPNEGO special case for + NTLMSSP+MechListMIC. LP: #1643708. + + -- Steve Langasek Mon, 21 Nov 2016 18:14:47 -0800 + krb5 (1.12+dfsg-2ubuntu5.2) trusty-security; urgency=medium * SECURITY UPDATE: denial of service via incorrect null bytes diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2015-8629.patch krb5-1.12+dfsg/debian/patches/CVE-2015-8629.patch --- krb5-1.12+dfsg/debian/patches/CVE-2015-8629.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2015-8629.patch 2019-01-08 17:12:36.000000000 +0000 @@ -0,0 +1,45 @@ +From df17a1224a3406f57477bcd372c61e04c0e5a5bb Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 8 Jan 2016 12:45:25 -0500 +Subject: [PATCH] Verify decoded kadmin C strings [CVE-2015-8629] + +In xdr_nullstring(), check that the decoded string is terminated with +a zero byte and does not contain any internal zero bytes. + +CVE-2015-8629: + +In all versions of MIT krb5, an authenticated attacker can cause +kadmind to read beyond the end of allocated memory by sending a string +without a terminating zero byte. Information leakage may be possible +for an attacker with permission to modify the database. + + CVSSv2 Vector: AV:N/AC:H/Au:S/C:P/I:N/A:N/E:POC/RL:OF/RC:C + +ticket: 8341 (new) +target_version: 1.14-next +target_version: 1.13-next +tags: pullup +--- + src/lib/kadm5/kadm_rpc_xdr.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c +index 2bef858631..ba67084105 100644 +--- a/src/lib/kadm5/kadm_rpc_xdr.c ++++ b/src/lib/kadm5/kadm_rpc_xdr.c +@@ -64,7 +64,14 @@ bool_t xdr_nullstring(XDR *xdrs, char **objp) + return FALSE; + } + } +- return (xdr_opaque(xdrs, *objp, size)); ++ if (!xdr_opaque(xdrs, *objp, size)) ++ return FALSE; ++ /* Check that the unmarshalled bytes are a C string. */ ++ if ((*objp)[size - 1] != '\0') ++ return FALSE; ++ if (memchr(*objp, '\0', size - 1) != NULL) ++ return FALSE; ++ return TRUE; + + case XDR_ENCODE: + if (size != 0) diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2015-8630.patch krb5-1.12+dfsg/debian/patches/CVE-2015-8630.patch --- krb5-1.12+dfsg/debian/patches/CVE-2015-8630.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2015-8630.patch 2019-01-08 17:12:44.000000000 +0000 @@ -0,0 +1,75 @@ +From b863de7fbf080b15e347a736fdda0a82d42f4f6b Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 8 Jan 2016 12:52:28 -0500 +Subject: [PATCH] Check for null kadm5 policy name [CVE-2015-8630] + +In kadm5_create_principal_3() and kadm5_modify_principal(), check for +entry->policy being null when KADM5_POLICY is included in the mask. + +CVE-2015-8630: + +In MIT krb5 1.12 and later, an authenticated attacker with permission +to modify a principal entry can cause kadmind to dereference a null +pointer by supplying a null policy value but including KADM5_POLICY in +the mask. + + CVSSv2 Vector: AV:N/AC:H/Au:S/C:N/I:N/A:C/E:POC/RL:OF/RC:C + +ticket: 8342 (new) +target_version: 1.14-next +target_version: 1.13-next +tags: pullup +--- + src/lib/kadm5/srv/svr_principal.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c +index 5b95fa3e13..1d4365c836 100644 +--- a/src/lib/kadm5/srv/svr_principal.c ++++ b/src/lib/kadm5/srv/svr_principal.c +@@ -395,6 +395,8 @@ kadm5_create_principal_3(void *server_handle, + /* + * Argument sanity checking, and opening up the DB + */ ++ if (entry == NULL) ++ return EINVAL; + if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || + (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || + (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || +@@ -403,12 +405,12 @@ kadm5_create_principal_3(void *server_handle, + return KADM5_BAD_MASK; + if ((mask & KADM5_KEY_DATA) && entry->n_key_data != 0) + return KADM5_BAD_MASK; ++ if((mask & KADM5_POLICY) && entry->policy == NULL) ++ return KADM5_BAD_MASK; + if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) + return KADM5_BAD_MASK; + if((mask & ~ALL_PRINC_MASK)) + return KADM5_BAD_MASK; +- if (entry == NULL) +- return EINVAL; + + /* + * Check to see if the principal exists +@@ -643,6 +645,8 @@ kadm5_modify_principal(void *server_handle, + + krb5_clear_error_message(handle->context); + ++ if(entry == NULL) ++ return EINVAL; + if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || + (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || + (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || +@@ -651,10 +655,10 @@ kadm5_modify_principal(void *server_handle, + return KADM5_BAD_MASK; + if((mask & ~ALL_PRINC_MASK)) + return KADM5_BAD_MASK; ++ if((mask & KADM5_POLICY) && entry->policy == NULL) ++ return KADM5_BAD_MASK; + if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) + return KADM5_BAD_MASK; +- if(entry == (kadm5_principal_ent_t) NULL) +- return EINVAL; + if (mask & KADM5_TL_DATA) { + tl_data_orig = entry->tl_data; + while (tl_data_orig) { diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2015-8631.patch krb5-1.12+dfsg/debian/patches/CVE-2015-8631.patch --- krb5-1.12+dfsg/debian/patches/CVE-2015-8631.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2015-8631.patch 2019-01-08 17:33:01.000000000 +0000 @@ -0,0 +1,570 @@ +From 83ed75feba32e46f736fcce0d96a0445f29b96c2 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 8 Jan 2016 13:16:54 -0500 +Subject: [PATCH] Fix leaks in kadmin server stubs [CVE-2015-8631] + +In each kadmind server stub, initialize the client_name and +server_name variables, and release them in the cleanup handler. Many +of the stubs will otherwise leak the client and server name if +krb5_unparse_name() fails. Also make sure to free the prime_arg +variables in rename_principal_2_svc(), or we can leak the first one if +unparsing the second one fails. Discovered by Simo Sorce. + +CVE-2015-8631: + +In all versions of MIT krb5, an authenticated attacker can cause +kadmind to leak memory by supplying a null principal name in a request +which uses one. Repeating these requests will eventually cause +kadmind to exhaust all available memory. + + CVSSv2 Vector: AV:N/AC:L/Au:S/C:N/I:N/A:C/E:POC/RL:OF/RC:C + +ticket: 8343 (new) +target_version: 1.14-next +target_version: 1.13-next +tags: pullup +--- + src/kadmin/server/server_stubs.c | 151 ++++++++++++++++--------------- + 1 file changed, 77 insertions(+), 74 deletions(-) + +diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c +index 1879dc67ef..6ac797e288 100644 +--- a/src/kadmin/server/server_stubs.c ++++ b/src/kadmin/server/server_stubs.c +@@ -334,7 +334,8 @@ create_principal_2_svc(cprinc_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + restriction_t *rp; +@@ -382,10 +383,10 @@ create_principal_2_svc(cprinc_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); +- gss_release_buffer(&minor_stat, &client_name); +- gss_release_buffer(&minor_stat, &service_name); + + exit_func: ++ gss_release_buffer(&minor_stat, &client_name); ++ gss_release_buffer(&minor_stat, &service_name); + free_server_handle(handle); + return &ret; + } +@@ -395,7 +396,8 @@ create_principal3_2_svc(cprinc3_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + restriction_t *rp; +@@ -444,10 +446,10 @@ create_principal3_2_svc(cprinc3_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); +- gss_release_buffer(&minor_stat, &client_name); +- gss_release_buffer(&minor_stat, &service_name); + + exit_func: ++ gss_release_buffer(&minor_stat, &client_name); ++ gss_release_buffer(&minor_stat, &service_name); + free_server_handle(handle); + return &ret; + } +@@ -457,8 +459,8 @@ delete_principal_2_svc(dprinc_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -501,10 +503,10 @@ delete_principal_2_svc(dprinc_arg *arg, struct svc_req *rqstp) + + } + free(prime_arg); +- gss_release_buffer(&minor_stat, &client_name); +- gss_release_buffer(&minor_stat, &service_name); + + exit_func: ++ gss_release_buffer(&minor_stat, &client_name); ++ gss_release_buffer(&minor_stat, &service_name); + free_server_handle(handle); + return &ret; + } +@@ -514,8 +516,8 @@ modify_principal_2_svc(mprinc_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + restriction_t *rp; +@@ -559,9 +561,9 @@ modify_principal_2_svc(mprinc_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -570,10 +572,9 @@ generic_ret * + rename_principal_2_svc(rprinc_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; +- char *prime_arg1, +- *prime_arg2; +- gss_buffer_desc client_name, +- service_name; ++ char *prime_arg1 = NULL, *prime_arg2 = NULL; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + restriction_t *rp; +@@ -655,11 +656,11 @@ rename_principal_2_svc(rprinc_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + + } ++exit_func: + free(prime_arg1); + free(prime_arg2); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -669,8 +670,8 @@ get_principal_2_svc(gprinc_arg *arg, struct svc_req *rqstp) + { + static gprinc_ret ret; + char *prime_arg, *funcname; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -719,9 +720,9 @@ get_principal_2_svc(gprinc_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -731,8 +732,8 @@ get_princs_2_svc(gprincs_arg *arg, struct svc_req *rqstp) + { + static gprincs_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -777,9 +778,9 @@ get_princs_2_svc(gprincs_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + + } ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -789,8 +790,8 @@ chpass_principal_2_svc(chpass_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -840,9 +841,9 @@ chpass_principal_2_svc(chpass_arg *arg, struct svc_req *rqstp) + } + + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -852,8 +853,8 @@ chpass_principal3_2_svc(chpass3_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -909,9 +910,9 @@ chpass_principal3_2_svc(chpass3_arg *arg, struct svc_req *rqstp) + } + + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -921,8 +922,8 @@ setv4key_principal_2_svc(setv4key_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -969,9 +970,9 @@ setv4key_principal_2_svc(setv4key_arg *arg, struct svc_req *rqstp) + } + + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -981,8 +982,8 @@ setkey_principal_2_svc(setkey_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1029,9 +1030,9 @@ setkey_principal_2_svc(setkey_arg *arg, struct svc_req *rqstp) + } + + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1041,8 +1042,8 @@ setkey_principal3_2_svc(setkey3_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1092,9 +1093,9 @@ setkey_principal3_2_svc(setkey3_arg *arg, struct svc_req *rqstp) + } + + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1106,8 +1107,8 @@ chrand_principal_2_svc(chrand_arg *arg, struct svc_req *rqstp) + krb5_keyblock *k; + int nkeys; + char *prime_arg, *funcname; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1164,9 +1165,9 @@ chrand_principal_2_svc(chrand_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1178,8 +1179,8 @@ chrand_principal3_2_svc(chrand3_arg *arg, struct svc_req *rqstp) + krb5_keyblock *k; + int nkeys; + char *prime_arg, *funcname; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1241,9 +1242,9 @@ chrand_principal3_2_svc(chrand3_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1253,8 +1254,8 @@ create_policy_2_svc(cpol_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1295,9 +1296,9 @@ create_policy_2_svc(cpol_arg *arg, struct svc_req *rqstp) + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1307,8 +1308,8 @@ delete_policy_2_svc(dpol_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1347,9 +1348,9 @@ delete_policy_2_svc(dpol_arg *arg, struct svc_req *rqstp) + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1359,8 +1360,8 @@ modify_policy_2_svc(mpol_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1400,9 +1401,9 @@ modify_policy_2_svc(mpol_arg *arg, struct svc_req *rqstp) + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1413,8 +1414,8 @@ get_policy_2_svc(gpol_arg *arg, struct svc_req *rqstp) + static gpol_ret ret; + kadm5_ret_t ret2; + char *prime_arg, *funcname; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_principal_ent_rec caller_ent; + kadm5_server_handle_t handle; +@@ -1475,9 +1476,9 @@ get_policy_2_svc(gpol_arg *arg, struct svc_req *rqstp) + log_unauth(funcname, prime_arg, + &client_name, &service_name, rqstp); + } ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + +@@ -1488,8 +1489,8 @@ get_pols_2_svc(gpols_arg *arg, struct svc_req *rqstp) + { + static gpols_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1531,9 +1532,9 @@ get_pols_2_svc(gpols_arg *arg, struct svc_req *rqstp) + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1541,7 +1542,8 @@ get_pols_2_svc(gpols_arg *arg, struct svc_req *rqstp) + getprivs_ret * get_privs_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) + { + static getprivs_ret ret; +- gss_buffer_desc client_name, service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1571,9 +1573,9 @@ getprivs_ret * get_privs_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1583,7 +1585,8 @@ purgekeys_2_svc(purgekeys_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg, *funcname; +- gss_buffer_desc client_name, service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + +@@ -1629,9 +1632,9 @@ purgekeys_2_svc(purgekeys_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1641,8 +1644,8 @@ get_strings_2_svc(gstrings_arg *arg, struct svc_req *rqstp) + { + static gstrings_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1688,9 +1691,9 @@ get_strings_2_svc(gstrings_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1700,8 +1703,8 @@ set_string_2_svc(sstring_arg *arg, struct svc_req *rqstp) + { + static generic_ret ret; + char *prime_arg; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; +@@ -1744,9 +1747,9 @@ set_string_2_svc(sstring_arg *arg, struct svc_req *rqstp) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); ++exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +-exit_func: + free_server_handle(handle); + return &ret; + } +@@ -1754,8 +1757,8 @@ set_string_2_svc(sstring_arg *arg, struct svc_req *rqstp) + generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) + { + static generic_ret ret; +- gss_buffer_desc client_name, +- service_name; ++ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + kadm5_server_handle_t handle; + OM_uint32 minor_stat; + const char *errmsg = NULL; +@@ -1797,10 +1800,10 @@ generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) + rqstp->rq_cred.oa_flavor); + if (errmsg != NULL) + krb5_free_error_message(NULL, errmsg); +- gss_release_buffer(&minor_stat, &client_name); +- gss_release_buffer(&minor_stat, &service_name); + + exit_func: ++ gss_release_buffer(&minor_stat, &client_name); ++ gss_release_buffer(&minor_stat, &service_name); + return(&ret); + } + diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2016-3119.patch krb5-1.12+dfsg/debian/patches/CVE-2016-3119.patch --- krb5-1.12+dfsg/debian/patches/CVE-2016-3119.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2016-3119.patch 2019-01-08 17:38:20.000000000 +0000 @@ -0,0 +1,38 @@ +From 08c642c09c38a9c6454ab43a9b53b2a89b9eef99 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Mon, 14 Mar 2016 17:26:34 -0400 +Subject: [PATCH] Fix LDAP null deref on empty arg [CVE-2016-3119] + +In the LDAP KDB module's process_db_args(), strtok_r() may return NULL +if there is an empty string in the db_args array. Check for this case +and avoid dereferencing a null pointer. + +CVE-2016-3119: + +In MIT krb5 1.6 and later, an authenticated attacker with permission +to modify a principal entry can cause kadmind to dereference a null +pointer by supplying an empty DB argument to the modify_principal +command, if kadmind is configured to use the LDAP KDB module. + + CVSSv2 Vector: AV:N/AC:H/Au:S/C:N/I:N/A:C/E:H/RL:OF/RC:ND + +ticket: 8383 (new) +target_version: 1.14-next +target_version: 1.13-next +tags: pullup +--- + src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +index 6e591e1974..79c4cf05cc 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +@@ -296,6 +296,7 @@ process_db_args(krb5_context context, char **db_args, xargs_t *xargs, + if (db_args) { + for (i=0; db_args[i]; ++i) { + arg = strtok_r(db_args[i], "=", &arg_val); ++ arg = (arg != NULL) ? arg : ""; + if (strcmp(arg, TKTPOLICY_ARG) == 0) { + dptr = &xargs->tktpolicydn; + } else { diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2016-3120.patch krb5-1.12+dfsg/debian/patches/CVE-2016-3120.patch --- krb5-1.12+dfsg/debian/patches/CVE-2016-3120.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2016-3120.patch 2019-01-08 17:39:43.000000000 +0000 @@ -0,0 +1,54 @@ +From 93b4a6306a0026cf1cc31ac4bd8a49ba5d034ba7 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Tue, 19 Jul 2016 11:00:28 -0400 +Subject: [PATCH] Fix S4U2Self KDC crash when anon is restricted + +In validate_as_request(), when enforcing restrict_anonymous_to_tgt, +use client.princ instead of request->client; the latter is NULL when +validating S4U2Self requests. + +CVE-2016-3120: + +In MIT krb5 1.9 and later, an authenticated attacker can cause krb5kdc +to dereference a null pointer if the restrict_anonymous_to_tgt option +is set to true, by making an S4U2Self request. + + CVSSv2 Vector: AV:N/AC:H/Au:S/C:N/I:N/A:C/E:H/RL:OF/RC:C + +ticket: 8458 (new) +target_version: 1.14-next +target_version: 1.13-next +--- + src/kdc/kdc_util.c | 2 +- + src/tests/t_pkinit.py | 5 +++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index 776e130e55..29f9dbbf07 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -739,7 +739,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm, + return(KDC_ERR_MUST_USE_USER2USER); + } + +- if (check_anon(kdc_active_realm, request->client, request->server) != 0) { ++ if (check_anon(kdc_active_realm, client.princ, request->server) != 0) { + *status = "ANONYMOUS NOT ALLOWED"; + return(KDC_ERR_POLICY); + } +diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py +index b66c458dff..f0214b6529 100755 +--- a/src/tests/t_pkinit.py ++++ b/src/tests/t_pkinit.py +@@ -93,6 +93,11 @@ + if 'KDC policy rejects request' not in out: + fail('Wrong error for restricted anonymous PKINIT') + ++# Regression test for #8458: S4U2Self requests crash the KDC if ++# anonymous is restricted. ++realm.kinit(realm.host_princ, flags=['-k']) ++realm.run([kvno, '-U', 'user', realm.host_princ]) ++ + # Go back to a normal KDC and disable anonymous PKINIT. + realm.stop_kdc() + realm.start_kdc() diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2017-11368-1.patch krb5-1.12+dfsg/debian/patches/CVE-2017-11368-1.patch --- krb5-1.12+dfsg/debian/patches/CVE-2017-11368-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2017-11368-1.patch 2019-01-08 17:55:45.000000000 +0000 @@ -0,0 +1,107 @@ +From ffb35baac6981f9e8914f8f3bffd37f284b85970 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 13 Jul 2017 12:14:20 -0400 +Subject: [PATCH] Prevent KDC unset status assertion failures + +Assign status values if S4U2Self padata fails to decode, if an +S4U2Proxy request uses invalid KDC options, or if an S4U2Proxy request +uses an evidence ticket which does not match the canonicalized request +server principal name. Reported by Samuel Cabrero. + +If a status value is not assigned during KDC processing, default to +"UNKNOWN_REASON" rather than failing an assertion. This change will +prevent future denial of service bugs due to similar mistakes, and +will allow us to omit assigning status values for unlikely errors such +as small memory allocation failures. + +CVE-2017-11368: + +In MIT krb5 1.7 and later, an authenticated attacker can cause an +assertion failure in krb5kdc by sending an invalid S4U2Self or +S4U2Proxy request. + + CVSSv3 Vector: AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C + +ticket: 8599 (new) +target_version: 1.15-next +target_version: 1.14-next +tags: pullup +--- + src/kdc/do_as_req.c | 4 ++-- + src/kdc/do_tgs_req.c | 3 ++- + src/kdc/kdc_util.c | 10 ++++++++-- + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c +index 2d3ad134d0..9b256c8764 100644 +--- a/src/kdc/do_as_req.c ++++ b/src/kdc/do_as_req.c +@@ -366,8 +366,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + did_log = 1; + + egress: +- if (errcode != 0) +- assert (state->status != 0); ++ if (errcode != 0 && state->status == NULL) ++ state->status = "UNKNOWN_REASON"; + + au_state->status = state->status; + au_state->reply = &state->reply; +diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c +index cdc79ad2f1..d8d67199b9 100644 +--- a/src/kdc/do_tgs_req.c ++++ b/src/kdc/do_tgs_req.c +@@ -823,7 +823,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + free(reply.enc_part.ciphertext.data); + + cleanup: +- assert(status != NULL); ++ if (status == NULL) ++ status = "UNKNOWN_REASON"; + if (reply_key) + krb5_free_keyblock(kdc_context, reply_key); + if (errcode) +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index 778a629e52..b710aefe4c 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -1220,8 +1220,10 @@ kdc_process_for_user(kdc_realm_t *kdc_active_realm, + req_data.data = (char *)pa_data->contents; + + code = decode_krb5_pa_for_user(&req_data, &for_user); +- if (code) ++ if (code) { ++ *status = "DECODE_PA_FOR_USER"; + return code; ++ } + + code = verify_for_user_checksum(kdc_context, tgs_session, for_user); + if (code) { +@@ -1320,8 +1322,10 @@ kdc_process_s4u_x509_user(krb5_context context, + req_data.data = (char *)pa_data->contents; + + code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user); +- if (code) ++ if (code) { ++ *status = "DECODE_PA_S4U_X509_USER"; + return code; ++ } + + code = verify_s4u_x509_user_checksum(context, + tgs_subkey ? tgs_subkey : +@@ -1624,6 +1628,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, + * that is validated previously in validate_tgs_request(). + */ + if (request->kdc_options & (NON_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY)) { ++ *status = "INVALID_S4U2PROXY_OPTIONS"; + return KRB5KDC_ERR_BADOPTION; + } + +@@ -1631,6 +1636,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, + if (!krb5_principal_compare(kdc_context, + server->princ, /* after canon */ + server_princ)) { ++ *status = "EVIDENCE_TICKET_MISMATCH"; + return KRB5KDC_ERR_SERVER_NOMATCH; + } + diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2017-11368-2.patch krb5-1.12+dfsg/debian/patches/CVE-2017-11368-2.patch --- krb5-1.12+dfsg/debian/patches/CVE-2017-11368-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2017-11368-2.patch 2019-01-08 19:31:46.000000000 +0000 @@ -0,0 +1,317 @@ +From d265f16b71058b0cb0546a3993c941975a48b70f Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Mon, 17 Jul 2017 13:11:54 -0400 +Subject: [PATCH] Simplify KDC status assignment + +Omit assigning status values for very unlikely error cases. Remove +the "UNKNOWN_REASON" fallback for validate_as_request() and +validate_tgs_request() as that fallback is now applied globally. +--- + src/kdc/do_as_req.c | 51 ++++++++++--------------------------------- + src/kdc/do_tgs_req.c | 52 ++++++++++---------------------------------- + 2 files changed, 24 insertions(+), 79 deletions(-) + +diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c +index 9b256c8764..5d49e80362 100644 +--- a/src/kdc/do_as_req.c ++++ b/src/kdc/do_as_req.c +@@ -219,10 +219,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + state->reply.ticket = &state->ticket_reply; + state->reply_encpart.session = &state->session_key; + if ((errcode = fetch_last_req_info(state->client, +- &state->reply_encpart.last_req))) { +- state->status = "FETCH_LAST_REQ"; ++ &state->reply_encpart.last_req))) + goto egress; +- } + state->reply_encpart.nonce = state->request->nonce; + state->reply_encpart.key_exp = get_key_exp(state->client); + state->reply_encpart.flags = state->enc_tkt_reply.flags; +@@ -278,27 +276,21 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + + errcode = krb5_encrypt_tkt_part(kdc_context, &state->server_keyblock, + &state->ticket_reply); +- if (errcode) { +- state->status = "ENCRYPTING_TICKET"; ++ if (errcode) + goto egress; +- } + + errcode = kau_make_tkt_id(kdc_context, &state->ticket_reply, + &au_state->tkt_out_id); +- if (errcode) { +- state->status = "GENERATE_TICKET_ID"; ++ if (errcode) + goto egress; +- } + + state->ticket_reply.enc_part.kvno = server_key->key_data_kvno; + errcode = kdc_fast_response_handle_padata(state->rstate, + state->request, + &state->reply, + state->client_keyblock.enctype); +- if (errcode) { +- state->status = "fast response handling"; ++ if (errcode) + goto egress; +- } + + /* now encode/encrypt the response */ + +@@ -306,10 +298,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + + errcode = kdc_fast_handle_reply_key(state->rstate, &state->client_keyblock, + &as_encrypting_key); +- if (errcode) { +- state->status = "generating reply key"; ++ if (errcode) + goto egress; +- } + errcode = return_enc_padata(kdc_context, state->req_pkt, state->request, + as_encrypting_key, state->server, + &state->reply_encpart, FALSE); +@@ -326,10 +316,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + &state->reply, &response); + if (client_key != NULL) + state->reply.enc_part.kvno = client_key->key_data_kvno; +- if (errcode) { +- state->status = "ENCODE_KDC_REP"; ++ if (errcode) + goto egress; +- } + + /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we + can use them in raw form if needed. But, we don't... */ +@@ -519,7 +507,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + if (fetch_asn1_field((unsigned char *) req_pkt->data, + 1, 4, &encoded_req_body) != 0) { + errcode = ASN1_BAD_ID; +- state->status = "Finding req_body"; + goto errout; + } + errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL, +@@ -532,10 +519,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + /* Not a FAST request; copy the encoded request body. */ + errcode = krb5_copy_data(kdc_context, &encoded_req_body, + &state->inner_body); +- if (errcode) { +- state->status = "storing req body"; ++ if (errcode) + goto errout; +- } + } + au_state->request = state->request; + state->rock.request = state->request; +@@ -549,10 +534,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + } + if ((errcode = krb5_unparse_name(kdc_context, + state->request->client, +- &state->cname))) { +- state->status = "UNPARSING_CLIENT"; ++ &state->cname))) + goto errout; +- } + limit_string(state->cname); + + /* +@@ -611,10 +594,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + } + if ((errcode = krb5_unparse_name(kdc_context, + state->request->server, +- &state->sname))) { +- state->status = "UNPARSING_SERVER"; ++ &state->sname))) + goto errout; +- } + limit_string(state->sname); + s_flags = 0; + setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK); +@@ -636,18 +617,14 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + + au_state->stage = VALIDATE_POL; + +- if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) { +- state->status = "TIMEOFDAY"; ++ if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) + goto errout; +- } + state->authtime = state->kdc_time; /* for audit_as_request() */ + + if ((errcode = validate_as_request(kdc_active_realm, + state->request, *state->client, + *state->server, state->kdc_time, + &state->status, &state->e_data))) { +- if (!state->status) +- state->status = "UNKNOWN_REASON"; + errcode += ERROR_TABLE_BASE_krb5; + goto errout; + } +@@ -667,10 +644,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + } + + if ((errcode = krb5_c_make_random_key(kdc_context, useenctype, +- &state->session_key))) { +- state->status = "RANDOM_KEY_FAILED"; ++ &state->session_key))) + goto errout; +- } + + /* + * Canonicalization is only effective if we are issuing a TGT +@@ -761,10 +746,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, + state->request->client = NULL; + errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(), + &state->request->client); +- if (errcode) { +- state->status = "Copying anonymous principal"; ++ if (errcode) + goto errout; +- } + state->enc_tkt_reply.client = state->request->client; + setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH); + } +diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c +index d8d67199b9..84445ed904 100644 +--- a/src/kdc/do_tgs_req.c ++++ b/src/kdc/do_tgs_req.c +@@ -188,15 +188,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + + if (!header_ticket) { + errcode = KRB5_NO_TKT_SUPPLIED; /* XXX? */ +- status="UNEXPECTED NULL in header_ticket"; + goto cleanup; + } + errcode = kau_make_tkt_id(kdc_context, header_ticket, + &au_state->tkt_in_id); +- if (errcode) { +- status = "GENERATE_TICKET_ID"; ++ if (errcode) + goto cleanup; +- } + + scratch.length = pa_tgs_req->length; + scratch.data = (char *) pa_tgs_req->contents; +@@ -248,16 +245,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + + au_state->stage = VALIDATE_POL; + +- if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) { +- status = "TIME_OF_DAY"; ++ if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) + goto cleanup; +- } + + if ((retval = validate_tgs_request(kdc_active_realm, + request, *server, header_ticket, + kdc_time, &status, &e_data))) { +- if (!status) +- status = "UNKNOWN_REASON"; + if (retval == KDC_ERR_POLICY || retval == KDC_ERR_BADOPTION) + au_state->violation = PROT_CONSTRAINT; + errcode = retval + ERROR_TABLE_BASE_krb5; +@@ -324,7 +317,6 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + retval = kau_make_tkt_id(kdc_context, request->second_ticket[st_idx], + &au_state->evid_tkt_id); + if (retval) { +- status = "GENERATE_TICKET_ID"; + errcode = retval; + goto cleanup; + } +@@ -715,10 +707,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + &ticket_reply); + if (!isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) + krb5_free_keyblock_contents(kdc_context, &encrypting_key); +- if (errcode) { +- status = "TKT_ENCRYPT"; ++ if (errcode) + goto cleanup; +- } + ticket_reply.enc_part.kvno = ticket_kvno; + /* Start assembling the response */ + au_state->stage = ENCR_REP; +@@ -732,10 +722,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + s4u_x509_user, + &reply, + &reply_encpart); +- if (errcode) { +- status = "KDC_RETURN_S4U2SELF_PADATA"; ++ if (errcode) + au_state->status = status; +- } + kau_s4u2self(kdc_context, errcode ? FALSE : TRUE, au_state); + if (errcode) + goto cleanup; +@@ -772,16 +760,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + header_ticket->enc_part2->session->enctype; + errcode = kdc_fast_response_handle_padata(state, request, &reply, + subkey ? subkey->enctype : header_ticket->enc_part2->session->enctype); +- if (errcode !=0 ) { +- status = "Preparing FAST padata"; ++ if (errcode) + goto cleanup; +- } + errcode =kdc_fast_handle_reply_key(state, + subkey?subkey:header_ticket->enc_part2->session, &reply_key); +- if (errcode) { +- status = "generating reply key"; ++ if (errcode) + goto cleanup; +- } + errcode = return_enc_padata(kdc_context, pkt, request, + reply_key, server, &reply_encpart, + is_referral && +@@ -793,10 +777,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + } + + errcode = kau_make_tkt_id(kdc_context, &ticket_reply, &au_state->tkt_out_id); +- if (errcode) { +- status = "GENERATE_TICKET_ID"; ++ if (errcode) + goto cleanup; +- } + + if (kdc_fast_hide_client(state)) + reply.client = (krb5_principal)krb5_anonymous_principal(); +@@ -804,11 +786,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + subkey ? 1 : 0, + reply_key, + &reply, response); +- if (errcode) { +- status = "ENCODE_KDC_REP"; +- } else { ++ if (!errcode) + status = "ISSUE"; +- } + + memset(ticket_reply.enc_part.ciphertext.data, 0, + ticket_reply.enc_part.ciphertext.length); +@@ -1045,7 +1024,7 @@ gen_session_key(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req, + retval = get_2ndtkt_enctype(kdc_active_realm, req, &useenctype, + status); + if (retval != 0) +- goto cleanup; ++ return retval; + } + if (useenctype == 0) { + useenctype = select_session_keytype(kdc_active_realm, server, +@@ -1055,17 +1034,10 @@ gen_session_key(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req, + if (useenctype == 0) { + /* unsupported ktype */ + *status = "BAD_ENCRYPTION_TYPE"; +- retval = KRB5KDC_ERR_ETYPE_NOSUPP; +- goto cleanup; +- } +- retval = krb5_c_make_random_key(kdc_context, useenctype, skey); +- if (retval != 0) { +- /* random key failed */ +- *status = "RANDOM_KEY_FAILED"; +- goto cleanup; ++ return KRB5KDC_ERR_ETYPE_NOSUPP; + } +-cleanup: +- return retval; ++ ++ return krb5_c_make_random_key(kdc_context, useenctype, skey); + } + + /* diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2017-11462.patch krb5-1.12+dfsg/debian/patches/CVE-2017-11462.patch --- krb5-1.12+dfsg/debian/patches/CVE-2017-11462.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2017-11462.patch 2019-01-08 19:50:56.000000000 +0000 @@ -0,0 +1,408 @@ +From 56f7b1bc95a2a3eeb420e069e7655fb181ade5cf Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 14 Jul 2017 13:02:46 -0400 +Subject: [PATCH] Preserve GSS context on init/accept failure + +After gss_init_sec_context() or gss_accept_sec_context() has created a +context, don't delete the mechglue context on failures from subsequent +calls, even if the mechanism deletes the mech-specific context (which +is allowed by RFC 2744 but not preferred). Check for union contexts +with no mechanism context in each GSS function which accepts a +gss_ctx_id_t. + +CVE-2017-11462: + +RFC 2744 permits a GSS-API implementation to delete an existing +security context on a second or subsequent call to +gss_init_sec_context() or gss_accept_sec_context() if the call results +in an error. This API behavior has been found to be dangerous, +leading to the possibility of memory errors in some callers. For +safety, GSS-API implementations should instead preserve existing +security contexts on error until the caller deletes them. + +All versions of MIT krb5 prior to this change may delete acceptor +contexts on error. Versions 1.13.4 through 1.13.7, 1.14.1 through +1.14.5, and 1.15 through 1.15.1 may also delete initiator contexts on +error. + +ticket: 8598 (new) +target_version: 1.15-next +target_version: 1.14-next +tags: pullup +--- + .../gssapi/mechglue/g_accept_sec_context.c | 22 +++++++++++++------ + .../gssapi/mechglue/g_complete_auth_token.c | 2 ++ + src/lib/gssapi/mechglue/g_context_time.c | 2 ++ + .../gssapi/mechglue/g_delete_sec_context.c | 14 +++++++----- + src/lib/gssapi/mechglue/g_exp_sec_context.c | 2 ++ + src/lib/gssapi/mechglue/g_init_sec_context.c | 19 +++++++++------- + src/lib/gssapi/mechglue/g_inq_context.c | 2 ++ + src/lib/gssapi/mechglue/g_prf.c | 2 ++ + src/lib/gssapi/mechglue/g_process_context.c | 2 ++ + src/lib/gssapi/mechglue/g_seal.c | 4 ++++ + src/lib/gssapi/mechglue/g_sign.c | 2 ++ + src/lib/gssapi/mechglue/g_unseal.c | 2 ++ + src/lib/gssapi/mechglue/g_unwrap_aead.c | 2 ++ + src/lib/gssapi/mechglue/g_unwrap_iov.c | 4 ++++ + src/lib/gssapi/mechglue/g_verify.c | 2 ++ + src/lib/gssapi/mechglue/g_wrap_aead.c | 2 ++ + src/lib/gssapi/mechglue/g_wrap_iov.c | 8 +++++++ + 17 files changed, 72 insertions(+), 21 deletions(-) + +diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c +index ddaf87412e..f28e2b14a9 100644 +--- a/src/lib/gssapi/mechglue/g_accept_sec_context.c ++++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c +@@ -185,6 +185,8 @@ gss_cred_id_t * d_cred; + } else { + union_ctx_id = (gss_union_ctx_id_t)*context_handle; + selected_mech = union_ctx_id->mech_type; ++ if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + } + + /* Now create a new context if we didn't get one. */ +@@ -203,9 +205,6 @@ gss_cred_id_t * d_cred; + free(union_ctx_id); + return (status); + } +- +- /* set the new context handle to caller's data */ +- *context_handle = (gss_ctx_id_t)union_ctx_id; + } + + /* +@@ -243,8 +242,10 @@ gss_cred_id_t * d_cred; + d_cred ? &tmp_d_cred : NULL); + + /* If there's more work to do, keep going... */ +- if (status == GSS_S_CONTINUE_NEEDED) ++ if (status == GSS_S_CONTINUE_NEEDED) { ++ *context_handle = (gss_ctx_id_t)union_ctx_id; + return GSS_S_CONTINUE_NEEDED; ++ } + + /* if the call failed, return with failure */ + if (status != GSS_S_COMPLETE) { +@@ -330,14 +331,22 @@ gss_cred_id_t * d_cred; + *mech_type = gssint_get_public_oid(actual_mech); + if (ret_flags != NULL) + *ret_flags = temp_ret_flags; +- return (status); ++ *context_handle = (gss_ctx_id_t)union_ctx_id; ++ return GSS_S_COMPLETE; + } else { + + status = GSS_S_BAD_MECH; + } + + error_out: +- if (union_ctx_id) { ++ /* ++ * RFC 2744 5.1 requires that we not create a context on a failed first ++ * call to accept, and recommends that on a failed subsequent call we ++ * make the caller responsible for calling gss_delete_sec_context. ++ * Even if the mech deleted its context, keep the union context around ++ * for the caller to delete. ++ */ ++ if (union_ctx_id && *context_handle == GSS_C_NO_CONTEXT) { + if (union_ctx_id->mech_type) { + if (union_ctx_id->mech_type->elements) + free(union_ctx_id->mech_type->elements); +@@ -350,7 +359,6 @@ gss_cred_id_t * d_cred; + GSS_C_NO_BUFFER); + } + free(union_ctx_id); +- *context_handle = GSS_C_NO_CONTEXT; + } + + if (src_name) +diff --git a/src/lib/gssapi/mechglue/g_complete_auth_token.c b/src/lib/gssapi/mechglue/g_complete_auth_token.c +index 9181551301..4bcb47e84b 100644 +--- a/src/lib/gssapi/mechglue/g_complete_auth_token.c ++++ b/src/lib/gssapi/mechglue/g_complete_auth_token.c +@@ -52,6 +52,8 @@ gss_complete_auth_token (OM_uint32 *minor_status, + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return GSS_S_NO_CONTEXT; + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech != NULL) { +diff --git a/src/lib/gssapi/mechglue/g_context_time.c b/src/lib/gssapi/mechglue/g_context_time.c +index 2ff8d0996e..c947e7646c 100644 +--- a/src/lib/gssapi/mechglue/g_context_time.c ++++ b/src/lib/gssapi/mechglue/g_context_time.c +@@ -58,6 +58,8 @@ OM_uint32 * time_rec; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c +index 4bf0dec5ce..574ff02944 100644 +--- a/src/lib/gssapi/mechglue/g_delete_sec_context.c ++++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c +@@ -87,12 +87,14 @@ gss_buffer_t output_token; + if (GSSINT_CHK_LOOP(ctx)) + return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); + +- status = gssint_delete_internal_sec_context(minor_status, +- ctx->mech_type, +- &ctx->internal_ctx_id, +- output_token); +- if (status) +- return status; ++ if (ctx->internal_ctx_id != GSS_C_NO_CONTEXT) { ++ status = gssint_delete_internal_sec_context(minor_status, ++ ctx->mech_type, ++ &ctx->internal_ctx_id, ++ output_token); ++ if (status) ++ return status; ++ } + + /* now free up the space for the union context structure */ + free(ctx->mech_type->elements); +diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c +index b63745299f..1d7990b1ca 100644 +--- a/src/lib/gssapi/mechglue/g_exp_sec_context.c ++++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c +@@ -95,6 +95,8 @@ gss_buffer_t interprocess_token; + */ + + ctx = (gss_union_ctx_id_t) *context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + if (!mech) + return GSS_S_BAD_MECH; +diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c +index 9f154b8936..e2df1ce261 100644 +--- a/src/lib/gssapi/mechglue/g_init_sec_context.c ++++ b/src/lib/gssapi/mechglue/g_init_sec_context.c +@@ -192,8 +192,13 @@ OM_uint32 * time_rec; + + /* copy the supplied context handle */ + union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT; +- } else ++ } else { + union_ctx_id = (gss_union_ctx_id_t)*context_handle; ++ if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) { ++ status = GSS_S_NO_CONTEXT; ++ goto end; ++ } ++ } + + /* + * get the appropriate cred handle from the union cred struct. +@@ -224,12 +229,13 @@ OM_uint32 * time_rec; + + if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) { + /* +- * the spec says (the preferred) method is to delete all +- * context info on the first call to init, and on all +- * subsequent calls make the caller responsible for +- * calling gss_delete_sec_context ++ * RFC 2744 5.19 requires that we not create a context on a failed ++ * first call to init, and recommends that on a failed subsequent call ++ * we make the caller responsible for calling gss_delete_sec_context. ++ * Even if the mech deleted its context, keep the union context around ++ * for the caller to delete. + */ + map_error(minor_status, mech); + if (*context_handle == GSS_C_NO_CONTEXT) { + free(union_ctx_id->mech_type->elements); + free(union_ctx_id->mech_type); +diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c +index 6f1c71eede..6c0d98dd33 100644 +--- a/src/lib/gssapi/mechglue/g_inq_context.c ++++ b/src/lib/gssapi/mechglue/g_inq_context.c +@@ -104,6 +104,8 @@ gss_inquire_context( + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (!mech || !mech->gss_inquire_context || !mech->gss_display_name || +diff --git a/src/lib/gssapi/mechglue/g_prf.c b/src/lib/gssapi/mechglue/g_prf.c +index fcca3e44c4..9e168adfe0 100644 +--- a/src/lib/gssapi/mechglue/g_prf.c ++++ b/src/lib/gssapi/mechglue/g_prf.c +@@ -59,6 +59,8 @@ gss_pseudo_random (OM_uint32 *minor_status, + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return GSS_S_NO_CONTEXT; + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech != NULL) { +diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c +index bc260aeb10..3968b5d9c6 100644 +--- a/src/lib/gssapi/mechglue/g_process_context.c ++++ b/src/lib/gssapi/mechglue/g_process_context.c +@@ -61,6 +61,8 @@ gss_buffer_t token_buffer; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c +index f17241c908..3db1ee095b 100644 +--- a/src/lib/gssapi/mechglue/g_seal.c ++++ b/src/lib/gssapi/mechglue/g_seal.c +@@ -92,6 +92,8 @@ gss_wrap( OM_uint32 *minor_status, + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +@@ -226,6 +228,8 @@ gss_wrap_size_limit(OM_uint32 *minor_status, + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (!mech) +diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c +index 86d641aa2e..03fbd8c01f 100644 +--- a/src/lib/gssapi/mechglue/g_sign.c ++++ b/src/lib/gssapi/mechglue/g_sign.c +@@ -94,6 +94,8 @@ gss_buffer_t msg_token; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c +index 3e8053c6e9..c208635b67 100644 +--- a/src/lib/gssapi/mechglue/g_unseal.c ++++ b/src/lib/gssapi/mechglue/g_unseal.c +@@ -76,6 +76,8 @@ gss_qop_t * qop_state; + * call it. + */ + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +diff --git a/src/lib/gssapi/mechglue/g_unwrap_aead.c b/src/lib/gssapi/mechglue/g_unwrap_aead.c +index e78bff2d32..0682bd8998 100644 +--- a/src/lib/gssapi/mechglue/g_unwrap_aead.c ++++ b/src/lib/gssapi/mechglue/g_unwrap_aead.c +@@ -186,6 +186,8 @@ gss_qop_t *qop_state; + * call it. + */ + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (!mech) +diff --git a/src/lib/gssapi/mechglue/g_unwrap_iov.c b/src/lib/gssapi/mechglue/g_unwrap_iov.c +index c0dd314b1b..599be2c7b2 100644 +--- a/src/lib/gssapi/mechglue/g_unwrap_iov.c ++++ b/src/lib/gssapi/mechglue/g_unwrap_iov.c +@@ -89,6 +89,8 @@ int iov_count; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +@@ -128,6 +130,8 @@ gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, + + /* Select the approprate underlying mechanism routine and call it. */ + ctx = (gss_union_ctx_id_t)context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return GSS_S_NO_CONTEXT; + mech = gssint_get_mechanism(ctx->mech_type); + if (mech == NULL) + return GSS_S_BAD_MECH; +diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c +index 1578ae1110..8996fce8d5 100644 +--- a/src/lib/gssapi/mechglue/g_verify.c ++++ b/src/lib/gssapi/mechglue/g_verify.c +@@ -65,6 +65,8 @@ gss_qop_t * qop_state; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +diff --git a/src/lib/gssapi/mechglue/g_wrap_aead.c b/src/lib/gssapi/mechglue/g_wrap_aead.c +index 96cdf3ce6a..7fe3b7b35b 100644 +--- a/src/lib/gssapi/mechglue/g_wrap_aead.c ++++ b/src/lib/gssapi/mechglue/g_wrap_aead.c +@@ -256,6 +256,8 @@ gss_buffer_t output_message_buffer; + * call it. + */ + ctx = (gss_union_ctx_id_t)context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + if (!mech) + return (GSS_S_BAD_MECH); +diff --git a/src/lib/gssapi/mechglue/g_wrap_iov.c b/src/lib/gssapi/mechglue/g_wrap_iov.c +index 40cd98fc91..14447c4ee1 100644 +--- a/src/lib/gssapi/mechglue/g_wrap_iov.c ++++ b/src/lib/gssapi/mechglue/g_wrap_iov.c +@@ -93,6 +93,8 @@ int iov_count; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +@@ -151,6 +153,8 @@ int iov_count; + */ + + ctx = (gss_union_ctx_id_t) context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return (GSS_S_NO_CONTEXT); + mech = gssint_get_mechanism (ctx->mech_type); + + if (mech) { +@@ -190,6 +194,8 @@ gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, + + /* Select the approprate underlying mechanism routine and call it. */ + ctx = (gss_union_ctx_id_t)context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return GSS_S_NO_CONTEXT; + mech = gssint_get_mechanism(ctx->mech_type); + if (mech == NULL) + return GSS_S_BAD_MECH; +@@ -215,6 +221,8 @@ gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle, + + /* Select the approprate underlying mechanism routine and call it. */ + ctx = (gss_union_ctx_id_t)context_handle; ++ if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) ++ return GSS_S_NO_CONTEXT; + mech = gssint_get_mechanism(ctx->mech_type); + if (mech == NULL) + return GSS_S_BAD_MECH; diff -Nru krb5-1.12+dfsg/debian/patches/CVE-2018-5729-CVE-2018-5730.patch krb5-1.12+dfsg/debian/patches/CVE-2018-5729-CVE-2018-5730.patch --- krb5-1.12+dfsg/debian/patches/CVE-2018-5729-CVE-2018-5730.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/CVE-2018-5729-CVE-2018-5730.patch 2019-01-09 18:57:07.000000000 +0000 @@ -0,0 +1,350 @@ +From e1caf6fb74981da62039846931ebdffed71309d1 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 12 Jan 2018 11:43:01 -0500 +Subject: [PATCH] Fix flaws in LDAP DN checking + +KDB_TL_USER_INFO tl-data is intended to be internal to the LDAP KDB +module, and not used in disk or wire principal entries. Prevent +kadmin clients from sending KDB_TL_USER_INFO tl-data by giving it a +type number less than 256 and filtering out type numbers less than 256 +in kadm5_create_principal_3(). (We already filter out low type +numbers in kadm5_modify_principal()). + +In the LDAP KDB module, if containerdn and linkdn are both specified +in a put_principal operation, check both linkdn and the computed +standalone_principal_dn for container membership. To that end, factor +out the checks into helper functions and call them on all applicable +client-influenced DNs. + +CVE-2018-5729: + +In MIT krb5 1.6 or later, an authenticated kadmin user with permission +to add principals to an LDAP Kerberos database can cause a null +dereference in kadmind, or circumvent a DN container check, by +supplying tagged data intended to be internal to the database module. +Thanks to Sharwan Ram and Pooja Anil for discovering the potential +null dereference. + +CVE-2018-5730: + +In MIT krb5 1.6 or later, an authenticated kadmin user with permission +to add principals to an LDAP Kerberos database can circumvent a DN +containership check by supplying both a "linkdn" and "containerdn" +database argument, or by supplying a DN string which is a left +extension of a container DN string but is not hierarchically within +the container DN. + +ticket: 8643 (new) +tags: pullup +target_version: 1.16-next +target_version: 1.15-next +--- + src/lib/kadm5/srv/svr_principal.c | 7 + + src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h | 2 +- + .../kdb/ldap/libkdb_ldap/ldap_principal2.c | 200 ++++++++++-------- + src/tests/t_kdb.py | 11 + + 4 files changed, 125 insertions(+), 95 deletions(-) + +diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c +index 2420f2c2be..a59a65e8f6 100644 +--- a/src/lib/kadm5/srv/svr_principal.c ++++ b/src/lib/kadm5/srv/svr_principal.c +@@ -411,6 +411,13 @@ kadm5_create_principal_3(void *server_handle, + return KADM5_BAD_MASK; + if((mask & ~ALL_PRINC_MASK)) + return KADM5_BAD_MASK; ++ if (mask & KADM5_TL_DATA) { ++ for (tl_data_tail = entry->tl_data; tl_data_tail != NULL; ++ tl_data_tail = tl_data_tail->tl_data_next) { ++ if (tl_data_tail->tl_data_type < 256) ++ return KADM5_BAD_TL_TYPE; ++ } ++ } + + /* + * Check to see if the principal exists +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h +index 535a1f309e..8b8420faa9 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h ++++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h +@@ -140,7 +140,7 @@ extern int set_ldap_error (krb5_context ctx, int st, int op); + #define UNSTORE16_INT(ptr, val) (val = load_16_be(ptr)) + #define UNSTORE32_INT(ptr, val) (val = load_32_be(ptr)) + +-#define KDB_TL_USER_INFO 0x7ffe ++#define KDB_TL_USER_INFO 0xff + + #define KDB_TL_PRINCTYPE 0x01 + #define KDB_TL_PRINCCOUNT 0x02 +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +index 88a1704950..b7c9212cb2 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +@@ -486,6 +486,107 @@ update_ldap_mod_auth_ind(krb5_context context, krb5_db_entry *entry, + return 0; + } + ++static krb5_error_code ++check_dn_in_container(krb5_context context, const char *dn, ++ char *const *subtrees, unsigned int ntrees) ++{ ++ unsigned int i; ++ size_t dnlen = strlen(dn), stlen; ++ ++ for (i = 0; i < ntrees; i++) { ++ if (subtrees[i] == NULL || *subtrees[i] == '\0') ++ return 0; ++ stlen = strlen(subtrees[i]); ++ if (dnlen >= stlen && ++ strcasecmp(dn + dnlen - stlen, subtrees[i]) == 0 && ++ (dnlen == stlen || dn[dnlen - stlen - 1] == ',')) ++ return 0; ++ } ++ ++ krb5_set_error_message(context, EINVAL, _("DN is out of the realm subtree")); ++ return EINVAL; ++} ++ ++static krb5_error_code ++check_dn_exists(krb5_context context, ++ krb5_ldap_server_handle *ldap_server_handle, ++ const char *dn, krb5_boolean nonkrb_only) ++{ ++ krb5_error_code st = 0, tempst; ++ krb5_ldap_context *ldap_context = context->dal_handle->db_context; ++ LDAP *ld = ldap_server_handle->ldap_handle; ++ LDAPMessage *result = NULL, *ent; ++ char *attrs[] = { "krbticketpolicyreference", "krbprincipalname", NULL }; ++ char **values; ++ ++ LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attrs, IGNORE_STATUS); ++ if (st != LDAP_SUCCESS) ++ return set_ldap_error(context, st, OP_SEARCH); ++ ++ ent = ldap_first_entry(ld, result); ++ CHECK_NULL(ent); ++ ++ values = ldap_get_values(ld, ent, "krbticketpolicyreference"); ++ if (values != NULL) ++ ldap_value_free(values); ++ ++ values = ldap_get_values(ld, ent, "krbprincipalname"); ++ if (values != NULL) { ++ ldap_value_free(values); ++ if (nonkrb_only) { ++ st = EINVAL; ++ krb5_set_error_message(context, st, _("ldap object is already kerberized")); ++ goto cleanup; ++ } ++ } ++ ++cleanup: ++ ldap_msgfree(result); ++ return st; ++} ++ ++static krb5_error_code ++validate_xargs(krb5_context context, ++ krb5_ldap_server_handle *ldap_server_handle, ++ const xargs_t *xargs, const char *standalone_dn, ++ char *const *subtrees, unsigned int ntrees) ++{ ++ krb5_error_code st; ++ ++ if (xargs->dn != NULL) { ++ /* The supplied dn must be within a realm container. */ ++ st = check_dn_in_container(context, xargs->dn, subtrees, ntrees); ++ if (st) ++ return st; ++ /* The supplied dn must exist without Kerberos attributes. */ ++ st = check_dn_exists(context, ldap_server_handle, xargs->dn, TRUE); ++ if (st) ++ return st; ++ } ++ ++ if (xargs->linkdn != NULL) { ++ /* The supplied linkdn must be within a realm container. */ ++ st = check_dn_in_container(context, xargs->linkdn, subtrees, ntrees); ++ if (st) ++ return st; ++ /* The supplied linkdn must exist. */ ++ st = check_dn_exists(context, ldap_server_handle, xargs->linkdn, ++ FALSE); ++ if (st) ++ return st; ++ } ++ ++ if (xargs->containerdn != NULL && standalone_dn != NULL) { ++ /* standalone_dn (likely composed using containerdn) must be within a ++ * container. */ ++ st = check_dn_in_container(context, standalone_dn, subtrees, ntrees); ++ if (st) ++ return st; ++ } ++ ++ return 0; ++} ++ + krb5_error_code + krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry, + char **db_args) +@@ -496,11 +597,11 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry, + LDAPMessage *result=NULL, *ent=NULL; + char *user=NULL, *subtree=NULL, *principal_dn=NULL; +- char **values=NULL, *strval[10]={NULL}, errbuf[1024]; ++ char *strval[10]={NULL}, errbuf[1024]; + char *filtuser=NULL; + struct berval **bersecretkey=NULL; + LDAPMod **mods=NULL; + krb5_boolean create_standalone_prinicipal=FALSE; +- krb5_boolean krb_identity_exists=FALSE, establish_links=FALSE; ++ krb5_boolean establish_links=FALSE; + char *standalone_principal_dn=NULL; + krb5_tl_data *tl_data=NULL; + krb5_key_data **keys=NULL; +@@ -698,26 +763,8 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry, + * any of the subtrees + */ + if (xargs.dn_from_kbd == TRUE) { +- /* make sure the DN falls in the subtree */ + unsigned int tre=0, ntrees=0; +- int dnlen=0, subtreelen=0; + char **subtreelist=NULL; +- char *dn=NULL; +- krb5_boolean outofsubtree=TRUE; +- +- if (xargs.dn != NULL) { +- dn = xargs.dn; +- } else if (xargs.linkdn != NULL) { +- dn = xargs.linkdn; +- } else if (standalone_principal_dn != NULL) { +- /* +- * Even though the standalone_principal_dn is constructed +- * within this function, there is the containerdn input +- * from the user that can become part of the it. +- */ +- dn = standalone_principal_dn; +- } +- + /* get the current subtree list */ + if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0) + goto cleanup; +@@ -722,85 +805,14 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry, + if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0) + goto cleanup; + +- for (tre=0; tre= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) { +- outofsubtree = FALSE; +- break; +- } +- } +- } +- + for (tre=0; tre < ntrees; ++tre) { + free(subtreelist[tre]); + } + +- if (outofsubtree == TRUE) { +- st = EINVAL; +- krb5_set_error_message(context, st, +- _("DN is out of the realm subtree")); ++ st = validate_xargs(context, ldap_server_handle, &xargs, ++ standalone_principal_dn, subtreelist, ntrees); ++ if (st) + goto cleanup; +- } +- +- /* +- * dn value will be set either by dn, linkdn or the standalone_principal_dn +- * In the first 2 cases, the dn should be existing and in the last case we +- * are supposed to create the ldap object. so the below should not be +- * executed for the last case. +- */ +- +- if (standalone_principal_dn == NULL) { +- /* +- * If the ldap object is missing, this results in an error. +- */ +- +- /* +- * Search for krbprincipalname attribute here. +- * This is to find if a kerberos identity is already present +- * on the ldap object, in which case adding a kerberos identity +- * on the ldap object should result in an error. +- */ +- char *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL}; +- +- LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS); +- if (st == LDAP_SUCCESS) { +- ent = ldap_first_entry(ld, result); +- if (ent != NULL) { +- if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) { +- ldap_value_free(values); +- } +- +- if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { +- krb_identity_exists = TRUE; +- ldap_value_free(values); +- } +- } +- ldap_msgfree(result); +- } else { +- st = set_ldap_error(context, st, OP_SEARCH); +- goto cleanup; +- } +- } +- } +- +- /* +- * If xargs.dn is set then the request is to add a +- * kerberos principal on a ldap object, but if +- * there is one already on the ldap object this +- * should result in an error. +- */ +- +- if (xargs.dn != NULL && krb_identity_exists == TRUE) { +- st = EINVAL; +- snprintf(errbuf, sizeof(errbuf), +- _("ldap object is already kerberized")); +- krb5_set_error_message(context, st, "%s", errbuf); +- goto cleanup; + } + + if (xargs.linkdn != NULL) { +diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py +index 217f2cdc3b..6e563b1032 100755 +--- a/src/tests/t_kdb.py ++++ b/src/tests/t_kdb.py +@@ -146,6 +146,13 @@ def ldap_add(dn, objectclass, attrs=[]): + out = realm.run_kadminl('ank -randkey -x dn=cn=krb5 princ1') + if 'DN is out of the realm subtree' not in out: + fail('Unexpected kadmin.local output for out-of-realm dn') ++# Check that the DN container check is a hierarchy test, not a simple ++# suffix match (CVE-2018-5730). We expect this operation to fail ++# either way (because "xcn" isn't a valid DN tag) but the container ++# check should happen before the DN is parsed. ++out = realm.run_kadminl('ank -randkey -x dn=xcn=t1,cn=krb5 princ1') ++if 'DN is out of the realm subtree' not in out: ++ fail('Invalid DN tag') + out = realm.run_kadminl('ank -randkey -x dn=cn=t2,cn=krb5 princ1') + if 'Principal "princ1@KRBTEST.COM" created.\n' not in out: + fail('Unexpected kadmin.local output for specified dn') +@@ -182,6 +188,11 @@ def ldap_add(dn, objectclass, attrs=[]): + out = realm.run_kadminl('modprinc -x containerdn=cn=t2,cn=krb5 princ3') + if 'containerdn option not supported' not in out: + fail('Unexpected kadmin.local output trying to reset containerdn') ++# Verify that containerdn is checked when linkdn is also supplied ++# (CVE-2018-5730). ++realm.run([kadminl, 'ank', '-randkey', '-x', 'containerdn=cn=krb5', ++ '-x', 'linkdn=cn=t2,cn=krb5', 'princ4'], expected_code=1, ++ expected_msg='DN is out of the realm subtree') + + # Create and modify a ticket policy. + kldaputil(['create_policy', '-maxtktlife', '3hour', '-maxrenewlife', '6hour', diff -Nru krb5-1.12+dfsg/debian/patches/series krb5-1.12+dfsg/debian/patches/series --- krb5-1.12+dfsg/debian/patches/series 2015-11-11 14:07:58.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/series 2019-01-09 17:03:20.000000000 +0000 @@ -13,7 +13,6 @@ CVE-2014-4343.patch CVE-2014-4344.patch CVE-2014-4345.patch - CVE-2014-5351.patch CVE-2014-5352.patch CVE-2014-5353.patch @@ -29,3 +28,13 @@ 0034-Fix-two-IAKERB-comments.patch 0035-Fix-IAKERB-context-export-import-CVE-2015-2698.patch 0036-Fix-SPNEGO-context-import.patch +upstream/0001-Add-SPNEGO-special-case-for-NTLMSSP-MechListMIC.patch +CVE-2015-8629.patch +CVE-2015-8630.patch +CVE-2015-8631.patch +CVE-2016-3119.patch +CVE-2016-3120.patch +CVE-2017-11368-1.patch +CVE-2017-11368-2.patch +CVE-2017-11462.patch +CVE-2018-5729-CVE-2018-5730.patch diff -Nru krb5-1.12+dfsg/debian/patches/upstream/0001-Add-SPNEGO-special-case-for-NTLMSSP-MechListMIC.patch krb5-1.12+dfsg/debian/patches/upstream/0001-Add-SPNEGO-special-case-for-NTLMSSP-MechListMIC.patch --- krb5-1.12+dfsg/debian/patches/upstream/0001-Add-SPNEGO-special-case-for-NTLMSSP-MechListMIC.patch 1970-01-01 00:00:00.000000000 +0000 +++ krb5-1.12+dfsg/debian/patches/upstream/0001-Add-SPNEGO-special-case-for-NTLMSSP-MechListMIC.patch 2016-11-22 02:14:47.000000000 +0000 @@ -0,0 +1,82 @@ +From cb96ca52a3354e5a0ea52e12495ff375de54f9b7 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Wed, 30 Mar 2016 13:00:19 -0400 +Subject: [PATCH] Add SPNEGO special case for NTLMSSP+MechListMIC + +MS-SPNG section 3.3.5.1 documents an odd behavior the SPNEGO layer +needs to implement specifically for the NTLMSSP mechanism. This is +required for compatibility with Windows services. + +ticket: 8423 (new) +--- + src/lib/gssapi/spnego/spnego_mech.c | 48 +++++++++++++++++++++++++++++++++---- + 1 file changed, 43 insertions(+), 5 deletions(-) + +Index: krb5-1.12+dfsg/src/lib/gssapi/spnego/spnego_mech.c +=================================================================== +--- krb5-1.12+dfsg.orig/src/lib/gssapi/spnego/spnego_mech.c ++++ krb5-1.12+dfsg/src/lib/gssapi/spnego/spnego_mech.c +@@ -473,6 +473,45 @@ + return (spnego_ctx); + } + ++/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) Microsoft(311) ++ * security(2) mechanisms(2) NTLM(10) */ ++static const gss_OID_desc gss_mech_ntlmssp_oid = ++ { 10, "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" }; ++ ++/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) samba(7165) ++ * gssntlmssp(655) controls(1) ntlmssp_reset_crypto(3) */ ++static const gss_OID_desc ntlmssp_reset_crypto_oid = ++ { 11, "\x2B\x06\x01\x04\x01\xB7\x7D\x85\x0F\x01\x03" }; ++ ++/* ++ * MS-SPNG section 3.3.5.1 warns that the NTLM mechanism requires special ++ * handling of the crypto state to interop with Windows. If the mechanism for ++ * sc is SPNEGO, invoke a mechanism-specific operation on the context to reset ++ * the RC4 state after producing or verifying a MIC. Ignore a result of ++ * GSS_S_UNAVAILABLE for compatibility with older versions of the mechanism ++ * that do not support this functionality. ++ */ ++static OM_uint32 ++ntlmssp_reset_crypto_state(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, ++ OM_uint32 verify) ++{ ++ OM_uint32 major, minor; ++ gss_buffer_desc value; ++ ++ if (!g_OID_equal(sc->internal_mech, &gss_mech_ntlmssp_oid)) ++ return GSS_S_COMPLETE; ++ ++ value.length = sizeof(verify); ++ value.value = &verify; ++ major = gss_set_sec_context_option(&minor, &sc->ctx_handle, ++ (gss_OID)&ntlmssp_reset_crypto_oid, ++ &value); ++ if (major == GSS_S_UNAVAILABLE) ++ return GSS_S_COMPLETE; ++ *minor_status = minor; ++ return major; ++} ++ + /* + * Both initiator and acceptor call here to verify and/or create mechListMIC, + * and to consistency-check the MIC state. handle_mic is invoked only if the +@@ -554,6 +593,8 @@ + ret = gss_verify_mic(minor_status, sc->ctx_handle, + &sc->DER_mechTypes, + mic_in, &qop_state); ++ if (ret == GSS_S_COMPLETE) ++ ret = ntlmssp_reset_crypto_state(minor_status, sc, 1); + if (ret != GSS_S_COMPLETE) { + *negState = REJECT; + *tokflag = ERROR_TOKEN_SEND; +@@ -568,6 +609,8 @@ + GSS_C_QOP_DEFAULT, + &sc->DER_mechTypes, + &tmpmic); ++ if (ret == GSS_S_COMPLETE) ++ ret = ntlmssp_reset_crypto_state(minor_status, sc, 0); + if (ret != GSS_S_COMPLETE) { + gss_release_buffer(&tmpmin, &tmpmic); + *tokflag = NO_TOKEN_SEND;