From 83ed75feba32e46f736fcce0d96a0445f29b96c2 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
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

Line numbers are slightly adjusted by Howard Guo <hguo@suse.com> to fit into
this older version of Kerberos.

diff -rupN krb5-1.6.3/src/kadmin/server/server_stubs.c krb5-1.6.3-patched/src/kadmin/server/server_stubs.c
--- krb5-1.6.3/src/kadmin/server/server_stubs.c	2016-01-28 16:08:58.566084205 +0100
+++ krb5-1.6.3-patched/src/kadmin/server/server_stubs.c	2016-01-28 16:10:02.510581628 +0100
@@ -302,7 +302,8 @@ create_principal_2_svc(cprinc_arg *arg,
 {
     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;
@@ -350,10 +351,10 @@ create_principal_2_svc(cprinc_arg *arg,
 	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
     }
     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;
 }
@@ -363,7 +364,8 @@ create_principal3_2_svc(cprinc3_arg *arg
 {
     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;
@@ -413,10 +415,10 @@ create_principal3_2_svc(cprinc3_arg *arg
 	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
     }
     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;
 }
@@ -426,8 +428,8 @@ delete_principal_2_svc(dprinc_arg *arg,
 {
     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;
     char                            *errmsg;
@@ -470,10 +472,10 @@ delete_principal_2_svc(dprinc_arg *arg,
 	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
     }
     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;
 }
@@ -483,9 +485,9 @@ modify_principal_2_svc(mprinc_arg *arg,
 {
     static generic_ret		    ret;
     char			    *prime_arg;
-    gss_buffer_desc		    client_name,
-				    service_name;
     OM_uint32			    minor_stat;
+    gss_buffer_desc		client_name = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc		service_name = GSS_C_EMPTY_BUFFER;
     kadm5_server_handle_t	    handle;
     restriction_t		    *rp;
     char                            *errmsg;
@@ -529,9 +531,9 @@ modify_principal_2_svc(mprinc_arg *arg,
 	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
     }
     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;
 }
@@ -540,10 +542,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;
@@ -620,11 +621,11 @@ rename_principal_2_svc(rprinc_arg *arg,
 			  slen, service_name.value, sdots,
 			  inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
     }
+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;
 }
@@ -635,8 +636,8 @@ get_principal_2_svc(gprinc_arg *arg, str
     static gprinc_ret		    ret;
     kadm5_principal_ent_t_v1	    e;
     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;
     char                            *errmsg;
@@ -696,9 +697,9 @@ get_principal_2_svc(gprinc_arg *arg, str
 
     }
     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;
 }
@@ -708,8 +709,8 @@ get_princs_2_svc(gprincs_arg *arg, struc
 {
     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;
     char                            *errmsg;
@@ -753,9 +754,9 @@ get_princs_2_svc(gprincs_arg *arg, struc
 		  &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;
 }
@@ -765,8 +766,8 @@ chpass_principal_2_svc(chpass_arg *arg,
 {
     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;
     char                            *errmsg;
@@ -815,9 +816,9 @@ chpass_principal_2_svc(chpass_arg *arg,
     }
 
     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;
 }
@@ -827,8 +828,8 @@ chpass_principal3_2_svc(chpass3_arg *arg
 {
     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;
     char                            *errmsg;
@@ -883,9 +884,9 @@ chpass_principal3_2_svc(chpass3_arg *arg
     }
 
     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;
 }
@@ -895,8 +896,8 @@ setv4key_principal_2_svc(setv4key_arg *a
 {
     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;
     char                            *errmsg;
@@ -942,9 +943,9 @@ setv4key_principal_2_svc(setv4key_arg *a
     }
 
     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;
 }
@@ -954,8 +955,8 @@ setkey_principal_2_svc(setkey_arg *arg,
 {
     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;
     char                            *errmsg;
@@ -1001,9 +1002,9 @@ setkey_principal_2_svc(setkey_arg *arg,
     }
 
     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;
 }
@@ -1013,8 +1014,8 @@ setkey_principal3_2_svc(setkey3_arg *arg
 {
     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;
     char                            *errmsg;
@@ -1063,9 +1064,9 @@ setkey_principal3_2_svc(setkey3_arg *arg
     }
 
     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;
 }
@@ -1077,8 +1078,8 @@ chrand_principal_2_svc(chrand_arg *arg,
     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;
     char                        *errmsg;
@@ -1140,9 +1141,9 @@ chrand_principal_2_svc(chrand_arg *arg,
 		 &client_name, &service_name, 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;
 }
@@ -1154,8 +1155,8 @@ chrand_principal3_2_svc(chrand3_arg *arg
     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;
     char                        *errmsg;
@@ -1222,9 +1223,9 @@ chrand_principal3_2_svc(chrand3_arg *arg
 		 &client_name, &service_name, 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;
 }
@@ -1234,8 +1235,8 @@ create_policy_2_svc(cpol_arg *arg, struc
 {
     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;
     char                            *errmsg;
@@ -1275,9 +1276,9 @@ create_policy_2_svc(cpol_arg *arg, struc
 		  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
 		  &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;
 }
@@ -1287,8 +1288,8 @@ delete_policy_2_svc(dpol_arg *arg, struc
 {
     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;
     char                            *errmsg;
@@ -1326,9 +1327,9 @@ delete_policy_2_svc(dpol_arg *arg, struc
 		  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
 		  &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;
 }
@@ -1338,8 +1339,8 @@ modify_policy_2_svc(mpol_arg *arg, struc
 {
     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;
     char                            *errmsg;
@@ -1378,9 +1379,9 @@ modify_policy_2_svc(mpol_arg *arg, struc
 		  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
 		  &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;
 }
@@ -1391,8 +1392,8 @@ get_policy_2_svc(gpol_arg *arg, struct s
     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_policy_ent_t	e;
     kadm5_principal_ent_rec	caller_ent;
@@ -1463,9 +1464,9 @@ get_policy_2_svc(gpol_arg *arg, struct s
 	 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;
 
@@ -1476,8 +1477,8 @@ get_pols_2_svc(gpols_arg *arg, struct sv
 {
     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;
     char                            *errmsg;
@@ -1518,9 +1519,9 @@ get_pols_2_svc(gpols_arg *arg, struct sv
 	 log_done("kadm5_get_policies", prime_arg, errmsg,
 		  &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;
 }
@@ -1528,7 +1529,8 @@ exit_func:
 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;
      char                           *errmsg;
@@ -1557,9 +1559,9 @@ getprivs_ret * get_privs_2_svc(krb5_ui_4
      log_done("kadm5_get_privs", client_name.value, errmsg,
 	      &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;
 }
@@ -1567,8 +1569,8 @@ exit_func:
 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;
      char                       *errmsg = 0;
@@ -1608,10 +1610,10 @@ generic_ret *init_2_svc(krb5_ui_4 *arg,
 		      slen, service_name.value, sdots,
 		      inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
 		      rqstp->rq_cred.oa_flavor);
-     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);
 }
 
