Hi --

I am developing a new Apache 2.0 module and I have encountered what I think
to be a bug in mod_ssl.  I have been unable to find any reports of a similar
problem.  I think this is because I am using AP_MODE_SPECULATIVE, which is
a bit unusual, so maybe no one else has run into this case yet.


Brief description of the problem:
  The problem is related to the use of both AP_MODE_SPECULATIVE and mod_ssl.
  Under certain conditions, ssl_engine_io.c:ssl_io_input_read() and its helper
  function char_buffer_read() might not handle "inctx->cbuf" properly.  In
  particular, this can lead to the inctx->cbuf.value pointer being assigned an
  incorrect value, after which Apache may segmentation fault.


Software Environment:
  I am running Apache 2.0.4[56] and using the mod_ssl that comes with it.
  The compile and runtime environments that I have been working with are
  Redhat 2.4.18-3 and FreeBSD 4.5.  I am using the standard system development
  tools etc.

  I am configuring Apache like so:
  % ./configure --prefix=/usr/local/apache2-2.0.45 --with-module=aaa:auth_dacs 
\
    --enable-ssl
  % ./httpd -l
  Compiled in modules: core.c mod_access.c mod_auth.c mod_include.c \
    mod_log_config.c mod_env.c mod_setenvif.c mod_ssl.c prefork.c \
    http_core.c mod_mime.c mod_auth_dacs.c mod_status.c mod_autoindex.c \
    mod_asis.c mod_cgi.c mod_negotiation.c mod_dir.c mod_imap.c mod_actions.c \
    mod_userdir.c mod_alias.c mod_so.c

  mod_auth_dacs.c is my new module.  The only thing unusual about it, I think,
  is that it makes the following call:

     rv = ap_get_brigade(r->input_filters, bb, AP_MODE_SPECULATIVE,
                            APR_BLOCK_READ, need);

Conditions:
  The conditions under which this happens are browser dependent.  It doesn't
  seem to ever happen with Mozilla 1.3 or Netscape 4.78 but it does happen
  reproducibly with IE 6.0 and Netscape Navigator 3.01.  I think this is
  related to the way they do SSL I/O because while debugging I see that the
  SSL buffer processing in mod_ssl is slightly different with IE 6.0.

  To trigger the bug, I invoke a POST method using https from IE 6.0, which
  leads mod_auth_dacs to make the function call that appears above.

  The bug does not seem to be present when SSL is not used.


Detailed description of the problem:
  The problem seems to occur if an AP_MODE_SPECULATIVE mode read operation
  is done when ssl_io_input_read() already has input buffered in inctx->cbuf.

  Here is ssl_engine_io.c:char_buffer_read():

  static int char_buffer_read(char_buffer_t *buffer, char *in, int inl)
  {
    if (!buffer->length) {
        return 0;
    }
    if (buffer->length > inl) {
        /* we have have enough to fill the caller's buffer */
        memcpy(in, buffer->value, inl);
        buffer->value += inl;
        buffer->length -= inl;
    }
    else {
        /* swallow remainder of the buffer */
        memcpy(in, buffer->value, buffer->length);
        inl = buffer->length;
        buffer->value = NULL;
        buffer->length = 0;
    }
    return inl;
  }

 If there is not enough buffered input, char_buffer_read() sets
 buffer->value to NULL.  Then, when it returns to ssl_io_input_read():
     if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) {
        *len = bytes;
        if (inctx->mode == AP_MODE_SPECULATIVE) {
            /* We want to rollback this read. */
            inctx->cbuf.value -= bytes;
            inctx->cbuf.length += bytes;
            return APR_SUCCESS;
        }

  it will do "inctx->cbuf.value -= bytes" which sets cbuf.value to an invalid
  pointer.  When the pointer is dereferenced later, a segmentation fault 
  occurs.  So at the very least, it would seem that the code should always
  avoid doing this.

  Also, I found that in char_buffer_read(), "in" and "buffer->value" may
  overlap, so memmove() should probably be used instead of memcpy().

Proposed fix:
  I have not tested this heavily, but it does seem to solve the problem in
  my test case (and my module then works with IE 6.0 and Navigator 3.01, as
  well as Mozilla and Netscape 4.78).

  I changed ssl_io_input_read() like so:

    if ((bytes = char_buffer_read(inctx, buf, wanted))) {
        *len = bytes;
        if (inctx->mode == AP_MODE_SPECULATIVE) {
            return APR_SUCCESS;
        }

  And I changed char_buffer_read() like so:

  static int char_buffer_read(bio_filter_in_ctx_t *inctx, char *in, int inl)
  {
    char_buffer_t *buffer = &inctx->cbuf;

    if (!buffer->length) {
        return 0;
    }

    if (buffer->length > inl) {
        /* we have have enough to fill the caller's buffer */
        memmove(in, buffer->value, inl);
        buffer->value += inl;
        buffer->length -= inl;
    }
    else {
        /* swallow remainder of the buffer */
        memmove(in, buffer->value, buffer->length);
        inl = buffer->length;
        if (inctx->mode == AP_MODE_SPECULATIVE) {
          buffer->value = in;
        }
        else {
          buffer->value = NULL;
          buffer->length = 0;
        }
    }

    return inl;
  }

I would be happy to provide any other details.  I can also show what
happens when I step through the code with gdb.

Thank you for your attention.

Barry

** Barry Brachman
** Distributed Systems Software, Inc.
** [EMAIL PROTECTED]



______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl)                   www.modssl.org
User Support Mailing List                      [EMAIL PROTECTED]
Automated List Manager                            [EMAIL PROTECTED]

Reply via email to