httpd-38340

Version:  

httpd 2.2.0

Failure report link:

https://issues.apache.org/bugzilla/show_bug.cgi?id=38340

How it is diagnosed (reproduced or source analysis)?

We cannot reproduce it so we relied on source analysis

Symptom:

Refuse valid input: common header codes (0xA0??) as described in http://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html.en#resppacketstruct

error printed and asserted.

[Fri Jan 20 14:07:48 2006] [debug] mod_proxy_ajp.c(195): proxy:
APR_BUCKET_IS_EOS
[Fri Jan 20 14:07:48 2006] [debug] mod_proxy_ajp.c(200): proxy: data to read
(max 8186 at 4)
[Fri Jan 20 14:07:48 2006] [debug] mod_proxy_ajp.c(215): proxy: got 0 bytes of
data
[Fri Jan 20 14:07:51 2006] [debug] ajp_header.c(643): ajp_read_header:
ajp_ilink_received 04
[Fri Jan 20 14:07:51 2006] [debug] ajp_header.c(653): ajp_parse_type: got 04
[Fri Jan 20 14:07:51 2006] [debug] ajp_header.c(484): ajp_unmarshal_response:
status = 200
[Fri Jan 20 14:07:51 2006] [debug] ajp_header.c(495): ajp_unmarshal_response:
Number of headers is = 2

[Fri Jan 20 14:07:51 2006] [error] ajp_msg_get_string():
BufferOverflowException 16 55
[Fri Jan 20 14:07:51 2006] [error] ajp_unmarshal_response: Null header value
[Fri Jan 20 14:07:51 2006] [error] (120001)APR does not understand this error
code: proxy: send body failed to (null) (localhost)

Root cause:

Developers used a wrong function when parsing response packet, causing Apache to mistakenly think there was a buffer overflow. The pointer of a buffer is not increased after read.

apr_status_t ajp_unmarshal_response(... ...)

{

… ...

 /* Root cause: using a wrong parsing function. */

 for(i = 0 ; i < (int) num_headers ; i++) {

    if ((name & 0XFF00) == 0XA000) {

-       ajp_msg_peek_uint16(msg, &name);

+       ajp_msg_get_uint16(msg, &name);

           ..

 /* The error message is printed eventually inside this function by a

    func named BufferOverflowException 16 55 */

   rc = ajp_msg_get_string(msg, &value);

         

}

apr_status_t ajp_msg_get_string(ajp_msg_t *msg, const char **rvalue) {

   status = ajp_msg_get_uint16(msg, &size);

   start = msg->pos;

   if ((status != APR_SUCCESS) || (size + start > AJP_MSG_BUFFER_SZ)) {

      // We reach here because size + start > AJP_MSG_BUFFER_SZ

      // start = msg->pos

      // size =  msg->buf[msg->pos-1] << 8 + msg->buf[msg->pos-1]

      // This function is to only print the BufferOverflowException,

      // msg->pos, msg->len, and return OVERFLOW status.

      // They check buffer overflow

     // before actually dereferencing the memory location.

       return ajp_log_overflow(msg, "ajp_msg_get_string");

     

   }

   msg->pos += (apr_size_t)size;

   msg->pos++;                   /* a String in AJP is NULL terminated */

   *rvalue = (const char *)(msg->buf + start);

   return APR_SUCCESS;

}

--------- Root cause: used wrong function.  ---------

ajp_msg_peek_uint16() peek a 16bits value from AJP message, position in message buffer is not updated.

apr_status_t ajp_msg_peek_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue) {

   apr_uint16_t value;

   if ((msg->pos + 1) > msg->len) {

       return ajp_log_overflow(msg, "ajp_msg_peek_uint16");

   }

   value = ((msg->buf[(msg->pos)] & 0xFF) << 8);

   value += ((msg->buf[(msg->pos + 1)] & 0xFF));

   *rvalue = value;

   return APR_SUCCESS;

}

ajp_msg_get_uint16() gets a 16bits value from AJP message, but also increment msg->pos by one.

apr_status_t ajp_msg_get_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue)

{

   apr_uint16_t value;

   if ((msg->pos + 1) > msg->len) {

       return ajp_log_overflow(msg, "ajp_msg_get_uint16");

   }

   value  = ((msg->buf[(msg->pos++)] & 0xFF) << 8);

   value += ((msg->buf[(msg->pos++)] & 0xFF));

   *rvalue = value;

   return APR_SUCCESS;

}

Since the programmers used peek function instead of get, the pointer of a buffer wasn’t updated and the next read from the pointer by sjp_msg_get_string got a wrong data --> buffer overflow error:

Fix:

use a correct function (get) instead of (peek)

Is there Error Message?

Yes.

Can Errlog anticipate the error message?

Yes. The error message is printed when a memory safety check fails (bound check). The pattern is:

if (index >= LENGTH) {

 handle_buffer_overflow;

}

… =a[index];