Back to Debian mailing lists. Here is a patch to the wheezy version that appears to work for me. Based on the upstream patches - the relevant parts seem to apply without any major dramas - although some bits required manual processing.
This is available for testing. At: https://people.debian.org/~bam/debian/pool/main/l/lynx-cur/ diff -Nru lynx-cur-2.8.8dev.12/debian/changelog lynx-cur-2.8.8dev.12/debian/changelog --- lynx-cur-2.8.8dev.12/debian/changelog 2016-11-16 18:14:13.000000000 +1100 +++ lynx-cur-2.8.8dev.12/debian/changelog 2016-11-16 17:47:21.000000000 +1100 @@ -1,3 +1,10 @@ +lynx-cur (2.8.8dev.12-2+deb7u1) wheezy-security; urgency=high + + * Non-maintainer upload by the LTS Team. + * Fix CVE-2016-9179: invalid URL parsing with '?'. + + -- Brian May <[email protected]> Wed, 16 Nov 2016 17:45:35 +1100 + lynx-cur (2.8.8dev.12-2) unstable; urgency=low * Applied use-dpkg-buildflags.patch which added hardening flags for diff -Nru lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-1.patch lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-1.patch --- lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-1.patch 1970-01-01 10:00:00.000000000 +1000 +++ lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-1.patch 2016-11-15 18:03:57.000000000 +1100 @@ -0,0 +1,163 @@ +--- a/WWW/Library/Implementation/HTTP.c ++++ b/WWW/Library/Implementation/HTTP.c +@@ -415,27 +415,150 @@ + #endif /* _WINDOWS */ + + /* ++ * RFC-1738 says we can have user/password using these ASCII characters ++ * safe = "$" | "-" | "_" | "." | "+" ++ * extra = "!" | "*" | "'" | "(" | ")" | "," ++ * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | ++ * "a" | "b" | "c" | "d" | "e" | "f" ++ * escape = "%" hex hex ++ * unreserved = alpha | digit | safe | extra ++ * uchar = unreserved | escape ++ * user = *[ uchar | ";" | "?" | "&" | "=" ] ++ * password = *[ uchar | ";" | "?" | "&" | "=" ] ++ * and we cannot have a password without user, i.e., no leading ":" ++ * and ":", "@", "/" must be encoded, i.e., will not appear as such. ++ * ++ * However, in a URL ++ * //<user>:<password>@<host>:<port>/<url-path> ++ * valid characters in the host are different, not allowing most of those ++ * punctuation characters. ++ * ++ * RFC-3986 amends this, using ++ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) ++ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" ++ * reserved = gen-delims / sub-delims ++ * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" ++ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" ++ * / "*" / "+" / "," / ";" / "=" ++ * and ++ * host = IP-literal / IPv4address / reg-name ++ * reg-name = *( unreserved / pct-encoded / sub-delims ) ++ */ ++#define RFC_3986_UNRESERVED(c) (isalnum(UCH(c)) || strchr("-._~", UCH(c)) != 0) ++#define RFC_3986_GEN_DELIMS(c) ((c) != 0 && strchr(":/?#[]@", UCH(c)) != 0) ++#define RFC_3986_SUB_DELIMS(c) ((c) != 0 && strchr("!$&'()*+,;=", UCH(c)) != 0) ++ ++static char *skip_user_passwd(char *host) ++{ ++ char *result = 0; ++ char *s = host; ++ int pass = 0; ++ int ch; ++ int last = -1; ++ ++ while ((ch = UCH(*s)) != '\0') { ++ if (ch == '\0') { ++ break; ++ } else if (ch == ':') { ++ if (pass++) ++ break; ++ } else if (ch == '@') { ++ if (s != host && last != ':') ++ result = s; ++ break; ++ } else if (RFC_3986_GEN_DELIMS(ch)) { ++ if (!RFC_3986_GEN_DELIMS(s[1])) ++ break; ++ } else if (ch == '%') { ++ if (!(isxdigit(UCH(s[1])) && isxdigit(UCH(s[2])))) ++ break; ++ } else if (!(RFC_3986_UNRESERVED(ch) || ++ RFC_3986_SUB_DELIMS(ch))) { ++ break; ++ } ++ ++s; ++ last = ch; ++ } ++ return result; ++} ++ ++static char *fake_hostname(char *auth) ++{ ++ char *result = NULL; ++ char *colon = NULL; ++ ++ StrAllocCopy(result, auth); ++ if ((colon = strchr(result, ':')) != 0) ++ *colon = '\0'; ++ if (strchr(result, '.') == 0) ++ FREE(result); ++ return result; ++} ++ ++/* + * Strip any username from the given string so we retain only the host. + */ + static void strip_userid(char *host) + { + char *p1 = host; +- char *p2 = strchr(host, '@'); +- char *fake; ++ char *p2 = skip_user_passwd(host); + + if (p2 != 0) { ++ char *msg = NULL; ++ char *auth = NULL; ++ char *save = NULL; ++ char *fake = NULL; ++ char *p3 = p2; ++ int gen_delims = 0; ++ int sub_delims = 0; ++ int my_delimit = UCH(*p2); ++ int do_trimming = (my_delimit == '@'); ++ + *p2++ = '\0'; +- if ((fake = HTParse(host, "", PARSE_HOST)) != NULL) { +- char *msg = NULL; ++ StrAllocCopy(auth, host); + +- CTRACE((tfp, "parsed:%s\n", fake)); +- HTSprintf0(&msg, gettext("Address contains a username: %s"), host); +- HTAlert(msg); +- FREE(msg); ++ /* ++ * Trailing "gen-delims" demonstrates that there is no user/password. ++ */ ++ while ((p3 != host) && RFC_3986_GEN_DELIMS(p3[-1])) { ++ ++gen_delims; ++ *(--p3) = '\0'; + } +- while ((*p1++ = *p2++) != '\0') { +- ; ++ /* ++ * While legal, punctuation-only user/password is questionable. ++ */ ++ while ((p3 != host) && RFC_3986_SUB_DELIMS(p3[-1])) { ++ ++sub_delims; ++ *(--p3) = '\0'; ++ } ++ CTRACE((tfp, "trimmed:%s\n", host)); ++ StrAllocCopy(save, host); ++ ++ if (gen_delims || strcmp(save, auth)) { ++ HTSprintf0(&msg, ++ gettext("User/password may appear to be a hostname: '%s' (e.g, '%s')"), ++ auth, save); ++ do_trimming = !gen_delims; ++ } else if (*host == '\0' && sub_delims) { ++ HTSprintf0(&msg, ++ gettext("User/password contains only punctuation: %s"), ++ auth); ++ } else if ((fake = fake_hostname(host)) != NULL) { ++ HTSprintf0(&msg, ++ gettext("User/password may be confused with hostname: '%s' (e.g, '%s')"), ++ auth, fake); ++ } ++ if (msg != 0) ++ HTAlert(msg); ++ if (do_trimming) { ++ while ((*p1++ = *p2++) != '\0') { ++ ; ++ } + } ++ FREE(fake); ++ FREE(save); ++ FREE(auth); ++ FREE(msg); + } + } + diff -Nru lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-2.patch lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-2.patch --- lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-2.patch 1970-01-01 10:00:00.000000000 +1000 +++ lynx-cur-2.8.8dev.12/debian/patches/CVE-2016-9179-2.patch 2016-11-16 17:40:59.000000000 +1100 @@ -0,0 +1,77 @@ +--- a/WWW/Library/Implementation/HTTCP.c ++++ b/WWW/Library/Implementation/HTTCP.c +@@ -1581,7 +1581,6 @@ + int status = 0; + char *line = NULL; + char *p1 = NULL; +- char *at_sign = NULL; + char *host = NULL; + + #ifdef INET6 +@@ -1603,14 +1602,8 @@ + * Get node name and optional port number. + */ + p1 = HTParse(url, "", PARSE_HOST); +- if ((at_sign = strchr(p1, '@')) != NULL) { +- /* +- * If there's an @ then use the stuff after it as a hostname. +- */ +- StrAllocCopy(host, (at_sign + 1)); +- } else { +- StrAllocCopy(host, p1); +- } ++ StrAllocCopy(host, p1); ++ strip_userid(host, FALSE); + FREE(p1); + + HTSprintf0(&line, "%s%s", WWW_FIND_MESSAGE, host); +--- a/WWW/Library/Implementation/HTTP.c ++++ b/WWW/Library/Implementation/HTTP.c +@@ -498,7 +498,7 @@ + /* + * Strip any username from the given string so we retain only the host. + */ +-static void strip_userid(char *host) ++void strip_userid(char *host, int parse_only) + { + char *p1 = host; + char *p2 = skip_user_passwd(host); +@@ -548,7 +548,7 @@ + gettext("User/password may be confused with hostname: '%s' (e.g, '%s')"), + auth, fake); + } +- if (msg != 0) ++ if (msg != 0 && !parse_only) + HTAlert(msg); + if (do_trimming) { + while ((*p1++ = *p2++) != '\0') { +@@ -1183,7 +1183,7 @@ + char *host = NULL; + + if ((host = HTParse(anAnchor->address, "", PARSE_HOST)) != NULL) { +- strip_userid(host); ++ strip_userid(host, TRUE); + HTBprintf(&command, "Host: %s%c%c", host, CR, LF); + FREE(host); + } +--- a/WWW/Library/Implementation/HTUtils.h ++++ b/WWW/Library/Implementation/HTUtils.h +@@ -778,6 +778,8 @@ + + extern FILE *TraceFP(void); + ++ extern void strip_userid(char *host, int warn); ++ + #ifdef USE_SSL + extern SSL *HTGetSSLHandle(void); + extern void HTSSLInitPRNG(void); +--- a/src/LYUtils.c ++++ b/src/LYUtils.c +@@ -4616,6 +4616,7 @@ + * Do a DNS test on the potential host field as presently trimmed. - FM + */ + StrAllocCopy(host, Str); ++ strip_userid(host, FALSE); + HTUnEscape(host); + if (LYCursesON) { + StrAllocCopy(MsgStr, WWW_FIND_MESSAGE); diff -Nru lynx-cur-2.8.8dev.12/debian/patches/series lynx-cur-2.8.8dev.12/debian/patches/series --- lynx-cur-2.8.8dev.12/debian/patches/series 2016-11-16 18:14:13.000000000 +1100 +++ lynx-cur-2.8.8dev.12/debian/patches/series 2016-11-16 17:41:36.000000000 +1100 @@ -1,3 +1,5 @@ lynxcfg.patch aboutlynx.patch use-dpkg-buildflags.patch +CVE-2016-9179-1.patch +CVE-2016-9179-2.patch diff -Nru lynx-cur-2.8.8dev.12/debian/source/format lynx-cur-2.8.8dev.12/debian/source/format --- lynx-cur-2.8.8dev.12/debian/source/format 1970-01-01 10:00:00.000000000 +1000 +++ lynx-cur-2.8.8dev.12/debian/source/format 2016-11-16 17:53:26.000000000 +1100 @@ -0,0 +1 @@ +3.0 (quilt) -- Brian May <[email protected]>
