Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Prevent a double free by not reentering be_tls_close().
authorNoah Misch <noah@leadboat.com>
Mon, 18 May 2015 14:02:31 +0000 (10:02 -0400)
committerNoah Misch <noah@leadboat.com>
Mon, 18 May 2015 14:02:38 +0000 (10:02 -0400)
Reentering this function with the right timing caused a double free,
typically crashing the backend.  By synchronizing a disconnection with
the authentication timeout, an unauthenticated attacker could achieve
this somewhat consistently.  Call be_tls_close() solely from within
proc_exit_prepare().  Back-patch to 9.0 (all supported versions).

Benkocs Norbert Attila

Security: CVE-2015-3165

src/backend/libpq/be-secure.c
src/backend/libpq/pqcomm.c
src/backend/postmaster/postmaster.c

index 28e3102c64e5136631d030d432c7f512ddb03c34..f2d65cc9b36b5f48762c723618daff7c71f420ec 100644 (file)
@@ -906,7 +906,6 @@ open_server_SSL(Port *port)
                (errcode(ERRCODE_PROTOCOL_VIOLATION),
                 errmsg("could not initialize SSL connection: %s",
                        SSLerrmessage())));
-       close_SSL(port);
        return -1;
    }
    if (!my_SSL_set_fd(port->ssl, port->sock))
@@ -915,7 +914,6 @@ open_server_SSL(Port *port)
                (errcode(ERRCODE_PROTOCOL_VIOLATION),
                 errmsg("could not set SSL socket: %s",
                        SSLerrmessage())));
-       close_SSL(port);
        return -1;
    }
 
@@ -963,7 +961,6 @@ aloop:
                                err)));
                break;
        }
-       close_SSL(port);
        return -1;
    }
 
@@ -992,7 +989,6 @@ aloop:
            {
                /* shouldn't happen */
                pfree(peer_cn);
-               close_SSL(port);
                return -1;
            }
 
@@ -1006,7 +1002,6 @@ aloop:
                        (errcode(ERRCODE_PROTOCOL_VIOLATION),
                         errmsg("SSL certificate's common name contains embedded null")));
                pfree(peer_cn);
-               close_SSL(port);
                return -1;
            }
 
index 92ad21cdfaa4c16ab70f722c12fa30bffeb3ded7..c0ecb57ceba322ae3a41521f56819cae637354d2 100644 (file)
@@ -170,32 +170,45 @@ pq_comm_reset(void)
 /* --------------------------------
  *     pq_close - shutdown libpq at backend exit
  *
- * Note: in a standalone backend MyProcPort will be null,
- * don't crash during exit...
+ * This is the one pg_on_exit_callback in place during BackendInitialize().
+ * That function's unusual signal handling constrains that this callback be
+ * safe to run at any instant.
  * --------------------------------
  */
 static void
 pq_close(int code, Datum arg)
 {
+   /* Nothing to do in a standalone backend, where MyProcPort is NULL. */
    if (MyProcPort != NULL)
    {
 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
 #ifdef ENABLE_GSS
        OM_uint32   min_s;
 
-       /* Shutdown GSSAPI layer */
+       /*
+        * Shutdown GSSAPI layer.  This section does nothing when interrupting
+        * BackendInitialize(), because pg_GSS_recvauth() makes first use of
+        * "ctx" and "cred".
+        */
        if (MyProcPort->gss->ctx != GSS_C_NO_CONTEXT)
            gss_delete_sec_context(&min_s, &MyProcPort->gss->ctx, NULL);
 
        if (MyProcPort->gss->cred != GSS_C_NO_CREDENTIAL)
            gss_release_cred(&min_s, &MyProcPort->gss->cred);
 #endif   /* ENABLE_GSS */
-       /* GSS and SSPI share the port->gss struct */
 
+       /*
+        * GSS and SSPI share the port->gss struct.  Since nowhere else does a
+        * postmaster child free this, doing so is safe when interrupting
+        * BackendInitialize().
+        */
        free(MyProcPort->gss);
 #endif   /* ENABLE_GSS || ENABLE_SSPI */
 
-       /* Cleanly shut down SSL layer */
+       /*
+        * Cleanly shut down SSL layer.  Nowhere else does a postmaster child
+        * call this, so this is safe when interrupting BackendInitialize().
+        */
        secure_close(MyProcPort);
 
        /*
index e3295c10cef6b70693e218d9e5b5d38db3497b73..e4513d14edb52d8bbcb81da2b0f70ff4d66b207f 100644 (file)
@@ -3417,7 +3417,16 @@ BackendInitialize(Port *port)
     * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT or
     * timeout while trying to collect the startup packet.  Otherwise the
     * postmaster cannot shutdown the database FAST or IMMED cleanly if a
-    * buggy client fails to send the packet promptly.
+    * buggy client fails to send the packet promptly.  XXX it follows that
+    * the remainder of this function must tolerate losing control at any
+    * instant.  Likewise, any pg_on_exit_callback registered before or during
+    * this function must be prepared to execute at any instant between here
+    * and the end of this function.  Furthermore, affected callbacks execute
+    * partially or not at all when a second exit-inducing signal arrives
+    * after proc_exit_prepare() decrements on_proc_exit_index.  (Thanks to
+    * that mechanic, callbacks need not anticipate more than one call.)  This
+    * is fragile; it ought to instead follow the norm of handling interrupts
+    * at selected, safe opportunities.
     */
    pqsignal(SIGTERM, startup_die);
    pqsignal(SIGQUIT, startup_die);