From 4358de43b2f29352f50441da180ed34faf609e07 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 17 Sep 2017 14:44:04 -0700 Subject: [PATCH] Fix backward search and string search across boundary in search.overlap=0 mode and fix mem leak (#8537) * Fix mem leaks in search * Fix backward search and string search across boundary in search.overlap=0 mode and fix mem leak --- binr/rafind2/rafind2.c | 2 +- libr/anal/sign.c | 2 +- libr/core/cmd_search.c | 131 ++++++++++++++-------------------------- libr/include/r_search.h | 4 +- libr/search/search.c | 84 ++++++++++++++++++-------- 5 files changed, 108 insertions(+), 115 deletions(-) diff --git a/binr/rafind2/rafind2.c b/binr/rafind2/rafind2.c index f7cebaf552..d541ed4d70 100644 --- a/binr/rafind2/rafind2.c +++ b/binr/rafind2/rafind2.c @@ -189,7 +189,7 @@ static int rafind_open(char *file) { bsize = ret; } - if (r_search_update (rs, &cur, buf, ret) == -1) { + if (r_search_update (rs, cur, buf, ret) == -1) { eprintf ("search: update read error at 0x%08"PFMT64x"\n", cur); break; } diff --git a/libr/anal/sign.c b/libr/anal/sign.c index 4b103b8c46..1f862b954b 100644 --- a/libr/anal/sign.c +++ b/libr/anal/sign.c @@ -920,7 +920,7 @@ R_API int r_sign_search_update(RAnal *a, RSignSearch *ss, ut64 *at, const ut8 *b if (!a || !ss || !buf || len <= 0) { return 0; } - return r_search_update (ss->search, at, buf, len); + return r_search_update (ss->search, *at, buf, len); } static bool fcnMetricsCmp(RSignItem *it, RAnalFunction *fcn) { diff --git a/libr/core/cmd_search.c b/libr/core/cmd_search.c index eed056f816..59f795d992 100644 --- a/libr/core/cmd_search.c +++ b/libr/core/cmd_search.c @@ -121,7 +121,6 @@ static bool json = false; static int first_hit = true; static const char *cmdhit = NULL; static const char *searchprefix = NULL; -static unsigned int searchcount = 0; struct search_parameters { RList *boundaries; @@ -289,7 +288,7 @@ R_API int r_core_search_prelude(RCore *core, ut64 from, ut64 to, const ut8 *buf, break; } (void)r_io_read_at (core->io, at, b, core->blocksize); - if (r_search_update (core->search, &at, b, core->blocksize) == -1) { + if (r_search_update (core->search, at, b, core->blocksize) == -1) { eprintf ("search: update read error at 0x%08"PFMT64x "\n", at); break; } @@ -404,6 +403,7 @@ static char *getstring(char *b, int l) { return res; } +// TODO int -> bool static int __cb_hit(RSearchKeyword *kw, void *user, ut64 addr) { RCore *core = (RCore *) user; ut64 base_addr = 0; @@ -414,18 +414,7 @@ static int __cb_hit(RSearchKeyword *kw, void *user, ut64 addr) { return false; } use_color = core->print->flags & R_PRINT_FLAGS_COLOR; - if (maxhits && searchhits >= maxhits) { - // eprintf ("Error: search.maxhits reached.\n"); - return false; - } - searchhits++; ///= kw->count+1; - if (searchcount) { - if (!--searchcount) { - // eprintf ("\nsearch stop: search.count reached\n"); - return false; - } - } if (searchshow && kw && kw->keyword_length > 0) { int len, i, extra, mallocsize; ut32 buf_sz = kw->keyword_length; @@ -504,8 +493,8 @@ static int __cb_hit(RSearchKeyword *kw, void *user, ut64 addr) { r_cons_printf (","); } char *es = escaped ? s : r_str_escape (s); - r_cons_printf ("{\"offset\": %"PFMT64d ",\"type\":\"%s\",\"data\":\"%s\"}", - base_addr + addr, type, es); + r_cons_printf ("{\"offset\":%"PFMT64d ",\"type\":\"%s\",\"data\":\"%s\"}", + base_addr + addr, type, es); if (!escaped) { free (es); } @@ -521,7 +510,7 @@ static int __cb_hit(RSearchKeyword *kw, void *user, ut64 addr) { if (!first_hit) { r_cons_printf (","); } - r_cons_printf ("{\"offset\": %"PFMT64d ",\"id:\":%d,\"len\":%d}", + r_cons_printf ("{\"offset\": %"PFMT64d ",\"len\":%d}", base_addr + addr, kw->kwidx, kw->keyword_length); } else { if (searchflags) { @@ -1452,6 +1441,7 @@ static int esil_addrinfo(RAnalEsil *esil) { static void do_esil_search(RCore *core, struct search_parameters *param, const char *input) { const int hit_combo_limit = r_config_get_i (core->config, "search.esilcombo"); + RSearch *search = core->search; RSearchKeyword kw = R_EMPTY; searchhits = 0; if (input[0] == 'E' && input[1] != ' ') { @@ -1461,7 +1451,6 @@ static void do_esil_search(RCore *core, struct search_parameters *param, const c RIOMap *map; RListIter *iter; r_list_foreach (param->boundaries, iter, map) { - const int kwidx = r_config_get_i (core->config, "search.kwidx"); const int iotrap = r_config_get_i (core->config, "esil.iotrap"); const int stacksize = r_config_get_i (core->config, "esil.stacksize"); int nonull = r_config_get_i (core->config, "esil.nonull"); @@ -1521,7 +1510,7 @@ static void do_esil_search(RCore *core, struct search_parameters *param, const c } // eprintf (" HIT AT 0x%"PFMT64x"\n", addr); kw.type = 0; // R_SEARCH_TYPE_ESIL; - kw.kwidx = kwidx; + kw.kwidx = search->n_kws; kw.count++; eprintf ("Hits: %d\r", kw.count); kw.keyword_length = 0; @@ -1546,7 +1535,7 @@ static void do_esil_search(RCore *core, struct search_parameters *param, const c hit_combo = 0; } } - r_config_set_i (core->config, "search.kwidx", kwidx + 1); + r_config_set_i (core->config, "search.kwidx", search->n_kws); // TODO remove r_cons_break_pop (); } r_cons_clear_line (1); @@ -1806,8 +1795,7 @@ static void do_asm_search(RCore *core, struct search_parameters *param, const ch static void do_string_search(RCore *core, RAddrInterval search_itv, struct search_parameters *param) { ut64 at; ut8 *buf; - int oldfd = (core && core->io) ? r_io_fd_get_current (core->io) : -1; - int bufsz; + RSearch *search = core->search; if (json) { r_cons_printf ("["); @@ -1822,10 +1810,6 @@ static void do_string_search(RCore *core, RAddrInterval search_itv, struct searc if (param->inverse) { core->search->maxhits = 1; } - searchcount = r_config_get_i (core->config, "search.count"); - if (searchcount) { - searchcount++; - } if (core->search->n_kws > 0 || param->crypto_search) { RSearchKeyword aeskw; if (param->crypto_search) { @@ -1839,10 +1823,14 @@ static void do_string_search(RCore *core, RAddrInterval search_itv, struct searc // REMOVE OLD FLAGS r_core_cmdf (core, "f-%s*", r_config_get (core->config, "search.prefix")); r_search_set_callback (core->search, &__cb_hit, core); cmdhit = r_config_get (core->config, "cmd.hit"); - buf = (ut8 *) malloc (core->blocksize + 1); - buf[core->blocksize] = 0; - bufsz = core->blocksize; + if (!(buf = malloc (core->blocksize))) { + return; + } + if (search->bckwrds) { + r_search_string_prepare_backward (search); + } r_cons_break_push (NULL, NULL); + // TODO search cross boundary r_list_foreach (param->boundaries, iter, map) { if (!r_itv_overlap (search_itv, map->itv)) { continue; @@ -1862,36 +1850,37 @@ static void do_string_search(RCore *core, RAddrInterval search_itv, struct searc break; } - if (param->bckwrds) { - if (itv.size <= bufsz) { - at = itv.addr; - param->do_bckwrd_srch = false; - } else { - at = r_itv_end (itv) - bufsz; - } - } else { - at = itv.addr; - } - /* bckwrds = false -> normal search -> must be at < to - bckwrds search -> check later */ - for (; (!param->bckwrds && at < r_itv_end (itv)) || param->bckwrds;) { - print_search_progress (at, r_itv_end (itv), searchhits); + const ut64 from = itv.addr, to = r_itv_end (itv), + from1 = search->bckwrds ? to : from, + to1 = search->bckwrds ? from : to; + ut64 len; + for (at = from1; at != to1; at = search->bckwrds ? at - len : at + len) { + print_search_progress (at, to1, search->nhits); if (r_cons_is_breaked ()) { eprintf ("\n\n"); break; } - // avoid searching beyond limits - bufsz = R_MIN (bufsz, itv.size); - if (!r_io_is_valid_offset (core->io, at, 0)) { - break; + if (search->bckwrds) { + len = R_MIN (core->blocksize, at - from); + // TODO prefix_read_at + if (!r_io_is_valid_offset (core->io, at - len, 0)) { + break; + } + (void)r_io_read_at (core->io, at - len, buf, len); + } else { + len = R_MIN (core->blocksize, to - at); + if (!r_io_is_valid_offset (core->io, at, 0)) { + break; + } + (void)r_io_read_at (core->io, at, buf, len); } - (void)r_io_read_at (core->io, at, buf, bufsz); if (param->crypto_search) { + // TODO support backward search int delta = 0; if (param->aes_search) { - delta = r_search_aes_update (core->search, at, buf, bufsz); + delta = r_search_aes_update (core->search, at, buf, len); } else if (param->rsa_search) { - delta = r_search_rsa_update (core->search, at, buf, bufsz); + delta = r_search_rsa_update (core->search, at, buf, len); } if (delta != -1) { if (!r_search_hit_new (core->search, &aeskw, at + delta)) { @@ -1900,41 +1889,15 @@ static void do_string_search(RCore *core, RAddrInterval search_itv, struct searc } aeskw.count++; } - } else if (r_search_update (core->search, &at, buf, bufsz) == -1) { + } else if (r_search_update (core->search, at, buf, len) < 0) { // eprintf ("search: update read error at 0x%08"PFMT64x"\n", at); break; } - - if (param->bckwrds) { - if (!param->do_bckwrd_srch) { - break; - } - if (at < bufsz) { - param->do_bckwrd_srch = false; - bufsz = at; - at = 0; - } else if (at - bufsz < itv.addr) { - param->do_bckwrd_srch = false; - bufsz = at - itv.addr; - at = itv.addr; - } else { - at -= bufsz; - } - } else { - at += bufsz; - } } - print_search_progress (at, r_itv_end (itv), searchhits); + print_search_progress (at, to1, search->nhits); r_cons_clear_line (1); - core->num->value = searchhits; - if (searchflags && (searchcount > 0) && !json) { - eprintf ("hits: %d %s%d_0 .. %s%d_%d\n", - searchhits, - searchprefix, core->search->n_kws - 1, - searchprefix, core->search->n_kws - 1, searchcount - 1); - } else if (!json) { - eprintf ("hits: %d\n", searchhits); - } + core->num->value = search->nhits; + eprintf ("hits: %" PFMT64d "\n", search->nhits); } r_cons_break_pop (); free (buf); @@ -1943,15 +1906,10 @@ static void do_string_search(RCore *core, RAddrInterval search_itv, struct searc r_list_free (param->boundaries); param->boundaries = NULL; } - r_io_use_fd (core->io, oldfd); } else { eprintf ("No keywords defined\n"); } - /* Crazy party counter (kill me please) */ - if (!searchhits && core->search->n_kws > 0) { - core->search->n_kws--; - } if (json) { r_cons_printf ("]"); } @@ -2135,6 +2093,7 @@ static int cmd_search(void *data, const char *input) { bool dosearch = false; int i, len, ret = true; RCore *core = (RCore *) data; + RSearch *search = core->search; int ignorecase = false; int param_offset = 2; char *inp; @@ -2873,18 +2832,18 @@ again: eprintf ("See /? for help.\n"); break; } - searchhits = 0; r_config_set_i (core->config, "search.kwidx", core->search->n_kws); if (dosearch) { do_string_search (core, search_itv, ¶m); } beach: - core->num->value = searchhits; + core->num->value = search->nhits; core->in_search = false; r_flag_space_pop (core->flags); if (json) { r_cons_newline (); } r_list_free (param.boundaries); + r_search_kw_reset (search); return ret; } diff --git a/libr/include/r_search.h b/libr/include/r_search.h index c4332704e2..3ee78ca7ad 100644 --- a/libr/include/r_search.h +++ b/libr/include/r_search.h @@ -84,7 +84,7 @@ R_API RSearch *r_search_free(RSearch *s); /* keyword management */ R_API RList *r_search_find(RSearch *s, ut64 addr, const ut8 *buf, int len); -R_API int r_search_update(RSearch *s, ut64 *from, const ut8 *buf, long len); +R_API int r_search_update(RSearch *s, ut64 from, const ut8 *buf, long len); R_API int r_search_update_i(RSearch *s, ut64 from, const ut8 *buf, long len); R_API void r_search_keyword_free (RSearchKeyword *kw); @@ -98,6 +98,8 @@ R_API RSearchKeyword *r_search_keyword_new_regexp (const char *str, const char * R_API int r_search_kw_add(RSearch *s, RSearchKeyword *kw); R_API void r_search_reset(RSearch *s, int mode); R_API void r_search_kw_reset(RSearch *s); +R_API void r_search_string_prepare_backward(RSearch *s); +R_API void r_search_kw_reset(RSearch *s); R_API int r_search_range_add(RSearch *s, ut64 from, ut64 to); R_API int r_search_range_set(RSearch *s, ut64 from, ut64 to); diff --git a/libr/search/search.c b/libr/search/search.c index ff18fe5443..37c7dc6c2a 100644 --- a/libr/search/search.c +++ b/libr/search/search.c @@ -38,7 +38,7 @@ R_API RSearch *r_search_new(int mode) { s->maxhits = 0; // TODO: review those mempool sizes. ensure never gets NULL s->pool = r_mem_pool_new (sizeof (RSearchHit), 1024, 10); - s->kws = r_list_new (); + s->kws = r_list_newf (free); if (!s->kws) { r_search_free (s); return NULL; @@ -51,8 +51,6 @@ R_API RSearch *r_search_free(RSearch *s) { if (!s) { return NULL; } - // TODO: it leaks - free (s->data); r_mem_pool_free (s->pool); r_list_free (s->hits); r_list_free (s->kws); @@ -102,6 +100,7 @@ R_API int r_search_begin(RSearch *s) { return true; } +// TODO int -> bool R_API int r_search_hit_new(RSearch *s, RSearchKeyword *kw, ut64 addr) { RSearchHit* hit; if (s->align && (addr%s->align)) { @@ -111,12 +110,12 @@ R_API int r_search_hit_new(RSearch *s, RSearchKeyword *kw, ut64 addr) { if (!s->contiguous) { if (kw->last && addr == kw->last) { kw->count--; - kw->last = addr + kw->keyword_length; + kw->last = s->bckwrds ? addr : addr + kw->keyword_length; eprintf ("0x%08"PFMT64x" Sequencial hit ignored.\n", addr); return true; } } - kw->last = addr + kw->keyword_length; + kw->last = s->bckwrds ? addr : addr + kw->keyword_length; if (s->callback) { return s->callback (kw, s->user, addr); } @@ -266,7 +265,7 @@ static bool brute_force_match(RSearch *s, RSearchKeyword *kw, const ut8 *buf, in return j == kw->keyword_length; } -// Supported search variants: binmask, icase, inverse, overlap +// Supported search variants: backward, binmask, icase, inverse, overlap R_API int r_search_mybinparse_update(void *_s, ut64 from, const ut8 *buf, int len) { RSearch *s = (RSearch*)_s; RSearchKeyword *kw; @@ -293,14 +292,26 @@ R_API int r_search_mybinparse_update(void *_s, ut64 from, const ut8 *buf, int le s->data = left; left->len = 0; } + if (s->bckwrds) { + // XXX Change function signature from const ut8 * to ut8 * + ut8 *i = (ut8 *)buf, *j = i + len; + while (i < j) { + ut8 t = *i; + *i++ = *--j; + *j = t; + } + } ut64 len1 = left->len + R_MIN (longest - 1, len); memcpy (left->data + left->len, buf, len1 - left->len); r_list_foreach (s->kws, iter, kw) { - i = !s->overlap && from - kw->last < left->len ? kw->last + left->len - from : 0; + i = s->overlap || !kw->count ? 0 : + s->bckwrds + ? kw->last - from < left->len ? from + left->len - kw->last : 0 + : from - kw->last < left->len ? kw->last + left->len - from : 0; for (; i + kw->keyword_length <= len1 && i < left->len; i++) { if (brute_force_match (s, kw, left->data, i) != s->inverse) { - if (!r_search_hit_new (s, kw, from + i - left->len)) { + if (!r_search_hit_new (s, kw, s->bckwrds ? from - kw->keyword_length - i + left->len : from + i - left->len)) { return -1; } kw->count++; @@ -314,9 +325,13 @@ R_API int r_search_mybinparse_update(void *_s, ut64 from, const ut8 *buf, int le } } } - for (i = 0; i + kw->keyword_length <= len; i++) { + i = s->overlap || !kw->count ? 0 : + s->bckwrds + ? from > kw->last ? from - kw->last : 0 + : from < kw->last ? kw->last - from : 0; + for (; i + kw->keyword_length <= len; i++) { if (brute_force_match (s, kw, buf, i) != s->inverse) { - if (!r_search_hit_new (s, kw, from + i)) { + if (!r_search_hit_new (s, kw, s->bckwrds ? from - kw->keyword_length - i: from + i)) { return -1; } kw->count++; @@ -342,7 +357,7 @@ R_API int r_search_mybinparse_update(void *_s, ut64 from, const ut8 *buf, int le left->len = longest - 1; memcpy (left->data, buf + len - longest + 1, longest - 1); } - left->end = from + len; + left->end = s->bckwrds ? from - len : from + len; return count; } @@ -366,14 +381,15 @@ R_API void r_search_set_callback(RSearch *s, RSearchCallback(callback), void *us s->user = user; } -/* TODO: initialize update callback in _init or begin... */ -R_API int r_search_update(RSearch *s, ut64 *from, const ut8 *buf, long len) { +// backward search: from points to the right endpoint +// forward search: from points to the left endpoint +R_API int r_search_update(RSearch *s, ut64 from, const ut8 *buf, long len) { int ret = -1; if (s->update) { if (s->maxhits && s->nhits >= s->maxhits) { return 0; } - ret = s->update (s, *from, buf, len); + ret = s->update (s, from, buf, len); if (s->mode == R_SEARCH_AES) { ret = R_MIN (R_SEARCH_AES_BOX_SIZE, len); } @@ -384,7 +400,7 @@ R_API int r_search_update(RSearch *s, ut64 *from, const ut8 *buf, long len) { } R_API int r_search_update_i(RSearch *s, ut64 from, const ut8 *buf, long len) { - return r_search_update (s, &from, buf, len); + return r_search_update (s, from, buf, len); } static int listcb(RSearchKeyword *k, void *user, ut64 addr) { @@ -401,7 +417,7 @@ static int listcb(RSearchKeyword *k, void *user, ut64 addr) { R_API RList *r_search_find(RSearch *s, ut64 addr, const ut8 *buf, int len) { RList *ret = r_list_new (); r_search_set_callback (s, listcb, ret); - r_search_update (s, &addr, buf, len); + r_search_update (s, addr, buf, len); return ret; } @@ -415,21 +431,37 @@ R_API int r_search_kw_add(RSearch *s, RSearchKeyword *kw) { return true; } -R_API void r_search_kw_reset(RSearch *s) { - r_list_free (s->kws); - s->kws = r_list_new (); +// Reverse bin_keyword & bin_binmask for backward search +R_API void r_search_string_prepare_backward(RSearch *s) { + RListIter *iter; + RSearchKeyword *kw; + // Precondition: !kw->binmask_length || kw->keyword_length % kw->binmask_length == 0 + r_list_foreach (s->kws, iter, kw) { + ut8 *i = kw->bin_keyword, *j = kw->bin_keyword + kw->keyword_length; + while (i < j) { + ut8 t = *i; + *i++ = *--j; + *j = t; + } + i = kw->bin_binmask; + j = kw->bin_binmask + kw->binmask_length; + while (i < j) { + ut8 t = *i; + *i++ = *--j; + *j = t; + } + } } R_API void r_search_reset(RSearch *s, int mode) { - R_FREE (s->data); - r_list_purge (s->hits); s->nhits = 0; - s->hits = r_list_newf ((RListFree)free); - if (!s->hits) { - return; - } - r_search_kw_reset (s); if (!r_search_set_mode (s, mode)) { eprintf ("Cannot init search for mode %d\n", mode); } } + +R_API void r_search_kw_reset(RSearch *s) { + r_list_purge (s->kws); + r_list_purge (s->hits); + R_FREE (s->data); +}