-
Bug
-
Resolution: Done
-
P1: Critical
-
5.3.2
-
None
-
Running a Qt daemon application inside a docker container
-
306c32f50e289c401e4636976c97dc2b40fdd69b
Description
A segmentation fault occur in (src/network/kernel/qdnslookup_unix.cpp) when using QDnsLookup to acces large TXT fields (561 byte) on a DNS query.
According to RFC, UDP DNS query over 512 byte can be truncated and the requester should retry to query over TCP. This is what is happening currently in my use case using QDnsLookup on Unix. I wasn't able to reproduce the crash on Windows or OSX
Steps To Reproduce
- Perform a QDNSLookup on TXT fields. ex:
QDnsLookup* txtLookup = new QDnsLookup(this); txtLookup->setNameserver(dns); txtLookup->setType(QDnsLookup::TXT); txtLookup->setName(TXTLOOKUPNAME); connect(txtLookup, &QDnsLookup::finished,......); txtLookup->lookup();
- Package the application as a deamon in a docker based on Debian Jessie
- Run the query periodically and wait for it to crash
Observed Behavior
When not crashing, results are truncated to 512 byte. TXT fields are returned by the name sever in random order so the fields that will be missing or truncated can vary. According the the order of the TXT fields, Qt can crash from a buffer overflow error because the response header state that the response contain more fields that what Qt is accepting from the request. Qt buffer size is set to PACKETSZ in unix
Expected behavior
The DNS query over TCP should parse the full content of the reply.
Possible solution
Increasing the size of the response buffer to 65536 (large enough for the largest DNS message) fixed the crash and the truncated responses content for me.
Call stack
From GDB with all QT debug symbol and no optimization:
(gdb) bt full
#0 0x00007ffff714c473 in QDnsLookupRunnable::query (requestType=16, requestName=..., nameserver=..., reply=0x7fffe5
be8d20) at kernel/qdnslookup_unix.cpp:357
length = 0 '\000'
length = 0 '\000'
txt = 0x7fffe5bea000 ""
record = {d = {d = 0x7fffd00037f0}}
name = {static null = {<No data fields>}, d = 0x7fffd0003860}
type = 16
ttl = 6973814
size = 25902
p = 0x7fffe5be8395 "com"
state = {retrans = 5, retry = 2, options = 524993, nscount = 1, nsaddr_list = {{sin_family = 2, sin_port = 1
3568, sin_addr = {s_addr = 21080256}, sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0, sin_port = 0, sin
_addr = {s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0, sin_port = 0, sin_addr = {s_addr
= 0}, sin_zero = "\000\000\000\000\000\000\000"}}, id = 4324, dnsrch = {0x7fffe5be8810 "cgocable.ca", 0x0, 0x0, 0x0,
0x0, 0x0, 0x0}, defdname = "cgocable.ca", '\000' <repeats 244 times>, pfcode = 0, ndots = 1, nsort = 0, ipv6_unavai
l = 0, unused = 0, sort_list = {{addr = {s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {s_addr =
0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {a
ddr = {s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {s_addr = 0
}, mask = 0}}, qhook = 0x0, rhook = 0x0, res_h_errno = 0, _vcsock = -1, _flags = 0, _u = {pad = "\001\000\000\000\00
0\000\000\000\377\377\377\377", '\000' <repeats 12 times>, "\240\023\000\320\377\177", '\000' <repeats 18 times>, "\
004\000\000", _ext = {nscount = 1, nsmap = {0, 0, 0}, nssocks = {-1, 0, 0}, nscount6 = 0, nsinit = 0, nsaddrs = {0x7
fffd00013a0, 0x0, 0x0}, _initstamp = {4, 0}}}}
state_ptr = {d = 0x7fffe5be8790}
response = "\344\020\201\200\000\001\000\a\000\000\000\000\004jive\003com\000\000\020\000\001\300\f\000\020\
000\001\000\000\000$\000-,status-page-domain-verification=0drlhdrwfd27\300\f\000\020\000\001\000\000\000$\000>=citri
x-verification-code=4bd0f3e9-f63e-4b7c-842f-1c8afd5fd746\300\f\000\020\000\001\000\000\000$\000EDgoogle-site-verific
ation=_4GdMM"...
responseLength = 512
responseLength = 512
answerCount = 7
host = "jive.com", '\000' <repeats 503 times>
status = 2
triedResolve = {_q_value = 1}
header = 0x7fffe5be8190
answer = '\000' <repeats 511 times>
answerIndex = 6
#1 0x00007ffff7135038 in QDnsLookupRunnable::run (this=0x7ea790) at kernel/qdnslookup.cpp:998
reply = {error = QDnsLookup::NoError, errorString = {static null = {<No data fields>}, d = 0x7ffff644d8a0 <Q
ArrayData::shared_null>}, canonicalNameRecords = {{p = {static shared_null = {ref = {atomic = {_q_value = -1}}, allo
c = 0, begin = 0, end = 0, array = {0x0}}, d = 0x7ffff6451570 <QListData::shared_null>}, d = 0x7ffff6451570 <QListDa
ta::shared_null>}}, hostAddressRecords = {{p = {static shared_null = {ref = {atomic = {_q_value = -1}}, alloc = 0, b
egin = 0, end = 0, array = {0x0}}, d = 0x7ffff6451570 <QListData::shared_null>}, d = 0x7ffff6451570 <QListData::shar
ed_null>}}, mailExchangeRecords = {{p = {static shared_null = {ref = {atomic = {_q_value = -1}}, alloc = 0, begin =
0, end = 0, array = {0x0}}, d = 0x7ffff6451570 <QListData::shared_null>}, d = 0x7ffff6451570 <QListData::shared_null
>}}, nameServerRecords = {{p = {static shared_null = {ref = {atomic = {_q_value = -1}}, alloc = 0, begin = 0, end =
0, array = {0x0}}, d = 0x7ffff6451570 <QListData::shared_null>}, d = 0x7ffff6451570 <QListData::shared_null>}}, poin
terRecords = {{p = {static shared_null = {ref = {atomic = {_q_value = -1}}, alloc = 0, begin = 0, end = 0, array = {
0x0}}, d = 0x7ffff6451570 <QListData::shared_null>}, d = 0x7ffff6451570 <QListData::shared_null>}}, serviceRecords =
{{p = {static shared_null = {ref = {atomic = {_q_value = -1}}, alloc = 0, begin = 0, end = 0, array = {0x0}}, d = 0
x7ffff6451570 <QListData::shared_null>}, d = 0x7ffff6451570 <QListData::shared_null>}}, textRecords = {{p = {static
shared_null = {ref = {atomic = {_q_value = -1}}, alloc = 0, begin = 0, end = 0, array = {0x0}}, d = 0x7fffd00034d0},
d = 0x7fffd00034d0}}}
#2 0x00007ffff60fdf9d in QThreadPoolThread::run (this=0x7ea8c0) at thread/qthreadpool.cpp:101
autoDelete = true
autoDelete = true
r = 0x7ea7a0
expired = false
locker = {val = 8298288}
__PRETTY_FUNCTION__ = "virtual void QThreadPoolThread::run()"
#3 0x00007ffff61043c1 in QThreadPrivate::start (arg=0x7ea8c0) at thread/qthread_unix.cpp:345
__clframe = {__cancel_routine = 0x7ffff6104448 <QThreadPrivate::finish(void*)>, __cancel_arg = 0x7ea8c0, __d
o_it = 1, __cancel_type = 0}
thr = 0x7ea8c0
data = 0x7eabd0
objectName = {static null = {<No data fields>}, d = 0x7eacc0}
#4 0x00007ffff5baa064 in start_thread (arg=0x7fffe5be9700) at pthread_create.c:309
__res = <optimized out>
pd = 0x7fffe5be9700
now = <optimized out>
unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737047860992, -5318128364370376861, 1, 140737354125408, 14073
7338628140, 140737047860992, 5318184984417552227, 5318149832888305507}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x
0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
not_first_call = <optimized out>
pagesize_m1 = <optimized out>
sp = <optimized out>
freesize = <optimized out>
__PRETTY_FUNCTION__ = "start_thread"
#5 0x00007ffff50bd62d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
Here is the full content on the response (truncated by Qt) after the segmentation fault. You can compare it with the attached packet capture to see the actual content of the full request >512 byte:
(gdb) x/70s &response 0x7fffe5be8190: "\252w\201\200" 0x7fffe5be8195: "\001" 0x7fffe5be8197: "\a" 0x7fffe5be8199: "" 0x7fffe5be819a: "" 0x7fffe5be819b: "" 0x7fffe5be819c: "\004jive\003com" 0x7fffe5be81a6: "" 0x7fffe5be81a7: "\020" 0x7fffe5be81a9: "\001\300\f" 0x7fffe5be81ad: "\020" 0x7fffe5be81af: "\001" 0x7fffe5be81b1: "" 0x7fffe5be81b2: "" 0x7fffe5be81b3: "\t" 0x7fffe5be81b5: ">=citrix-verification-code=4bd0f3e9-f63e-4b7c-842f-1c8afd5fd746\300\f" 0x7fffe5be81f7: "\020" 0x7fffe5be81f9: "\001" 0x7fffe5be81fb: "" 0x7fffe5be81fc: "" 0x7fffe5be81fd: "\t" 0x7fffe5be81ff: "EDgoogle-site-verification=_4GdMM2-9DuMtEdksMjatJYREN3UzvegKUw4z3QkjRU\300\f" 0x7fffe5be8248: "\020" 0x7fffe5be824a: "\001" 0x7fffe5be824c: "" 0x7fffe5be824d: "" 0x7fffe5be824e: "\t" 0x7fffe5be8250: "\307\306v=spf1 ip4:199.36.248.1/22 ip4:199.87.120.1/22 ip4:199.87.120.0/22 +include:stspg-customer.co m +include:_spf.google.com +include:_spf.salesforce.com +include:mktomail.com +include:amazonses.com ~all"... 0x7fffe5be8318: "\300\f" 0x7fffe5be831b: "\020" 0x7fffe5be831d: "\001" 0x7fffe5be831f: "" 0x7fffe5be8320: "" 0x7fffe5be8321: "\t" 0x7fffe5be8323: "\016\rMS=ms35084001\300\f" 0x7fffe5be8335: "\020" 0x7fffe5be8337: "\001" 0x7fffe5be8339: "" 0x7fffe5be833a: "" 0x7fffe5be833b: "\t" 0x7fffe5be833d: "\022\021\066\065\070\070\062\063\062\064\067-3475009\300\f" 0x7fffe5be8353: "\020" 0x7fffe5be8355: "\001" 0x7fffe5be8357: "" 0x7fffe5be8358: "" 0x7fffe5be8359: "\t" 0x7fffe5be835b: ",+MS=2F8792E977E20CDBD10A4BF28CDE7AD18CCEE50B\300\f" 0x7fffe5be838b: "\020" 0x7fffe5be838d: "\001" 0x7fffe5be838f: "" 0x7fffe5be8390: "jive.com" 0x7fffe5be8399: "" 0x7fffe5be839a: "" 0x7fffe5be839b: "" 0x7fffe5be839c: "" 0x7fffe5be839d: "" 0x7fffe5be839e: "" 0x7fffe5be839f: "" 0x7fffe5be83a0: "" 0x7fffe5be83a1: "" 0x7fffe5be83a2: "" 0x7fffe5be83a3: "" 0x7fffe5be83a4: "" 0x7fffe5be83a5: ""
The last TXT field is missing :
status-page-domain-verification=0drlhdrwfd27