]> granicus.if.org Git - libevent/commitdiff
evdns: fix searching empty hostnames
authorAzat Khuzhin <a3at.mail@gmail.com>
Thu, 24 Mar 2016 21:33:47 +0000 (00:33 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Thu, 24 Mar 2016 21:37:46 +0000 (00:37 +0300)
From #332:
  Here follows a bug report by **Guido Vranken** via the _Tor bug bounty program_. Please credit Guido accordingly.

  ## Bug report

  The DNS code of Libevent contains this rather obvious OOB read:

  ```c
  static char *
  search_make_new(const struct search_state *const state, int n, const char *const base_name) {
      const size_t base_len = strlen(base_name);
      const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
  ```

  If the length of ```base_name``` is 0, then line 3125 reads 1 byte before the buffer. This will trigger a crash on ASAN-protected builds.

  To reproduce:

  Build libevent with ASAN:
  ```
  $ CFLAGS='-fomit-frame-pointer -fsanitize=address' ./configure && make -j4
  ```
  Put the attached ```resolv.conf``` and ```poc.c``` in the source directory and then do:

  ```
  $ gcc -fsanitize=address -fomit-frame-pointer poc.c .libs/libevent.a
  $ ./a.out
  =================================================================
  ==22201== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60060000efdf at pc 0x4429da bp 0x7ffe1ed47300 sp 0x7ffe1ed472f8
  READ of size 1 at 0x60060000efdf thread T0
  ```

P.S. we can add a check earlier, but since this is very uncommon, I didn't add it.

Fixes: #332
evdns.c

diff --git a/evdns.c b/evdns.c
index 905ff6b5141b81aae5cfd215154e8ea31930ff02..e9dbc35c60662ccda395d21d95997193840b4b57 100644 (file)
--- a/evdns.c
+++ b/evdns.c
@@ -3175,9 +3175,12 @@ search_set_from_hostname(struct evdns_base *base) {
 static char *
 search_make_new(const struct search_state *const state, int n, const char *const base_name) {
        const size_t base_len = strlen(base_name);
-       const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+       char need_to_append_dot;
        struct search_domain *dom;
 
+       if (!base_len) return NULL;
+       need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+
        for (dom = state->head; dom; dom = dom->next) {
                if (!n--) {
                        /* this is the postfix we want */