Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-64742

QDnsLookup crash on unix when DNS response is over 512 byte

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P1: Critical
    • Resolution: Done
    • Affects Version/s: 5.3.2
    • Fix Version/s: 5.9.4
    • Component/s: Network: DNS
    • Labels:
      None
    • Environment:
      Running a Qt daemon application inside a docker container
    • Commits:
      306c32f50e289c401e4636976c97dc2b40fdd69b

      Description

      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

      1. 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();
        
      1. Package the application as a deamon in a docker based on Debian Jessie
      2. 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

       

        Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

            • Assignee:
              tpochep Timur Pocheptsov
              Reporter:
              stephane.brillant Stephane Brillant
            • Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Gerrit Reviews

                There are no open Gerrit changes