Short read from krb5_rc_io_read

Mike Patnode mike.patnode at centrify.com
Fri Mar 14 12:41:41 EDT 2008


I'm currently running valgrind on code build with 1.4.3, but I don't see
any difference here in the 1.6 source base.    I'm getting the following
error:


==7938== Conditional jump or move depends on uninitialised value(s)
==7938==    at 0x72A8F7: krb5_rc_io_fetch (rc_dfl.c:356)
==7938==    by 0x72ABE5: krb5_rc_dfl_recover_locked (rc_dfl.c:460)
==7938==    by 0x72AF19: krb5_rc_dfl_recover_or_init (rc_dfl.c:522)
==7938==    by 0x6F68B4: krb5_rc_recover_or_initialize (rcfns.c:44)
==7938==    by 0x6F1671: krb5_get_server_rcache (srv_rcache.c:115)
==7938==    by 0x6EC4A6: krb5_rd_req (rd_req.c:89)
... (my code which looks something like this:

    rc = krb5_auth_con_init(m_kcontext, &serverAuthContext);

    ...

    rc = krb5_rd_req(m_kcontext,
                     &serverAuthContext,
                     &ticket,
                     NULL /* don't check SPN */,
                     &ktab,
                     NULL /* no options */,
                     ret_ticket);

Where we're verifying a user ticket by requesting a service ticket for
the local host to prevent the classic rogue KDC response attack.   In
anycase, it appears krb5_rc_io_read doesn't protect against a short
read:

In krb5_rc_io_fetch, we have:

    int len2;
    unsigned int len;
    krb5_error_code retval;

    rep->client = rep->server = 0;

    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len2,
                             sizeof(len2));
    if (retval)
        return retval;

    if ((len2 <= 0) || (len2 >= maxlen))   // line 356
        return KRB5_RC_IO_EOF;

And krb5_rc_io_read is:

krb5_error_code
krb5_rc_io_read(krb5_context context, krb5_rc_iostuff *d, krb5_pointer
buf,
                unsigned int num)
{
    int count;
    if ((count = read(d->fd, (char *) buf, num)) == -1)
        switch(errno)
        {
        case EIO: return KRB5_RC_IO_IO;
        case EBADF:
        default:
            krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
                                   "Can't read from replay cache: %s",
                                   strerror(errno));
            return KRB5_RC_IO_UNKNOWN;
        }
    if (count == 0)
        return KRB5_RC_IO_EOF;
    return 0;
}

So there is no guarantee that we're are going to read 4 bytes.   I
suspect in this case we read 1, 2 or 3, and valgrind complained about
some of the bytes in len2 not being initialized (or fstat() didn't
initialize st_size?).

Now I strongly suspect this was a side effect of running within valgrind
due to the performance issues introduced.    It only happened once
during a 24 hour stress test of this code path, but I confess to not
having a deep understanding of what's happening at this point in time.
We could obviously pacify valgrind by initializing len2 to 0, but I
don't think that's necessarily the right thing to do...  Is it possible
the length value would be less than 4 bytes?   Any thoughts on whether
this is a real-world problem?

mp





More information about the krbdev mailing list