Commit c82e3aba authored by Dridi Boukelmoune's avatar Dridi Boukelmoune

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.
parent 611a48e3
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
......@@ -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 */
......@@ -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);
}
......@@ -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.
......@@ -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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment