Fix RFC 2616 section 2.2 quote-string handling.
* Restrict the parser to the known length of the value string to prevent
buffer over-reads from specially crafted inputs.
* Drop quoted-string values containing CTL octets.
const char *target = NULL; /* ;foo */
const char *temp = NULL; /* temp buffer */
int type;
- int ilen;
+ int ilen, vlen;
int initiallen;
HttpHdrScTarget *sct;
assert(sc && str);
while (strListGetItem(str, ',', &item, &ilen, &pos)) {
initiallen = ilen;
+ vlen = 0;
/* decrease ilen to still match the token for '=' statements */
- if ((p = strchr(item, '=')) && (p - item < ilen))
- ilen = p++ - item;
+ if ((p = strchr(item, '=')) && (p - item < ilen)) {
+ vlen = ilen - (++p - item);
+ ilen = p - item;
+ }
/* decrease ilen to still match the token for ';' qualified non '=' statments */
else if ((p = strchr(item, ';')) && (p - item < ilen))
case SC_CONTENT:
- if (!p || !httpHeaderParseQuotedString(p, &sct->content)) {
+ if (!p || !httpHeaderParseQuotedString(p, vlen, &sct->content)) {
debugs(90, 2, "sc: invalid content= quoted string near '" << item << "'");
sct->content.clean();
EBIT_CLR(sct->mask, type);
};
-extern int httpHeaderParseQuotedString (const char *start, String *val);
+extern int httpHeaderParseQuotedString(const char *start, const int len, String *val);
SQUIDCEXTERN int httpHeaderHasByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator);
SQUIDCEXTERN void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
SQUIDCEXTERN void httpHeaderCalcMask(HttpHeaderMask * mask, http_hdr_type http_hdr_type_enums[], size_t count);
/**
* Parses a quoted-string field (RFC 2616 section 2.2), complains if
* something went wrong, returns non-zero on success.
+ * Un-escapes quoted-pair characters found within the string.
* start should point at the first double-quote.
- * RC TODO: This is too looose. We should honour the BNF and exclude CTL's
*/
int
-httpHeaderParseQuotedString(const char *start, String *val)
+httpHeaderParseQuotedString(const char *start, const int len, String *val)
{
const char *end, *pos;
val->clean();
}
pos = start + 1;
- while (*pos != '"') {
+ while (*pos != '"' && len > (pos-start)) {
bool quoted = (*pos == '\\');
if (quoted)
pos++;
- if (!*pos) {
+ if (!*pos || (pos-start) > len) {
debugs(66, 2, "failed to parse a quoted-string header field near '" << start << "'");
val->clean();
return 0;
}
- end = pos + strcspn(pos + quoted, "\"\\") + quoted;
+ end = pos;
+ while(end <= (start+len) && *end != '\\' && *end != '\"' && *end > 0x1F && *end != 0x7F)
+ end++;
+ if (*end <= 0x1F || *end == 0x7F) {
+ debugs(66, 2, "failed to parse a quoted-string header field with CTL octet " << (start-pos)
+ << " bytes into '" << start << "'");
+ val->clean();
+ return 0;
+ }
val->append(pos, end-pos);
pos = end;
}
String value;
if (vlen > 0) {
if (*p == '"') {
- if (!httpHeaderParseQuotedString(p, &value)) {
+ if (!httpHeaderParseQuotedString(p, vlen, &value)) {
debugs(29, 9, "authDigestDecodeAuth: Failed to parse attribute '" << item << "' in '" << temp << "'");
continue;
}