[Bug 267944] free() of uninitialized pointer from kadmind_dispatch() and ret_principal_ent()

From: <bugzilla-noreply_at_freebsd.org>
Date: Wed, 23 Nov 2022 10:43:20 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=267944

            Bug ID: 267944
           Summary: free() of uninitialized pointer from
                    kadmind_dispatch() and ret_principal_ent()
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: bugs@FreeBSD.org
          Reporter: rtm@lcs.mit.edu
 Attachment #238276 text/plain
         mime type:

Created attachment 238276
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=238276&action=edit
provoke a free() of an uninitialized pointer in kadmin

kadmind_dispatch() says:

    kadm5_principal_ent_rec ent;
    ...;
    case kadm_create:{
        ret = kadm5_ret_principal_ent(sp, &ent);
        ...;
        ret = krb5_ret_int32(sp, &mask);
        if(ret){
            kadm5_free_principal_ent(contextp->context, &ent);

kadm5_free_pincipal_ent(hand, princ) frees ent.mod_name (and in
particular ent->mod_name->name.name_string.val):

    if(princ->mod_name)
        krb5_free_principal(context->context, princ->mod_name);

However, certain client messages can cause princ->mod_name to be
uninitialized (and contain a non-NULL garbage value).

kadmind_dispatch() doesn't zero out ent. ret_principal_ent() in
lib/kadm5/marshall.c is in charge of setting all fields from values
sent by the client. For mod_name:

    if (mask & KADM5_MOD_NAME) {
        krb5_ret_int32(sp, &tmp);
        if(tmp)
            krb5_ret_principal(sp, &princ->mod_name);
        else
            princ->mod_name = NULL;
    }

In this situation the mask bit is always set. krb5_ret_principal() can
return an error for some client inputs -- but ret_principal_ent()
ignores the error, and on such a code path mode_name is never set, and
continues to hold the uninitialized value. One way this can happen is
if the client message is too short, so that krb5_ret_principal() hits
the end before it has read everything it needs.

I've attached a demo; kdc and kadmind should be running, and the user
must have kerberos tickets.

# cc kadmind14a.c -lkrb5
# ./a.out

A backtrace from kadmind. valgrind also sees the bad free().

#0  der_free_general_string (str=0x11ad9e1000000000)
    at /usr/rtm/symbsd/src/crypto/heimdal/lib/asn1/der_free.c:43
#1  0x000000070731254c in free_PrincipalName (data=0x67fafadac <recenti>)
    at asn1_krb5_asn1.c:961
#2  0x00000007073129ae in free_Principal (data=0x67fafadac <recenti>)
    at asn1_krb5_asn1.c:1122
#3  0x0000000704e6919c in krb5_free_principal (context=<optimized out>, 
    p=0x67fafadac <recenti>)
    at /usr/rtm/symbsd/src/crypto/heimdal/lib/krb5/principal.c:84
#4  0x0000000701eaff68 in kadm5_free_principal_ent (server_handle=0x711ad9e10, 
    princ=0x7009e6390)
    at /usr/rtm/symbsd/src/crypto/heimdal/lib/kadm5/free.c:66
#5  0x000000067faf6146 in kadmind_dispatch (kadm_handlep=0x711b1f4c0, 
    initial=0, in=<optimized out>, out=0x7009e6568)
    at /usr/rtm/symbsd/src/crypto/heimdal/kadmin/server.c:122
#6  0x000000067faf5f16 in v5_loop (contextp=<optimized out>, 
    ac=<optimized out>, initial=<optimized out>, kadm_handlep=<optimized out>, 
    fd=<optimized out>)
    at /usr/rtm/symbsd/src/crypto/heimdal/kadmin/server.c:459
#7  0x000000067faf5dea in handle_v5 (contextp=0x711ad9e10, 
    keytab=<optimized out>, fd=<optimized out>)
    at /usr/rtm/symbsd/src/crypto/heimdal/kadmin/server.c:551
#8  0x000000067faf5cf2 in kadmind_loop (contextp=0x711ad9e10,

-- 
You are receiving this mail because:
You are the assignee for the bug.