From 0c1d0e93d1f82d9b7bd4d5098a7d8db84587b728 Mon Sep 17 00:00:00 2001 From: Nardi Ivan Date: Mon, 13 Mar 2023 15:48:03 +0100 Subject: [PATCH] Update libinjection code Update libinjection code to the current master https://github.com/libinjection/libinjection/commit/7e4b74e824dc3f0623ba4894df2a0d817351ec39 The goal is to finally fix #1820 See: https://github.com/libinjection/libinjection/issues/33 Close #1820 --- .../third_party/include/libinjection_sqli.h | 22 +++++------ src/lib/third_party/src/libinjection_html5.c | 20 +++++++++- src/lib/third_party/src/libinjection_sqli.c | 37 ++++++++++++------- src/lib/third_party/src/libinjection_xss.c | 23 ++++++++---- 4 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/lib/third_party/include/libinjection_sqli.h b/src/lib/third_party/include/libinjection_sqli.h index b9746555a7f..a6c96ff5154 100644 --- a/src/lib/third_party/include/libinjection_sqli.h +++ b/src/lib/third_party/include/libinjection_sqli.h @@ -175,7 +175,7 @@ struct libinjection_sqli_state { typedef struct libinjection_sqli_state sfilter; struct libinjection_sqli_token* libinjection_sqli_get_token( - struct libinjection_sqli_state* sqlistate, int i); + struct libinjection_sqli_state* sql_state, int i); /* * Version info. @@ -193,8 +193,8 @@ const char* libinjection_version(void); /** * */ -void libinjection_sqli_init(struct libinjection_sqli_state* sql_state, - const char* s, size_t slen, +void libinjection_sqli_init(struct libinjection_sqli_state *sf, + const char* s, size_t len, int flags); /** @@ -210,7 +210,7 @@ int libinjection_is_sqli(struct libinjection_sqli_state* sql_state); /* FOR HACKERS ONLY * provides deep hooks into the decision making process */ -void libinjection_sqli_callback(struct libinjection_sqli_state* sql_state, +void libinjection_sqli_callback(struct libinjection_sqli_state *sf, ptr_lookup_fn fn, void* userdata); @@ -218,7 +218,7 @@ void libinjection_sqli_callback(struct libinjection_sqli_state* sql_state, /* * Resets state, but keeps initial string and callbacks */ -void libinjection_sqli_reset(struct libinjection_sqli_state* sql_state, +void libinjection_sqli_reset(struct libinjection_sqli_state *sf, int flags); /** @@ -236,17 +236,17 @@ void libinjection_sqli_reset(struct libinjection_sqli_state* sql_state, * do not free! * */ -const char* libinjection_sqli_fingerprint(struct libinjection_sqli_state* sql_state, +const char* libinjection_sqli_fingerprint(struct libinjection_sqli_state *sql_state, int flags); /** * The default "word" to token-type or fingerprint function. This * uses a ASCII case-insensitive binary tree. */ -char libinjection_sqli_lookup_word(struct libinjection_sqli_state* sql_state, +char libinjection_sqli_lookup_word(struct libinjection_sqli_state *sql_state, int lookup_type, - const char* s, - size_t slen); + const char* str, + size_t len); /* Streaming tokenization interface. * @@ -255,13 +255,13 @@ char libinjection_sqli_lookup_word(struct libinjection_sqli_state* sql_state, * \returns 1, has a token, keep going, or 0 no tokens * */ -int libinjection_sqli_tokenize(struct libinjection_sqli_state * sql_state); +int libinjection_sqli_tokenize(struct libinjection_sqli_state *sf); /** * parses and folds input, up to 5 tokens * */ -int libinjection_sqli_fold(struct libinjection_sqli_state * sql_state); +int libinjection_sqli_fold(struct libinjection_sqli_state *sf); /** The built-in default function to match fingerprints * and do false negative/positive analysis. This calls the following diff --git a/src/lib/third_party/src/libinjection_html5.c b/src/lib/third_party/src/libinjection_html5.c index a380ca0ad68..640f6265699 100644 --- a/src/lib/third_party/src/libinjection_html5.c +++ b/src/lib/third_party/src/libinjection_html5.c @@ -29,7 +29,7 @@ /* prototypes */ static int h5_skip_white(h5_state_t* hs); -static int h5_is_white(char c); +static int h5_is_white(char ch); static int h5_state_eof(h5_state_t* hs); static int h5_state_data(h5_state_t* hs); static int h5_state_tag_open(h5_state_t* hs); @@ -323,6 +323,10 @@ static int h5_state_before_attribute_name(h5_state_t* hs) int ch; TRACE(); + + /* for manual tail call optimization, see comment below */ + tail_call:; + ch = h5_skip_white(hs); switch (ch) { case CHAR_EOF: { @@ -330,6 +334,18 @@ static int h5_state_before_attribute_name(h5_state_t* hs) } case CHAR_SLASH: { hs->pos += 1; + /* Logically, We want to call h5_state_self_closing_start_tag(hs) here. + + As this function may call us back and the compiler + might not implement automatic tail call optimization, + this might result in a deep recursion. + + We detect this case here and start over with the current state. + */ + + if (hs->pos < hs->len && hs->s[hs->pos] != CHAR_GT) { + goto tail_call; + } return h5_state_self_closing_start_tag(hs); } case CHAR_GT: { @@ -574,6 +590,8 @@ static int h5_state_after_attribute_value_quoted_state(h5_state_t* hs) /** * 12.2.4.43 + * + * WARNING: This function is partially inlined into h5_state_before_attribute_name() */ static int h5_state_self_closing_start_tag(h5_state_t* hs) { diff --git a/src/lib/third_party/src/libinjection_sqli.c b/src/lib/third_party/src/libinjection_sqli.c index c411677347f..058d08deb3a 100644 --- a/src/lib/third_party/src/libinjection_sqli.c +++ b/src/lib/third_party/src/libinjection_sqli.c @@ -18,7 +18,7 @@ #include "libinjection_sqli.h" #include "libinjection_sqli_data.h" -#define LIBINJECTION_VERSION "3.9.2" +#define LIBINJECTION_VERSION "3.9.2.60-8e70-dirty" #define LIBINJECTION_SQLI_TOKEN_SIZE sizeof(((stoken_t*)(0))->val) #define LIBINJECTION_SQLI_MAX_TOKENS 5 @@ -503,12 +503,7 @@ static size_t parse_slash(struct libinjection_sqli_state * sf) * skip over initial '/x' */ ptr = memchr2(cur + 2, slen - (pos + 2), '*', '/'); - - /* - * (ptr == NULL) causes false positive in cppcheck 1.61 - * casting to type seems to fix it - */ - if (ptr == (const char*) NULL) { + if (ptr == NULL) { /* till end of line */ clen = slen - pos; } else { @@ -525,7 +520,10 @@ static size_t parse_slash(struct libinjection_sqli_state * sf) * are an automatic black ban! */ - if(ptr && (memchr2(cur + 2, (size_t)(ptr - (cur + 1)), '/', '*') != NULL)) { + if ( + ptr != NULL && + memchr2(cur + 2, (size_t)(ptr - (cur + 1)), '/', '*') != NULL + ) { ctype = TYPE_EVIL; } else if (is_mysql_comment(cs, slen, pos)) { ctype = TYPE_EVIL; @@ -599,6 +597,16 @@ static size_t parse_operator2(struct libinjection_sqli_state * sf) } } +#ifndef __clang_analyzer__ +/* Code not to be analyzed by clang. + * + * Why we do this? Because there is a false positive here: + * libinjection_sqli.c:608:13: warning: Out of bound memory access (access exceeds upper limit of memory block) [alpha.security.ArrayBoundV2] + * if (*ptr != '\\') { + * ^~~~ + * Specifically, this function deals with non-null terminated char arrays. This can be added + * as prerequisite, and is not written clearly. But the math in the for below holds. + */ /* * Ok! " \" " one backslash = escaped! * " \\" " two backslash = not escaped! @@ -616,6 +624,7 @@ static int is_backslash_escaped(const char* end, const char* start) return (end - ptr) & 1; } +#endif static size_t is_double_delim_escaped(const char* cur, const char* end) { @@ -1066,9 +1075,9 @@ static size_t parse_money(struct libinjection_sqli_state *sf) } /* we have $foobar$ ... find it again */ - strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); + strend = my_memmem(cs+pos+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); - if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) { + if (strend == NULL) { /* fell off edge */ st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2); sf->current->str_open = '$'; @@ -1197,12 +1206,12 @@ static size_t parse_number(struct libinjection_sqli_state * sf) * without having to regenerated the SWIG (or other binding) in minor * releases. */ -const char* libinjection_version() +const char* libinjection_version(void) { return LIBINJECTION_VERSION; } -int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf) +int libinjection_sqli_tokenize(struct libinjection_sqli_state *sf) { pt2Function fnptr; size_t *pos = &sf->pos; @@ -2309,12 +2318,12 @@ int libinjection_is_sqli(struct libinjection_sqli_state * sql_state) return FALSE; } -int libinjection_sqli(const char* input, size_t slen, char fingerprint[]) +int libinjection_sqli(const char* s, size_t slen, char fingerprint[]) { int issqli; struct libinjection_sqli_state state; - libinjection_sqli_init(&state, input, slen, 0); + libinjection_sqli_init(&state, s, slen, 0); issqli = libinjection_is_sqli(&state); if (issqli) { strcpy(fingerprint, state.fingerprint); diff --git a/src/lib/third_party/src/libinjection_xss.c b/src/lib/third_party/src/libinjection_xss.c index f0df4d84acf..3ef827df95f 100644 --- a/src/lib/third_party/src/libinjection_xss.c +++ b/src/lib/third_party/src/libinjection_xss.c @@ -20,7 +20,7 @@ static int is_black_tag(const char* s, size_t len); static int is_black_url(const char* s, size_t len); static int cstrcasecmp_with_null(const char *a, const char *b, size_t n); static int html_decode_char_at(const char* src, size_t len, size_t* consumed); -static int htmlencode_startswith(const char* prefix, const char *src, size_t n); +static int htmlencode_startswith(const char *a/* prefix */, const char *b /* src */, size_t n); typedef struct stringtype { @@ -509,22 +509,31 @@ int libinjection_is_xss(const char* s, size_t len, int flags) /* * wrapper + * + * + * const char* s: is expected to be a null terminated string. + * size_t len: should represent the length of the string + * without the null terminator - strlen(s). + * + * Further info: + * - https://github.com/client9/libinjection/issues/150 + * */ -int libinjection_xss(const char* s, size_t len) +int libinjection_xss(const char* s, size_t slen) { - if (libinjection_is_xss(s, len, DATA_STATE)) { + if (libinjection_is_xss(s, slen, DATA_STATE)) { return 1; } - if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) { + if (libinjection_is_xss(s, slen, VALUE_NO_QUOTE)) { return 1; } - if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) { + if (libinjection_is_xss(s, slen, VALUE_SINGLE_QUOTE)) { return 1; } - if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) { + if (libinjection_is_xss(s, slen, VALUE_DOUBLE_QUOTE)) { return 1; } - if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) { + if (libinjection_is_xss(s, slen, VALUE_BACK_QUOTE)) { return 1; }