2c0d227
From 159042c71bbdd5909f792208dcdffffb1674ecfe Mon Sep 17 00:00:00 2001
2c0d227
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
2c0d227
Date: Thu, 19 Aug 2021 16:07:06 +0200
2c0d227
Subject: [PATCH] Fix a crash in gss_release_oid() when destructing out_mech
2c0d227
 returned by gss_accept_sec_context()
2c0d227
MIME-Version: 1.0
2c0d227
Content-Type: text/plain; charset=UTF-8
2c0d227
Content-Transfer-Encoding: 8bit
2c0d227
2c0d227
If Perl GSSAPI was built against MIT krb5, an example gss-server.pl
2c0d227
script crashed like this:
2c0d227
2c0d227
    Program terminated with signal SIGSEGV, Segmentation fault.
2c0d227
    #0  0x00007f27f3d48b23 in __GI___libc_free (mem=<optimized out>)
2c0d227
        at malloc.c:3131
2c0d227
    3131	  ar_ptr = arena_for_chunk (p);
2c0d227
    (gdb) bt
2c0d227
    #0  0x00007f27f3d48b23 in __GI___libc_free (mem=<optimized out>)
2c0d227
        at malloc.c:3131
2c0d227
    #1  0x00007f27f2fe17c6 in generic_gss_release_oid (
2c0d227
        minor_status=minor_status@entry=0x7fffc750333c,
2c0d227
        oid=oid@entry=0x7fffc7503340) at oid_ops.c:102
2c0d227
    #2  0x00007f27f2fee6df in gss_release_oid (
2c0d227
        minor_status=minor_status@entry=0x7fffc750333c,
2c0d227
        oid=oid@entry=0x7fffc7503340) at g_initialize.c:202
2c0d227
    #3  0x00007f27f322f5cf in XS_GSSAPI__OID_DESTROY (my_perl=<optimized out>,
2c0d227
        cv=0x564037c87130) at ./xs/OID.xs:24
2c0d227
    #4  0x00007f27f4f58149 in Perl_pp_entersub (my_perl=0x5640378d42a0)
2c0d227
        at pp_hot.c:4227
2c0d227
2c0d227
The cause is that gss_accept_sec_context() returns a pointer to
2c0d227
a static storage in out_mech argument. When GSSAPI passed out_mech to
2c0d227
a desctructor, the invoked gss_release_oid() crashed when freeing the
2c0d227
memory.
2c0d227
2c0d227
Accoding to RFC 2744, the static storage is correct. Hence the flaw is
2c0d227
on Perl GSSAPI side. This patch fixes it by copying the out_mech OID
2c0d227
object on a heap which is then correctly processed by
2c0d227
gss_release_oid().
2c0d227
2c0d227
CPAN RT#121873.
2c0d227
2c0d227
Signed-off-by: Petr Písař <ppisar@redhat.com>
2c0d227
---
2c0d227
 xs/Context.xs | 18 ++++++++++++++++++
2c0d227
 1 file changed, 18 insertions(+)
2c0d227
2c0d227
diff --git a/xs/Context.xs b/xs/Context.xs
2c0d227
index d176f08..4549595 100644
2c0d227
--- a/xs/Context.xs
2c0d227
+++ b/xs/Context.xs
2c0d227
@@ -80,6 +80,24 @@ accept(context, acc_cred, in_token, binding, out_name, out_mech, out_token, out_
2c0d227
 				       &in_token, binding, out_name, out_mech,
2c0d227
 				       &out_token, out_flags, out_time,
2c0d227
 				       delegated_cred);
2c0d227
+#if !defined(HEIMDAL)
2c0d227
+	if (out_mech && *out_mech) {
2c0d227
+		/* RFC 2744 documents that the returned *out_mech is a pointer
2c0d227
+		 * to static data. To prevent from freeing them when destructing
2c0d227
+		 * out_mech, we change *out_mech into a pointer to a heap-allocated
2c0d227
+		 * buffer with the same content. Otherwise, MITKRB5-provided
2c0d227
+		 * gss_release_oid() deallocator which cannot recognize this static
2c0d227
+		 * storage would crash. We use malloc() because gss_release_oid() used
2c0d227
+		 * free(). */
2c0d227
+		GSSAPI__OID copy = malloc(sizeof(*copy));
2c0d227
+		if (!copy) croak("Not enough memory for copying out_mech!");
2c0d227
+		copy->elements = malloc((*out_mech)->length);
2c0d227
+		if (!copy->elements) croak("Not enough memory for copying out_mech!");
2c0d227
+		memcpy(copy->elements, (*out_mech)->elements, (*out_mech)->length);
2c0d227
+		copy->length = (*out_mech)->length;
2c0d227
+		*out_mech = copy;
2c0d227
+    }
2c0d227
+#endif
2c0d227
     OUTPUT:
2c0d227
 	RETVAL
2c0d227
 	context
2c0d227
-- 
2c0d227
2.31.1
2c0d227