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