> Please avoid defining macros for such control blocks, especially when
> involve implicit local variables and can cause returns, it's always
> harder to follow and when checking for unrelated bugs, they tend to
> be disturbing. I know we already do it with CHECK_HTTP_MESSAGE_FIRST(),
> but it's used a lot more, something like 25 times or so. And even then
> it's annoying when you have to single-step through it.
>
> Another point is that nobody will ever see this alert, so in practice better
> not even send it and just ensure that the function fails so that the rules
> processing is aborted and an error is returned. I guess -1 already grants
> this given that you added the control in your patch. So that could simply
> result in adding this at the four places where you used CHECK_ACT_REPLACE :
>
>       if (trash.len < 0)
>             return -1;
> Another point concerning the code's efficiency, for the source I believe
> you should stick to the *str test instead of str < str_end for 3 reasons :
>
>   - everywhere it's tested, the following instruction is a fetch of *str,
>     so the same register will be reused ;
>
>   - on machines with low number of registers (eg: x86), it will avoid
>     moving variables back and forth to the stack.
>
>   - it avoids having to run over the whole input string twice (once for
>     strlen() and a second time for the actual work).
>

Willy:

I am attaching a patch that incorporates your revisions.

-- 
Sasha Pachev

Fast Running Blog.
http://fastrunningblog.com
Run. Blog. Improve. Repeat.
diff --git a/include/common/regex.h b/include/common/regex.h
index 9789ec3..63689af 100644
--- a/include/common/regex.h
+++ b/include/common/regex.h
@@ -79,7 +79,7 @@ extern regmatch_t pmatch[MAX_MATCH];
  * The function return 1 is succes case, else return 0 and err is filled.
  */
 int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err);
-int exp_replace(char *dst, char *src, const char *str,	const regmatch_t *matches);
+int exp_replace(char *dst, uint dst_size, char *src, const char *str, const regmatch_t *matches);
 const char *check_replace_string(const char *str);
 const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
 			int action, const char *replace, void *cond);
diff --git a/src/proto_http.c b/src/proto_http.c
index bd6d024..88e27e2 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -6817,7 +6817,11 @@ int apply_filter_to_req_headers(struct session *s, struct channel *req, struct h
 				break;
 
 			case ACT_REPLACE:
-				trash.len = exp_replace(trash.str, cur_ptr, exp->replace, pmatch);
+				trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
+
+				if (trash.len < 0)
+					return -1;
+
 				delta = buffer_replace2(req->buf, cur_ptr, cur_end, trash.str, trash.len);
 				/* FIXME: if the user adds a newline in the replacement, the
 				 * index will not be recalculated for now, and the new line
@@ -6927,7 +6931,11 @@ int apply_filter_to_req_line(struct session *s, struct channel *req, struct hdr_
 
 		case ACT_REPLACE:
 			*cur_end = term; /* restore the string terminator */
-			trash.len = exp_replace(trash.str, cur_ptr, exp->replace, pmatch);
+			trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
+			
+			if (trash.len < 0)
+				return -1;
+
 			delta = buffer_replace2(req->buf, cur_ptr, cur_end, trash.str, trash.len);
 			/* FIXME: if the user adds a newline in the replacement, the
 			 * index will not be recalculated for now, and the new line
@@ -7676,7 +7684,11 @@ int apply_filter_to_resp_headers(struct session *s, struct channel *rtr, struct
 				break;
 
 			case ACT_REPLACE:
-				trash.len = exp_replace(trash.str, cur_ptr, exp->replace, pmatch);
+				trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
+				
+				if (trash.len < 0)
+					return -1;
+
 				delta = buffer_replace2(rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
 				/* FIXME: if the user adds a newline in the replacement, the
 				 * index will not be recalculated for now, and the new line
@@ -7766,7 +7778,11 @@ int apply_filter_to_sts_line(struct session *s, struct channel *rtr, struct hdr_
 
 		case ACT_REPLACE:
 			*cur_end = term; /* restore the string terminator */
-			trash.len = exp_replace(trash.str, cur_ptr, exp->replace, pmatch);
+			trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
+			
+			if (trash.len < 0)
+				return -1;
+
 			delta = buffer_replace2(rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
 			/* FIXME: if the user adds a newline in the replacement, the
 			 * index will not be recalculated for now, and the new line
@@ -7847,7 +7863,8 @@ int apply_filters_to_response(struct session *s, struct channel *rtr, struct pro
 			/* The filter did not match the response, it can be
 			 * iterated through all headers.
 			 */
-			apply_filter_to_resp_headers(s, rtr, exp);
+			if (unlikely(apply_filter_to_resp_headers(s, rtr, exp) < 0))
+				return -1;
 		}
 	}
 	return 0;
diff --git a/src/regex.c b/src/regex.c
index 7a76940..58ddd30 100644
--- a/src/regex.c
+++ b/src/regex.c
@@ -22,14 +22,18 @@
 /* regex trash buffer used by various regex tests */
 regmatch_t pmatch[MAX_MATCH];  /* rm_so, rm_eo for regular expressions */
 
-
-int exp_replace(char *dst, char *src, const char *str, const regmatch_t *matches)
+int exp_replace(char *dst, uint dst_size, char *src, const char *str, const regmatch_t *matches)
 {
 	char *old_dst = dst;
-
+	char* dst_end = dst + dst_size;
+	
 	while (*str) {
 		if (*str == '\\') {
 			str++;
+			
+			if (!*str)
+				return -1;
+
 			if (isdigit((unsigned char)*str)) {
 				int len, num;
 
@@ -38,6 +42,10 @@ int exp_replace(char *dst, char *src, const char *str, const regmatch_t *matches
 
 				if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
 					len = matches[num].rm_eo - matches[num].rm_so;
+					
+					if (dst + len >= dst_end)
+						return -1;
+
 					memcpy(dst, src + matches[num].rm_so, len);
 					dst += len;
 				}
@@ -46,19 +54,40 @@ int exp_replace(char *dst, char *src, const char *str, const regmatch_t *matches
 				unsigned char hex1, hex2;
 				str++;
 
+				if (!*str)
+					return -1;
+
 				hex1 = toupper(*str++) - '0';
+				
+				if (!*str)
+					return -1;
+
 				hex2 = toupper(*str++) - '0';
 
 				if (hex1 > 9) hex1 -= 'A' - '9' - 1;
 				if (hex2 > 9) hex2 -= 'A' - '9' - 1;
+				
+				if (dst >= dst_end)
+					return -1;
+
 				*dst++ = (hex1<<4) + hex2;
 			} else {
+				if (dst >= dst_end)
+					return -1;
+
 				*dst++ = *str++;
 			}
 		} else {
+			if (dst >= dst_end)
+				return -1;
+
 			*dst++ = *str++;
 		}
 	}
+	
+	if (dst >= dst_end)
+		return -1;
+
 	*dst = '\0';
 	return dst - old_dst;
 }

Reply via email to