Mailing List Archive

[master] c82e3abab New VRE_quote() function
commit c82e3ababca5d6533f07ec9dd4c064cfbee82f75
Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
Date: Fri Jun 5 17:09:22 2020 +0200

New VRE_quote() function

This is a tool for VMOD authors for the use case of building a regular
expression partially from arbitrary input, where the input is intended
for an exact match.

For example, one could implement a dispatch feature depending on the
request's host header, building something like:

"\.?\Q" + req.http.host + "\E$"

A malicious client could however hijack the regular expression with a
\E sequence in the host header. To get safely to this result you can
do this instead in pseudo-code before compiling the regex:

VSB_cat(vsb, "\\.?");
VRE_quote(vsb, req.http.host);
VSB_putc(vsb, '$');

The input is enclosed with PCRE's \Q and \E escape sequences, ensuring
that \E sequences in the input string don't allow Little Bobby Tables'
cousin to mess with your regular expressions.

diff --git a/bin/varnishtest/tests/v00065.vtc b/bin/varnishtest/tests/v00065.vtc
new file mode 100644
index 000000000..b941c19b9
--- /dev/null
+++ b/bin/varnishtest/tests/v00065.vtc
@@ -0,0 +1,33 @@
+varnishtest "VRT_re_quote() coverage"
+
+varnish v1 -vcl {
+ import debug;
+
+ backend be none;
+
+ sub vcl_recv {
+ return (synth(200));
+ }
+
+ sub vcl_synth {
+ set resp.http.sanity = regsub("\Q", "\Q\Q\E", "sane");
+ set resp.http.q0 = debug.re_quote("");
+ set resp.http.q1 = debug.re_quote("hello");
+ set resp.http.q2 = debug.re_quote("hello\E");
+ set resp.http.q3 = debug.re_quote("hello\Eworld");
+ set resp.http.q4 = debug.re_quote("\E");
+ set resp.http.q5 = debug.re_quote("\Q");
+ }
+} -start
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.http.sanity == sane
+ expect resp.http.q0 == {}
+ expect resp.http.q1 == {\Qhello\E}
+ expect resp.http.q2 == {\Qhello\\EE}
+ expect resp.http.q3 == {\Qhello\\EE\Qworld\E}
+ expect resp.http.q4 == {\Q\\EE}
+ expect resp.http.q5 == {\Q\Q\E}
+} -run
diff --git a/include/vre.h b/include/vre.h
index b139c8a06..6dcf0e593 100644
--- a/include/vre.h
+++ b/include/vre.h
@@ -38,6 +38,7 @@
#define VRE_H_INCLUDED

struct vre;
+struct vsb;

struct vre_limits {
unsigned match;
@@ -59,5 +60,6 @@ int VRE_exec(const vre_t *code, const char *subject, int length,
int startoffset, int options, int *ovector, int ovecsize,
const volatile struct vre_limits *lim);
void VRE_free(vre_t **);
+void VRE_quote(struct vsb *, const char *);

#endif /* VRE_H_INCLUDED */
diff --git a/lib/libvarnish/vre.c b/lib/libvarnish/vre.c
index 7ef62da8d..4b9c6d7b1 100644
--- a/lib/libvarnish/vre.c
+++ b/lib/libvarnish/vre.c
@@ -36,6 +36,7 @@
#include "vdef.h"

#include "vas.h" // XXX Flexelint "not used" - but req'ed for assert()
+#include "vsb.h"
#include "miniobj.h"

#include "vre.h"
@@ -147,3 +148,17 @@ VRE_free(vre_t **vv)
pcre_free(v->re);
FREE_OBJ(v);
}
+
+void
+VRE_quote(struct vsb *vsb, const char *src)
+{
+ const char *b, *e;
+
+ CHECK_OBJ_NOTNULL(vsb, VSB_MAGIC);
+ if (src == NULL)
+ return;
+ for (b = src; (e = strstr(b, "\\E")) != NULL; b = e + 2)
+ VSB_printf(vsb, "\\Q%.*s\\\\EE", (int)(e - b), b);
+ if (*b != '\0')
+ VSB_printf(vsb, "\\Q%s\\E", b);
+}
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 89cc648e4..63c326cf4 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -300,3 +300,7 @@ fail any rollback before ok_rollback() is called
$Function VOID ok_rollback()

Allow rollbacks. Must be called before the end of the task.
+
+$Function STRING re_quote(STRING)
+
+Quote an input string to be usable for an exact match in a regular expression.
diff --git a/lib/libvmod_debug/vmod_debug.c b/lib/libvmod_debug/vmod_debug.c
index 01013b892..aa54dfeb8 100644
--- a/lib/libvmod_debug/vmod_debug.c
+++ b/lib/libvmod_debug/vmod_debug.c
@@ -39,6 +39,7 @@
#include "cache/cache_varnishd.h"
#include "cache/cache_filter.h"

+#include "vre.h"
#include "vsa.h"
#include "vtim.h"
#include "vcc_if.h"
@@ -1145,3 +1146,19 @@ xyzzy_ok_rollback(VRT_CTX)
p->priv = NULL;
p->free = NULL;
}
+
+VCL_STRING v_matchproto_(td_xyzzy_debug_re_quote)
+xyzzy_re_quote(VRT_CTX, VCL_STRING s)
+{
+ struct vsb vsb[1];
+ char *q;
+
+ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+ CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
+ WS_VSB_new(vsb, ctx->ws);
+ VRE_quote(vsb, s);
+ q = WS_VSB_finish(vsb, ctx->ws, NULL);
+ if (q == NULL)
+ WS_MarkOverflow(ctx->ws);
+ return (q);
+}
_______________________________________________
varnish-commit mailing list
varnish-commit@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-commit