Comment 11 for bug 1892145

Revision history for this message
Jesse Michael (jesse.michael) wrote : Re: smbclient cannot connect anonymously in Kerberos context (freeipa)

This bug is due to a double-free in source3/librpc/crypto/gse.c where gse_ctx->k5ctx is freed twice if gse_context_init fails and the err_out path is taken.

The beginning of gse_context_init calls talloc_set_destructor to call gse_context_destructor:

        talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);

This gse_context_destructor callback function is triggered by calls to TALLOC_FREE(gse_ctx) and frees pointers stored in the gse_ctx structure including gse_ctx->k5ctx:

        if (gse_ctx->k5ctx) {
                if (gse_ctx->ccache) {
                        krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
                        gse_ctx->ccache = NULL;
                }
                if (gse_ctx->keytab) {
                        krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
                        gse_ctx->keytab = NULL;
                }
                krb5_free_context(gse_ctx->k5ctx);
                gse_ctx->k5ctx = NULL;
        }

However, if gse_context_init fails and takes the err_out path, gse_ctx->k5ctx is freed without setting that pointer to NULL and then immediately calls TALLOC_FREE(gse_ctx) which then attempts to free gse_ctx->k5ctx a second time:

err_out:
        if (gse_ctx->k5ctx) {
                krb5_free_context(gse_ctx->k5ctx);
        }

        TALLOC_FREE(gse_ctx);

This results in the following double-free stack trace:

(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007ffff7443859 in __GI_abort () at abort.c:79
#2 0x00007ffff74ae3ee in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff75d8285 "%s\n") at ../sysdeps/posix/libc_fatal.c:155
#3 0x00007ffff74b647c in malloc_printerr (str=str@entry=0x7ffff75da5d0 "free(): double free detected in tcache 2") at malloc.c:5347
#4 0x00007ffff74b80ed in _int_free (av=0x7ffff7609b80 <main_arena>, p=0x5555555ce2c0, have_lock=0) at malloc.c:4201
#5 0x00007ffff6cc29f9 in krb5_free_context (context=0x5555555cdcd0) at ../../source4/heimdal/lib/krb5/context.c:595
#6 0x00007ffff73e75d1 in gse_context_destructor (ptr=ptr@entry=0x5555555cdc50) at ../../source3/librpc/crypto/gse.c:84
#7 0x00007ffff776553e in _tc_free_internal (tc=0x5555555cdbf0, location=0x7ffff73f2480 "../../source3/librpc/crypto/gse.c:241") at ../../talloc.c:1157
#8 0x00007ffff73e826c in gse_context_init (mem_ctx=mem_ctx@entry=0x5555555cdb60, do_sign=<optimized out>, do_seal=<optimized out>, add_gss_c_flags=<optimized out>, _gse_ctx=_gse_ctx@entry=0x7fffffffd500,
    ccache_name=<optimized out>) at ../../source3/librpc/crypto/gse.c:241
#9 0x00007ffff73e8433 in gse_init_client (ccache_name=0x0, realm=<optimized out>, username=<optimized out>, password=<optimized out>, _gse_ctx=<synthetic pointer>, add_gss_c_flags=<optimized out>,
    service=0x5555555ccdf0 "cifs", server=0x5555555ccfb0 "freenas", do_seal=<optimized out>, do_sign=<optimized out>, mem_ctx=0x5555555cdb60) at ../../source3/librpc/crypto/gse.c:268
#10 gensec_gse_client_start (gensec_security=0x5555555cdb60) at ../../source3/librpc/crypto/gse.c:786
#11 0x00007ffff7390453 in gensec_start_mech (gensec_security=0x5555555cdb60) at ../../auth/gensec/gensec_start.c:743
#12 gensec_start_mech (gensec_security=0x5555555cdb60) at ../../auth/gensec/gensec_start.c:704
#13 0x00007ffff7387822 in gensec_spnego_client_negTokenInit_step (gensec_security=0x5555555c9b70, spnego_state=0x5555555cc1b0, n=0x5555555cd4a0, spnego_in=<optimized out>, last_status=...,
    in_mem_ctx=<optimized out>, in_next=0x5555555cd3f8) at ../../auth/gensec/spnego.c:633
#14 0x00007ffff7387e02 in gensec_spnego_client_negTokenInit_start (gensec_security=0x5555555c9b70, spnego_state=0x5555555cc1b0, n=0x5555555cd4a0, spnego_in=0x5555555cd368, in_mem_ctx=0x5555555cd340,
    in_next=0x5555555cd3f8) at ../../auth/gensec/spnego.c:537
#15 0x00007ffff7388b84 in gensec_spnego_update_pre (req=0x5555555cd190) at ../../auth/gensec/spnego.c:1943
#16 gensec_spnego_update_send (mem_ctx=<optimized out>, ev=0x5555555aee90, gensec_security=<optimized out>, in=...) at ../../auth/gensec/spnego.c:1741
#17 0x00007ffff738f3b0 in gensec_update_send (mem_ctx=<optimized out>, ev=0x5555555aee90, gensec_security=0x5555555c9b70, in=...) at ../../auth/gensec/gensec.c:449
#18 0x00007ffff7f6dba6 in cli_session_setup_gensec_local_next (req=0x5555555c9d90) at ../../source3/libsmb/cliconnect.c:997
#19 0x00007ffff7f6f520 in cli_session_setup_gensec_send (target_service=0x7ffff7fa478e "cifs", target_hostname=0x5555555ca480 "freenas", creds=0x5555555adf90, cli=0x5555555adf90, ev=0x5555555aee90,
    mem_ctx=<optimized out>) at ../../source3/libsmb/cliconnect.c:977
#20 cli_session_setup_spnego_send (creds=0x5555555adf90, cli=0x5555555adf90, ev=0x5555555aee90, mem_ctx=<optimized out>) at ../../source3/libsmb/cliconnect.c:1346
#21 cli_session_setup_creds_send (mem_ctx=mem_ctx@entry=0x5555555aee90, ev=ev@entry=0x5555555aee90, cli=cli@entry=0x5555555adf90, creds=creds@entry=0x5555555b4380) at ../../source3/libsmb/cliconnect.c:1505
#22 0x00007ffff7f6fcad in cli_session_setup_creds (cli=0x5555555adf90, creds=creds@entry=0x5555555b4380) at ../../source3/libsmb/cliconnect.c:1843
#23 0x00007ffff7f8ca57 in do_connect (ctx=ctx@entry=0x5555555aae90, server=<optimized out>, server@entry=0x5555555b4790 "freenas", share=share@entry=0x555555571183 "IPC$", auth_info=0x5555555b42f0,
    force_encrypt=<optimized out>, max_protocol=max_protocol@entry=13, port=0, name_type=32, pcli=0x7fffffffd8a0) at ../../source3/libsmb/clidfs.c:236
#24 0x00007ffff7f8cfa8 in cli_cm_connect (ctx=ctx@entry=0x5555555aae90, referring_cli=referring_cli@entry=0x0, server=server@entry=0x5555555b4790 "freenas", share=share@entry=0x555555571183 "IPC$",
    auth_info=<optimized out>, force_encrypt=force_encrypt@entry=false, max_protocol=13, port=0, name_type=32, pcli=0x7fffffffd900) at ../../source3/libsmb/clidfs.c:339
#25 0x00007ffff7f8d13f in cli_cm_open (ctx=0x5555555aae90, referring_cli=0x0, server=0x5555555b4790 "freenas", share=0x555555571183 "IPC$", auth_info=<optimized out>, force_encrypt=<optimized out>,
    max_protocol=13, port=0, name_type=32, pcli=0x55555557c398 <cli>) at ../../source3/libsmb/clidfs.c:441
#26 0x000055555555edc0 in do_host_query (query_host=0x5555555b4790 "freenas") at ../../source3/client/client.c:6702
#27 main (argc=<optimized out>, argv=<optimized out>) at ../../source3/client/client.c:6702
(gdb)

When explicitly setting gse_ctx->k5ctx to NULL after the free, this crash no longer occurs and I can now access SMB shares successfully:

err_out:
        if (gse_ctx->k5ctx) {
                krb5_free_context(gse_ctx->k5ctx);
                gse_ctx->k5ctx = NULL;
        }

        TALLOC_FREE(gse_ctx);

This bug appears to have been fixed upstream by removing the explicit krb5_free_context call here and depending on gse_context_destructor to free the k5ctx member pointer:

err_out:
        TALLOC_FREE(gse_ctx);