Hello Patrick,

On 06/14/2018 11:05 PM, Patrick Hemmer wrote:
Haproxy segfaults if you pass the wrong argument type to a converter.
Example:

haproxy.cfg:
     global
         lua-load /tmp/haproxy.lua

     frontend f1
         mode http
         bind :8000
         default_backend b1

         http-request lua.foo

     backend b1
         mode http
         server s1 127.0.0.1:8080

haproxy.lua:
     core.register_action("foo", { "http-req" }, function(txn)
         txn.sc:ipmask(txn.f:src(), 24, 112)
     end)

Result:
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x18)         frame #0: 0x00007fffc9fcbf56 libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 182
libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell:
     ->  0x7fffc9fcbf56 <+182>: movb   (%rsi,%r8), %cl
         0x7fffc9fcbf5a <+186>: movb   %cl, (%rdi,%r8)
         0x7fffc9fcbf5e <+190>: subq   $0x1, %rdx
         0x7fffc9fcbf62 <+194>: je 0x7fffc9fcbf78            ; <+216>
     Target 0: (haproxy) stopped.
     (lldb) bt
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x18)       * frame #0: 0x00007fffc9fcbf56 libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 182
         frame #1: 0x00007fffc9e7442e libsystem_c.dylib`__memcpy_chk + 22
        frame #2: 0x000000010002ec46 haproxy`hlua_lua2arg_check(L=0x000000010120d298, first=3, argp=0x00007fff5fbfe690, mask=196, p=0x0000000101817000) at hlua.c:749         frame #3: 0x000000010001fa00 haproxy`hlua_run_sample_conv(L=0x000000010120d298) at hlua.c:3393
         frame #4: 0x000000010032400b haproxy`luaD_precall + 747
         frame #5: 0x00000001003343c6 haproxy`luaV_execute + 3158
         frame #6: 0x0000000100323429 haproxy`luaD_rawrunprotected + 89
         frame #7: 0x0000000100324516 haproxy`lua_resume + 278
        frame #8: 0x000000010001b199 haproxy`hlua_ctx_resume(lua=0x0000000101205080, yield_allowed=1) at hlua.c:1080         frame #9: 0x0000000100027de8 haproxy`hlua_action(rule=0x000000010101b180, px=0x0000000101817000, sess=0x000000010120cb70, s=0x000000010120cc00, flags=2) at hlua.c:6198         frame #10: 0x0000000100044bcd haproxy`http_req_get_intercept_rule(px=0x0000000101817000, rules=0x0000000101817048, s=0x000000010120cc00, deny_status=0x00007fff5fbfee78) at proto_http.c:2760         frame #11: 0x0000000100046182 haproxy`http_process_req_common(s=0x000000010120cc00, req=0x000000010120cc10, an_bit=16, px=0x0000000101817000) at proto_http.c:3461         frame #12: 0x0000000100094c50 haproxy`process_stream(t=0x000000010120cf40, context=0x000000010120cc00, state=9) at stream.c:1905         frame #13: 0x000000010016179f haproxy`process_runnable_tasks at task.c:362         frame #14: 0x00000001000ea0eb haproxy`run_poll_loop at haproxy.c:2403         frame #15: 0x00000001000e7c74 haproxy`run_thread_poll_loop(data=0x00007fff5fbff3a4) at haproxy.c:2464         frame #16: 0x00000001000e4a49 haproxy`main(argc=3, argv=0x00007fff5fbff590) at haproxy.c:3082
         frame #17: 0x00007fffc9db9235 libdyld.dylib`start + 1

Issue goes away if you change the lua txn.sc:ipmask() line to:
     txn.sc:ipmask(txn.f:src(), '24', '112')

Reproduced with current master (9db0fed) and lua version 5.3.4.

-Patrick

I have reproduced the same issue with varnishtest.

Here is a linux backtrace:


Program terminated with signal SIGSEGV, Segmentation fault.
#0  __memcpy_sse2_unaligned ()
    at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33
33 ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.
(gdb) bt
#0  __memcpy_sse2_unaligned ()
    at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33
#1  0x000000000041b428 in hlua_lua2arg_check (L=L@entry=0xf1b528,
first=first@entry=3, argp=argp@entry=0x7fffa27a2790, mask=196, p=0xee3600)
    at src/hlua.c:749
#2 0x000000000041c6ae in hlua_run_sample_conv (L=0xf1b528) at src/hlua.c:3393
#3  0x0000000000508664 in luaD_precall ()
#4  0x000000000051350d in luaV_execute ()
#5  0x0000000000507ebc in luaD_rawrunprotected ()
#6  0x0000000000508af0 in lua_resume ()
#7  0x0000000000423dec in hlua_ctx_resume (lua=0xf1b490,
    yield_allowed=yield_allowed@entry=1) at src/hlua.c:1080
#8  0x0000000000428bb7 in hlua_action (rule=0xee51c0, px=0xee3600,
    sess=<optimized out>, s=0xf15690, flags=2) at src/hlua.c:6198
#9  0x0000000000438a9c in http_req_get_intercept_rule (px=0xeb8d20,
    px@entry=0xee3600, rules=0xee3648, s=0xf15690, deny_status=0x726a606e,
    deny_status@entry=0x7fffa27a2d6c) at src/proto_http.c:2760
#10 0x000000000043e216 in http_process_req_common (s=s@entry=0xf15690,
    req=req@entry=0xf156a0, an_bit=an_bit@entry=16, px=0xee3600)
    at src/proto_http.c:3461
#11 0x000000000046fcb0 in process_stream (t=<optimized out>, context=0xf15690,
    state=<optimized out>) at src/stream.c:1905
#12 0x00000000004efeca in process_runnable_tasks () at src/task.c:362
#13 0x00000000004a25f4 in run_poll_loop () at src/haproxy.c:2403
#14 run_thread_poll_loop (data=data@entry=0xf0b2d0) at src/haproxy.c:2464
#15 0x000000000041642a in main (argc=<optimized out>, argv=0x7fffa27a3288)
    at src/haproxy.c:3067
(gdb) p ((struct arg*)0x7fffa27a2790).data
$6 = {sint = 24, str = {str = 0x18 <error: Cannot access memory at address 0x18>, size = 822083584, len = 959787063}, ipv4 = {s_addr = 24}, ipv6 = {__in6_u = { __u6_addr8 = "\030\000\000\000\000\000\000\000\000\000\000\061\067\060\065\071", __u6_addr16 = {24, 0, 0, 0, 0, 12544, 12343, 14645}, __u6_addr32 = {24, 0, 822083584, 959787063}}}, prx = 0x18, srv = 0x18, usr = 0x18, map = 0x18, reg = 0x18, var = {name = 0x18 <error: Cannot access memory at address 0x18>,
    scope = 822083584}}


It seems that 'str' field to be corrupted.

The varnishtest attached to this mail passes with the same modification that of Patrick.



$ ~/src/haproxy/haproxy -vv
HA-Proxy version 1.9-dev0-9db0fe-450 2018/06/14
Copyright 2000-2017 Willy Tarreau <wi...@haproxy.org>

Build options :
  TARGET  = linux2628
  CPU     = generic
  CC      = gcc
CFLAGS = -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -fno-strict-overflow -Wno-unused-label
  OPTIONS = USE_THREAD=1 USE_LUA=1

Default settings :
  maxconn = 2000, bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with Lua version : Lua 5.3.4
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Encrypted password support via crypt(3): yes
Built with multi-threading support.
Built without PCRE or PCRE2 support (using libc's regex instead)
Built without compression support (neither USE_ZLIB nor USE_SLZ are set).
Compression algorithms supported : identity("identity")
Built with network namespace support.

Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use epoll.

Available filters :
        [SPOE] spoe
        [COMP] compression
        [TRACE] trace

varnishtest "Basic test h00000" 
feature ignore_unknown_macro

server s1 -repeat 2 {
    rxreq
    txresp
} -start

haproxy h1 -conf {
    global
        lua-load ${testdir}/h00000.lua
   
    frontend fe1
        mode http
        bind "fd@${fe1}"
        default_backend b1
   
        http-request lua.foo
   
    backend b1
        mode http
        server s1 ${s1_addr}:${s1_port}

} -start

client c0 -connect ${h1_fe1_sock} {
    txreq -url "/foo"
    rxresp
    expect resp.status == 200
}

client c1 -connect ${h1_fe1_sock} {
    txreq -url "/foo"
    rxresp
    expect resp.status == 200
}

client c0 -start
client c1 -start

client c0 -wait
client c1 -wait

Reply via email to