Full_Name: Peter Arrenbrecht
Version: 2.8.1
OS: Windows 2000
Submission from: (NULL) (193.247.162.250)
Description of crash of mod_ssl on Win2K
========================================
Netscape 4.7 causes Apache/mod_ssl to crash on Win32 when accessing a secure
page. There seems to be an overwrite of central context data for mod_ssl with
string data ("image/gif" etc.).
**** Configuration
apache 1.3.19
mod_ssl 2.8.1-1.3.19
open_ssl 0.9.6
Visual C++ 6.0
Netscape 4.7
**** What to do:
Configure a directory with SSLRequireSSL and basic pwd authentication
required. Access it directly with Netscape, ie. https://127.0.0.1/mydir/
Enter name/pwd. Netscape shows the page, but apache faults with a
bad read access. This happend with both apache 1.3.19 and 1.3.17 with
corresponding versions of mod_ssl. Both in versions built myself and
in binary downloads (I found those only for 1.3.17).
Seems also to happen if the dir does not require password authentication
(call stack is for case with pwd, however).
**** Call stack:
ap_ctx_get(ap_ctx_rec * 0x00000002, char * 0x1001a20c) line 125 + 21 bytes
ssl_io_suck_read(ssl_st * 0x040f5a18, char * 0x0088fe38, int 4096) line 265 + 21
bytes
SSL_recvwithtimeout(buff_struct * 0x0088fdf0, char * 0x0088fe38, int 4096) line
566 + 20 bytes
ssl_io_hook_recvwithtimeout(buff_struct * 0x0088fdf0, char * 0x0088fe38, int
4096) line 460 + 17 bytes
ap_hook_call_func(char * 0x036edbac, ap_hook_entry * 0x007bdc50, ap_hook_func *
0x007c7490) line 649 + 26 bytes
ap_hook_call(char * 0x6ffaf4ec `string') line 382 + 26 bytes
buff_read(buff_struct * 0x0088fdf0, void * 0x0088fe38, int 4096) line 299 + 26
bytes
saferead_guts(buff_struct * 0x0088fdf0, void * 0x0088fe38, int 4096) line 702 +
17 bytes
read_with_errors(buff_struct * 0x0088fdf0, void * 0x0088fe38, int 4096) line 753
+ 17 bytes
ap_bgets(char * 0x036ede28, int 8192, buff_struct * 0x0088fdf0) line 906 + 23
bytes
getline(char * 0x036ede28, int 8192, buff_struct * 0x0088fdf0, int 0) line 834 +
17 bytes
read_request_line(request_rec * 0x008b2df0) line 957 + 29 bytes
ap_read_request(conn_rec * 0x008a91e0) line 1119 + 9 bytes
child_sub_main(int 39) line 5561 + 27 bytes
child_main(int 39) line 5638 + 9 bytes
_threadstartex(void * 0x008428b0) line 212 + 13 bytes
KERNEL32! 77e837cd()
**** Call chain (=== delimits calls, and introduces problem description;
>> indicates current line)
==== Problem: ctx is 0x2! ("if (ctx!=0).." was introduced by me.)
API_EXPORT(void *) ap_ctx_get(ap_ctx *ctx, char *key)
{
int i;
if (ctx != 0) {
>> for (i = 0; ctx->cr_entry[i] != NULL; i++)
if (strcmp(ctx->cr_entry[i]->ce_key, key) == 0)
return ctx->cr_entry[i]->ce_val;
}
return NULL;
}
==== Problem: It seems that only r->pool and r->connection are valid.
==== r->pool is 0, r->connection points to meaningful information.
==== r->server is already an invalid pointer (0x67616d69), and subsequent
==== information is garbage as well. Viewing the values in server, next, prev
==== as characters reveals "image/gif". Starting with the_request, I see the
==== same sequence again. And then again in protocol. In status_line etc. I see
==== "HTTPSon". In sent_bodyct there is again "image/gif".
static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
{
ap_ctx *actx;
struct ssl_io_suck_st *ss;
request_rec *r = NULL;
int rv;
actx = (ap_ctx *)SSL_get_app_data2(ssl);
if (actx != NULL)
r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
rv = -1;
if (r != NULL) {
>> ss = ap_ctx_get(r->ctx, "ssl::io::suck");
if (ss != NULL) {
====
static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len)
{
int iostate = 1;
fd_set fdset;
struct timeval tv;
int err = WSAEWOULDBLOCK;
int rv;
int sock = fb->fd_in;
SSL *ssl;
ssl = ap_ctx_get(fb->ctx, "ssl");
if (!(tv.tv_sec = ap_check_alarm()))
return (SSL_read(ssl, buf, len));
rv = ioctlsocket(sock, FIONBIO, &iostate);
iostate = 0;
ap_assert(!rv);
>> rv = SSL_read(ssl, buf, len);
if (rv <= 0) {
====
static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len)
{
SSL *ssl;
int rc;
if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL)
>> rc = SSL_recvwithtimeout(fb, buf, len);
else
rc = recvwithtimeout(fb->fd, buf, len, 0);
return rc;
}
====
ap_hook_call_func
ap_hook_call
====
static ap_inline int buff_read(BUFF *fb, void *buf, int nbyte)
{
int rv;
#if defined (WIN32) || defined(NETWARE)
if (fb->flags & B_SOCKET) {
#ifdef EAPI
>> if (!ap_hook_call("ap::buff::recvwithtimeout", &rv, fb, buf, nbyte))
#endif /* EAPI */
====
static ap_inline int saferead_guts(BUFF *fb, void *buf, int nbyte)
{
int rv;
if (fb->flags & B_SAFEREAD) {
ap_bhalfduplex(fb);
}
do {
>> rv = buff_read(fb, buf, nbyte);
} while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
return (rv);
}
====
static int read_with_errors(BUFF *fb, void *buf, int nbyte)
{
int rv;
>> rv = saferead(fb, buf, nbyte);
====
API_EXPORT(int) ap_bgets(char *buff, int n, BUFF *fb)
{
int i, ch, ct;
/* Can't do bgets on an unbuffered stream */
if (!(fb->flags & B_RD)) {
errno = EINVAL;
return -1;
}
if (fb->flags & B_RDERR)
return -1;
ct = 0;
i = 0;
for (;;) {
if (i == fb->incnt) {
/* no characters left */
fb->inptr = fb->inbase;
fb->incnt = 0;
if (fb->flags & B_EOF)
break;
>> i = read_with_errors(fb, fb->inptr, fb->bufsiz);
====
static int getline(char *s, int n, BUFF *in, int fold)
{
char *pos, next;
int retval;
int total = 0;
#ifdef CHARSET_EBCDIC
/* When getline() is called, the HTTP protocol is in a state
* where we MUST be reading "plain text" protocol stuff,
* (Request line, MIME headers, Chunk sizes) regardless of
* the MIME type and conversion setting of the document itself.
* Save the current setting of the ASCII-EBCDIC conversion flag
* for uploads, then temporarily set it to ON
* (and restore it before returning).
*/
PUSH_EBCDIC_INPUTCONVERSION_STATE(in, 1);
#endif /*CHARSET_EBCDIC*/
pos = s;
do {
>> retval = ap_bgets(pos, n, in); /* retval == -1 if error, 0 if EOF
*/
====
static int read_request_line(request_rec *r)
{
char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */
const char *ll = l;
const char *uri;
conn_rec *conn = r->connection;
unsigned int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP"
protocol */
int len;
/* Read past empty lines until we get a real request line,
* a read error, the connection closes (EOF), or we timeout.
*
* We skip empty lines because browsers have to tack a CRLF on to the end
* of POSTs to support old CERN webservers. But note that we may not
* have flushed any previous response completely to the client yet.
* We delay the flush as long as possible so that we can improve
* performance for clients that are pipelining requests. If a request
* is pipelined then we won't block during the (implicit) read() below.
* If the requests aren't pipelined, then the client is still waiting
* for the final buffer flush from us, and we will block in the implicit
* read(). B_SAFEREAD ensures that the BUFF layer flushes if it will
* have to block during a read.
*/
ap_bsetflag(conn->client, B_SAFEREAD, 1);
>> while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
====
request_rec *ap_read_request(conn_rec *conn)
{
request_rec *r;
pool *p;
const char *expect;
int access_status;
p = ap_make_sub_pool(conn->pool);
r = ap_pcalloc(p, sizeof(request_rec));
r->pool = p;
r->connection = conn;
conn->server = conn->base_server;
r->server = conn->server;
conn->keptalive = conn->keepalive == 1;
conn->keepalive = 0;
conn->user = NULL;
conn->ap_auth_type = NULL;
r->headers_in = ap_make_table(r->pool, 50);
r->subprocess_env = ap_make_table(r->pool, 50);
r->headers_out = ap_make_table(r->pool, 12);
r->err_headers_out = ap_make_table(r->pool, 5);
r->notes = ap_make_table(r->pool, 5);
r->request_config = ap_create_request_config(r->pool);
r->per_dir_config = r->server->lookup_defaults;
r->sent_bodyct = 0; /* bytect isn't for body */
r->read_length = 0;
r->read_body = REQUEST_NO_BODY;
r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
r->the_request = NULL;
#ifdef EAPI
r->ctx = ap_ctx_new(r->pool);
#endif /* EAPI */
#ifdef CHARSET_EBCDIC
ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 1);
#endif
/* Get the request... */
ap_keepalive_timeout("read request line", r);
>> if (!read_request_line(r)) {
====
(in child_sub_main)
/*
* Read and process each request found on our connection
* until no requests are left or we decide to close.
*/
>> while ((r = ap_read_request(current_conn)) != NULL) {
(void) ap_update_child_status(child_num, SERVER_BUSY_WRITE, r);
====
______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl) www.modssl.org
User Support Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]