[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1013955: marked as done (libapache2-mod-auth-kerb: memory leak plus incorrect handling of keytabs)



Your message dated Fri, 05 Apr 2024 17:27:47 +0000
with message-id <[🔎] E1rsnLv-00Fr8g-I4@fasolo.debian.org>
and subject line Bug#1068262: Removed package(s) from unstable
has caused the Debian Bug report #1013955,
regarding libapache2-mod-auth-kerb: memory leak plus incorrect handling of keytabs
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1013955: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1013955
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: libapache2-mod-auth-kerb
Version: 5.4-2.5
Severity: normal
Tags: patch upstream
X-Debbugs-Cc: sorinm@gmail.com

Dear Maintainer,

I think there are two problems with the code:

In authenticate_user_gss the keytab path (configured by the Krb5Keytab conf directive) is in the process environment using a putenv call.

First, there is an obvious memory leak because the string put into the environment is malloc'ed. It is never freed. Moreover, this malloc and putenv happens at every request.

Second, not only that putenv is not thread-safe but it may lead to functional bugs. Let us assume that we have two different directories, each with its own Krb5Keytab conf directive, each pointing to a different keytab file. When two requests are handled by two threads in parallel, each will putenv KRB5_KTNAME=/path/to/keytab. It is possible that the calls to the GSSAPI/Krb5 functions of one thread use the value of the environment variable KRB5_KTNAME set by the other thread.

I've written a patch to correct these two problems. The patch works in my setup but I have to tested it exhaustively. Please have a look.

Thank you and best regards,
Sorin

-- System Information:
Debian Release: bookworm/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.17.0-1-amd64 (SMP w/8 CPU threads; PREEMPT)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=C, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages libapache2-mod-auth-kerb depends on:
ii  apache2-bin [apache2-api-20120211]  2.4.54-1
ii  krb5-config                         2.6+nmu1
ii  libc6                               2.33-7
ii  libcom-err2                         1.46.5-2
ii  libgssapi-krb5-2                    1.19.2-2+b2
ii  libkrb5-3                           1.19.2-2+b2

libapache2-mod-auth-kerb recommends no packages.

libapache2-mod-auth-kerb suggests no packages.

-- no debconf information
Index: mod_auth_kerb-5.4/src/mod_auth_kerb.c
===================================================================
--- mod_auth_kerb-5.4.orig/src/mod_auth_kerb.c
+++ mod_auth_kerb-5.4/src/mod_auth_kerb.c
@@ -228,7 +228,8 @@ static const char *
 cmd_delegationlock(cmd_parms *cmd, void *dconf, const char *a1);
 
 static int
-obtain_server_credentials(request_rec *r, const char *service_name);
+obtain_server_credentials(request_rec *r, const char *service_name,
+			  const char *kt_name);
 
 #ifdef STANDARD20_MODULE_STUFF
 #define command(name, func, var, type, usage)           \
@@ -1245,14 +1246,12 @@ end:
 }
 
 static int
-get_gss_creds(request_rec *r,
-              kerb_auth_config *conf,
-	      gss_cred_id_t *server_creds)
+get_server_name(request_rec *r,
+		kerb_auth_config *conf,
+		gss_name_t *server_name)
 {
    gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
-   OM_uint32 major_status, minor_status, minor_status2;
-   gss_name_t server_name = GSS_C_NO_NAME;
-   gss_cred_usage_t usage = GSS_C_ACCEPT;
+   OM_uint32 major_status, minor_status;
    char buf[1024];
    int have_server_princ;
 
@@ -1260,8 +1259,8 @@ get_gss_creds(request_rec *r,
    have_server_princ = conf->krb_service_name && strchr(conf->krb_service_name, '/') != NULL;
    if (have_server_princ)
       strncpy(buf, conf->krb_service_name, sizeof(buf));
-   else if (conf->krb_service_name && strcmp(conf->krb_service_name,"Any") == 0) {      
-      *server_creds = GSS_C_NO_CREDENTIAL;
+   else if (conf->krb_service_name && strcmp(conf->krb_service_name,"Any") == 0) {
+      *server_name = GSS_C_NO_NAME;
       return 0;
    }
    else
@@ -1274,7 +1273,7 @@ get_gss_creds(request_rec *r,
 
    major_status = gss_import_name(&minor_status, &token,
 	 			  (have_server_princ) ? (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME : (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
-				  &server_name);
+				  server_name);
    memset(&token, 0, sizeof(token));
    if (GSS_ERROR(major_status)) {
       log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -1283,7 +1282,7 @@ get_gss_creds(request_rec *r,
       return HTTP_INTERNAL_SERVER_ERROR;
    }
 
-   major_status = gss_display_name(&minor_status, server_name, &token, NULL);
+   major_status = gss_display_name(&minor_status, *server_name, &token, NULL);
    if (GSS_ERROR(major_status)) {
       /* Perhaps we could just ignore this error but it's safer to give up now,
          I think */
@@ -1295,15 +1294,46 @@ get_gss_creds(request_rec *r,
 
    log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Acquiring creds for %s",
 	      token.value);
+   gss_release_buffer(&minor_status, &token);
+
+   return 0;
+}
+
+static int
+get_gss_creds(request_rec *r,
+              kerb_auth_config *conf,
+	      gss_cred_id_t *server_creds)
+{
+   OM_uint32 major_status, minor_status, minor_status2;
+   gss_name_t server_name = GSS_C_NO_NAME;
+   gss_cred_usage_t usage = GSS_C_ACCEPT;
+   gss_key_value_element_desc e[1];
+   gss_key_value_set_desc kv = {0, &e[0]};
+
+   int rc = get_server_name(r, conf, &server_name);
+   if (rc)
+	   return rc;
+
    if (conf->krb5_s4u2proxy) {
        usage = GSS_C_BOTH;
-       obtain_server_credentials(r, conf->krb_service_name);
+       obtain_server_credentials(r, conf->krb_service_name, conf->krb_5_keytab);
    }
-   gss_release_buffer(&minor_status, &token);
-   
-   major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
-			           GSS_C_NO_OID_SET, usage,
-				   server_creds, NULL, NULL);
+
+   if (conf->krb_5_keytab) {
+	   e[kv.count].value = apr_pstrcat(r->pool, "FILE:", conf->krb_5_keytab,
+					   NULL);
+	   if (!e[kv.count].value) {
+		   log_rerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, r,
+			      "Out of memory");
+		   return HTTP_INTERNAL_SERVER_ERROR;
+	   }
+	   e[kv.count].key = "keytab";
+	   ++kv.count;
+   }
+
+   major_status = gss_acquire_cred_from(
+	   &minor_status, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+	   usage, &kv, server_creds, NULL, NULL);
    gss_release_name(&minor_status2, &server_name);
    if (GSS_ERROR(major_status)) {
       log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -1447,8 +1477,8 @@ cleanup:
 }
 
 static int
-obtain_server_credentials(request_rec *r,
-                          const char *service_name)
+obtain_server_credentials(request_rec *r, const char *service_name,
+			  const char *kt_name)
 {
     krb5_context kcontext = NULL;
     krb5_keytab keytab = NULL;
@@ -1555,7 +1585,9 @@ obtain_server_credentials(request_rec *r
         }
     }
 
-    if ((kerr = krb5_kt_default(kcontext, &keytab))) {
+    if ((kerr = (kt_name ?
+		 krb5_kt_resolve(kcontext, kt_name, &keytab) :
+		 krb5_kt_default(kcontext, &keytab)))) {
         log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                    "Unable to get default keytab: %s (%d)",
                    error_message(kerr), kerr);
@@ -1667,25 +1699,6 @@ authenticate_user_gss(request_rec *r, ke
   spnego_oid.length = 6;
   spnego_oid.elements = (void *)"\x2b\x06\x01\x05\x05\x02";
 
-  if (conf->krb_5_keytab) {
-     char *ktname;
-     /* we don't use the ap_* calls here, since the string passed to putenv()
-      * will become part of the enviroment and shouldn't be free()ed by apache
-      */
-     ktname = malloc(strlen("KRB5_KTNAME=") + strlen(conf->krb_5_keytab) + 1);
-     if (ktname == NULL) {
-	log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "malloc() failed: not enough memory");
-	ret = HTTP_INTERNAL_SERVER_ERROR;
-	goto end;
-     }
-     sprintf(ktname, "KRB5_KTNAME=%s", conf->krb_5_keytab);
-     putenv(ktname);
-#ifdef HEIMDAL
-     /* Seems to be also supported by latest MIT */
-     gsskrb5_register_acceptor_identity(conf->krb_5_keytab);
-#endif
-  }
-
   ret = get_gss_creds(r, conf, &server_creds);
   if (ret)
      goto end;

--- End Message ---
--- Begin Message ---
Version: 5.4-3+rm

Dear submitter,

as the package libapache-mod-auth-kerb has just been removed from the Debian archive
unstable we hereby close the associated bug reports.  We are sorry
that we couldn't deal with your issue properly.

For details on the removal, please see https://bugs.debian.org/1068262

The version of this package that was in Debian prior to this removal
can still be found using https://snapshot.debian.org/.

Please note that the changes have been done on the master archive and
will not propagate to any mirrors until the next dinstall run at the
earliest.

This message was generated automatically; if you believe that there is
a problem with it please contact the archive administrators by mailing
ftpmaster@ftp-master.debian.org.

Debian distribution maintenance software
pp.
Thorsten Alteholz (the ftpmaster behind the curtain)

--- End Message ---

Reply to: