I'm experimenting with haproxy on a centos6 VM here.  I found that when I
specified a health check page (option httpchk GET /url), and that page
didn't exist, we have a large 404 page returned, and that causes haproxy to
quickly segfault (seems like on the second try GET'ing and parsing the
page).  I couldn't figure out from the website where to submit a bug, so I
figure I'll try here first.

Steps to reproduce:
- setup http backend, with option httpchk and httpcheck expect string x.
Make option httpchk point to a non-existent page
- On backend server, set it up to serve large 404 response (in my case, the
404 page is 186kB, as it has an inline graphic and inline css)
- Start haproxy, and wait for it to segfault

I wasn't sure exactly what was causing this at first, so I did some work to
narrow it down with GDB.  The variable values from gdb led me to the cause
on my side, and hopefully can help you fix the issue.  I could not make
this work with simply a large page for the http response - in that case, it
seems to work as advertised, only inspecting the response up to
tune.chksize (default 16384 as i've left it).  But if I do this with a 404,
it seems to kill it.  Let me know what additional information you need if
any.  Thanks and kudos for the great bit of software!


*#haproxy config:*
#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------

# Help in developing config here:
# https://www.twilio.com/engineering/2013/10/16/haproxy


#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2 info

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    #enable stats
    stats socket /tmp/haproxy.sock

listen ha_stats :8088
    balance source
    mode http
    timeout client 30000ms
    stats enable
    stats auth haproxystats:foobar
    stats uri /haproxy?stats

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    #keep persisten client connection open
    option                  http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    # Limit number of retries - total time trying to connect = connect
timeout * (#retries + 1)
    retries                 2
    timeout http-request    10s
    timeout queue           1m
    #timeout opening a tcp connection to server - should be shorter than
timeout client and server
    timeout connect         3100
    timeout client          30s
    timeout server          30s
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend https_frontend
bind :80
 redirect scheme https if !{ ssl_fc }

#config help:
https://github.com/observing/balancerbattle/blob/master/haproxy.cfg
 bind *:443 ssl crt /etc/certs/mycert.pem ciphers
RC4-SHA:AES128-SHA:AES:!ADH:!aNULL:!DH:!EDH:!eNULL
mode http
 default_backend webapp

#---------------------------------------------------------------------
# Main backend for web application servers
#---------------------------------------------------------------------
backend webapp
    balance     roundrobin
    #Insert cookie SERVERID to pin it to one leg
    cookie SERVERID insert nocache indirect
    #http check should pull url below
    option httpchk GET /cp/testcheck.html HTTP/1.0
    #option httpchk GET /cp/testcheck.php HTTP/1.0
    #http check should find string below in response to be considered up
    http-check expect string good
    #Define servers - inter=interval of 5s, rise 2=become avail after 2
successful checks, fall 3=take out after 3 fails
    server app1 app1.myco.com:80 weight 5 cookie app1 check inter 5000 rise
2 fall 3
    server app2 app2.myco.com:80 weight 5 cookie app1 check inter 5000 rise
2 fall 3
    #Example sorry server
    #server backup host.name:80 backup

#---------------------------------------------------------------------
# Balancing for postfix / smtp
#---------------------------------------------------------------------
listen smtp 10.40.60.25:25
    option tcpka
    mode tcp
    option tcplog
    balance roundrobin
    server app1 app1.myco.com:25 check inter 20000
    server app2 app2.myco.com:25 check inter 20000


*GDB STack trace:*
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7fea7c0 (LWP 6083)]
0x00007ffff6e22c64 in memcpy () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install
glibc-2.12-1.132.el6.x86_64 keyutils-libs-1.4-4.el6.x86_64
krb5-libs-1.10.3-10.el6_4.6.x86_64 libcom_err-1.41.12-18.el6.x86_64
libselinux-2.0.94-5.3.el6_4.1.x86_64 nss-softokn-freebl-3.14.3-9.el6.x86_64
openssl-1.0.1e-16.el6_5.1.x86_64 pcre-7.8-6.el6.x86_64
zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0  0x00007ffff6e22c64 in memcpy () from /lib64/libc.so.6
#1  0x0000000000423b42 in bo_putblk (b=0x6eff90, blk=0x6d82d0 "GET
/cp/testcheck.php HTTP/1.0\r\n", len=32)
    at include/common/buffer.h:388
#2  0x0000000000425963 in process_chk (t=0x70fd80) at src/checks.c:1536
#3  0x000000000040e7e0 in process_runnable_tasks (next=0x7fffffffe45c) at
src/task.c:240
#4  0x00000000004051d0 in run_poll_loop () at src/haproxy.c:1278
#5  0x00000000004075f1 in main (argc=<value optimized out>, argv=<value
optimized out>) at src/haproxy.c:1609
(gdb)

*Full GDB output:*
[root@proxy1 ~]# gdb --args /usr/sbin/haproxy  -Ds -f
/etc/haproxy/haproxy.cfg
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html
>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/sbin/haproxy...Reading symbols from
/usr/lib/debug/usr/sbin/haproxy.debug...done.
done.
(gdb) set follow-fork-mode child
(gdb) break src/checks.c:1536
Breakpoint 1 at 0x425949: file src/checks.c, line 1536.
(gdb) run
Starting program: /usr/sbin/haproxy -Ds -f /etc/haproxy/haproxy.cfg
[Thread debugging using libthread_db enabled]
[WARNING] 009/124757 (7470) : config : 'option forwardfor' ignored for
proxy 'smtp' as it requires HTTP mode.
[WARNING] 009/124757 (7470) : config : 'option http-server-close' ignored
for proxy 'smtp' as it requires HTTP mode.
[New process 7473]
[Thread debugging using libthread_db enabled]
[Switching to Thread 0x7ffff7fea7c0 (LWP 7473)]

Breakpoint 1, process_chk (t=0x70fd00) at src/checks.c:1536
1536 bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
Missing separate debuginfos, use: debuginfo-install
glibc-2.12-1.132.el6.x86_64 keyutils-libs-1.4-4.el6.x86_64
krb5-libs-1.10.3-10.el6_4.6.x86_64 libcom_err-1.41.12-18.el6.x86_64
libselinux-2.0.94-5.3.el6_4.1.x86_64 nss-softokn-freebl-3.14.3-9.el6.x86_64
openssl-1.0.1e-16.el6_5.1.x86_64 pcre-7.8-6.el6.x86_64
zlib-1.2.3-29.el6.x86_64
(gdb) continue
Continuing.

Breakpoint 1, process_chk (t=0x70fd80) at src/checks.c:1536
1536 bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
(gdb) continue
Continuing.

Breakpoint 1, process_chk (t=0x70fd00) at src/checks.c:1536
1536 bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
(gdb) continue
Continuing.

Breakpoint 1, process_chk (t=0x70fd80) at src/checks.c:1536
1536 bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
(gdb) step
bo_putblk (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:375
375 {
(gdb) step
379 if (len > b->size - cur_len)
(gdb) step
376 int cur_len = buffer_len(b);
(gdb) step
buffer_len (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:151
151 return buf->i + buf->o;
(gdb) step
bo_putblk (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:375
375 {
(gdb) step
376 int cur_len = buffer_len(b);
(gdb) step
buffer_len (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:151
151 return buf->i + buf->o;
(gdb) step
379 if (len > b->size - cur_len)
(gdb) step
bo_putblk (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:380
380 len = (b->size - cur_len);
(gdb) step
381 if (!len)
(gdb) step
384 half = buffer_contig_space(b);
(gdb) step
buffer_contig_space (b=<value optimized out>, blk=0x6d82d0 "GET
/cp/testcheck.php HTTP/1.0\r\n", len=32)
    at include/common/buffer.h:222
222 if (buf->data + buf->o <= buf->p)
(gdb) step
223 right = buf->data + buf->size;
(gdb) step
222 if (buf->data + buf->o <= buf->p)
(gdb) step
223 right = buf->data + buf->size;
(gdb) step
222 if (buf->data + buf->o <= buf->p)
(gdb) step
227 left = buffer_wrap_add(buf, buf->p + buf->i);
(gdb) step
buffer_wrap_add (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php
HTTP/1.0\r\n", len=32) at include/common/buffer.h:191
191 if (ptr - buf->size >= buf->data)
(gdb) step
bo_putblk (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:388
388 memcpy(b->p, blk, half);
(gdb) print b->p
$1 = 0x6effa4 "play:table-column;float:none}table td[class*=\"col-\"],table
th[class*=\"col-\"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr"...
(gdb) print blk
$2 = 0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n"
(gdb) print half
$3 = <value optimized out>
(gdb)
$4 = <value optimized out>
(gdb) step
384 half = buffer_contig_space(b);
(gdb) step
buffer_contig_space (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php
HTTP/1.0\r\n", len=32) at include/common/buffer.h:227
227 left = buffer_wrap_add(buf, buf->p + buf->i);
(gdb) step
buffer_wrap_add (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php
HTTP/1.0\r\n", len=32) at include/common/buffer.h:191
191 if (ptr - buf->size >= buf->data)
(gdb) step
buffer_contig_space (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php
HTTP/1.0\r\n", len=32) at include/common/buffer.h:228
228 return right - left;
(gdb) step
bo_putblk (b=0x6eff90, blk=0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n",
len=32) at include/common/buffer.h:388
388 memcpy(b->p, blk, half);
(gdb) print b->p
$5 = 0x6effa4 "play:table-column;float:none}table td[class*=\"col-\"],table
th[class*=\"col-\"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr"...
(gdb) print blk
$6 = 0x6d82d0 "GET /cp/testcheck.php HTTP/1.0\r\n"
(gdb) print half
$7 = -2119952626
(gdb)
$8 = -2,119,952,626
(gdb) step

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6e22c64 in memcpy () from /lib64/libc.so.6




Steve Ruiz
Manager - Hosting Operations
Mirth
ste...@mirth.com <ste...@mirthcorp.com>

-- 
CONFIDENTIALITY NOTICE: The information contained in this electronic 
transmission may be confidential. If you are not an intended recipient, be 
aware that any disclosure, copying, distribution or use of the information 
contained in this transmission is prohibited and may be unlawful. If you 
have received this transmission in error, please notify us by email reply 
and then erase it from your computer system.

Reply via email to