Skip to content

Commit 0bf0636

Browse files
authored
Fix the reported security bug. (#159)
See GHSA-62q6-v997-f7v9 for more details on the security bug. Fix: - Use the JS_FunctionCall() API to call the FindProxyForURL() function instead of JS_EvaluateScript() API. - This also does away with the need to str_replace function. Making code simpler. - I've verified the fix with the test cases provided in the security bug.
1 parent e7c99e3 commit 0bf0636

5 files changed

Lines changed: 26 additions & 150 deletions

File tree

src/Makefile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,7 @@ jsapi_buildstamp: spidermonkey/js/src
8787
spidermonkey/libjs.a: spidermonkey/js/src
8888
cd spidermonkey && SMCFLAGS="$(SHFLAGS) $(SMCFLAGS)" $(MAKE) jslib
8989

90-
pac_utils_test: pac_utils_test.c pac_utils.h
91-
$(CC) $(MAINT_CFLAGS) $(CFLAGS) $(SHFLAGS) pac_utils_test.c -o pac_utils_test -lm -L. -I.
92-
93-
pacparser.o: pacparser.c pac_utils.h pacparser.h pac_utils_test jsapi_buildstamp
94-
./pac_utils_test
90+
pacparser.o: pacparser.c pac_utils.h pacparser.h jsapi_buildstamp
9591
$(CC) $(MAINT_CFLAGS) $(CFLAGS) $(SHFLAGS) -c pacparser.c -o pacparser.o
9692
touch pymod/pacparser_o_buildstamp
9793

src/pac_utils.h

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
2727
// USA
2828

29-
#include <string.h>
30-
#include <stdlib.h>
31-
3229
static const char *pacUtils =
3330
"function dnsDomainIs(host, domain) {\n"
3431
" return (host.length >= domain.length &&\n"
@@ -335,57 +332,3 @@ static const char *pacUtils =
335332
" return FindProxyForURL(url, host);\n"
336333
" }\n"
337334
"}\n";
338-
339-
340-
// You must free the result if result is non-NULL.
341-
char *str_replace(const char *orig, const char *rep, const char *with) {
342-
if (orig == NULL || rep == NULL || with == NULL) {
343-
return NULL;
344-
}
345-
346-
size_t len_orig = strnlen(orig, 1024);
347-
size_t len_rep = strnlen(rep, 1024);
348-
size_t len_with = strnlen(with, 1024);
349-
350-
if (len_orig == 0 || len_rep == 0) {
351-
char *result = malloc(len_orig + 1);
352-
strcpy(result, orig);
353-
return result;
354-
}
355-
356-
// Count replacements needed
357-
int count; // number of replacements
358-
char const *start = orig;
359-
// Cursor moves through the string, looking for rep.
360-
char const *cursor;
361-
for (count = 0;; ++count) {
362-
cursor = strstr(start, rep);
363-
if (cursor == NULL) {
364-
break;
365-
}
366-
start = cursor + len_rep;
367-
}
368-
369-
char *tmp;
370-
char *result;
371-
tmp = result = malloc(len_orig + (len_with - len_rep) * count + 1);
372-
373-
// first time through the loop, all the variable are set correctly
374-
// from here on,
375-
// tmp points to the end of the result string
376-
// ins points to the next occurrence of rep in orig
377-
// orig points to the remainder of orig after "end of rep"
378-
while (count--) {
379-
const char *ins = strstr(orig, rep);
380-
int len_front = (int)(ins - orig); // How far have we moved
381-
// Into the tmp, copy everything until we reach the rep.
382-
// and move tmp forward.
383-
tmp = strncpy(tmp, orig, len_front) + len_front;
384-
tmp = strcpy(tmp, with) + len_with;
385-
orig += len_front + len_rep; // move to next "end of rep"
386-
}
387-
388-
// Copy the remaining string.
389-
strcpy(tmp, orig);
390-
return result;
391-
}

src/pac_utils_test.c

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/pacparser.c

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ my_ip(JSContext *cx, JSObject *UNUSED(o), uintN UNUSED(u), jsval *argv, jsval *r
238238
// myIpAddressEx in JS context; not available in core JavaScript.
239239
// returns 127.0.0.1 if not able to determine local ip.
240240
static JSBool // JS_TRUE or JS_FALSE
241-
my_ip_ex(JSContext *cx, JSObject *UNUSED(o), uintN UNUSED(u), jsval *argv, jsval *rval)
241+
my_ip_ex(JSContext *cx, JSObject *UNUSED(o), uintN UNUSED(u), jsval *UNUSED(argv), jsval *rval)
242242
{
243243
char ipaddr[INET6_ADDRSTRLEN * MAX_IP_RESULTS + MAX_IP_RESULTS];
244244
char* out;
@@ -451,32 +451,14 @@ pacparser_find_proxy(const char *url, const char *host)
451451
return NULL;
452452
}
453453

454-
// URL-encode "'" as we use single quotes to stick the URL into a temporary script.
455-
char *sanitized_url = str_replace(url, "'", "%27");
456-
// Hostname shouldn't have single quotes in them
457-
if (strchr(host, '\'')) {
458-
print_error("%s %s\n", error_prefix,
459-
"Invalid hostname: hostname can't have single quotes.");
460-
free(sanitized_url);
461-
return NULL;
462-
}
463-
464-
script = (char*) malloc(32 + strlen(sanitized_url) + strlen(host));
465-
script[0] = '\0';
466-
strcat(script, "findProxyForURL('");
467-
strcat(script, sanitized_url);
468-
strcat(script, "', '");
469-
strcat(script, host);
470-
strcat(script, "')");
471-
if (_debug()) print_error("DEBUG: Executing JavaScript: %s\n", script);
472-
if (!JS_EvaluateScript(cx, global, script, strlen(script), NULL, 1, &rval)) {
454+
jsval args[2];
455+
args[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, url));
456+
args[1] = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, host));
457+
458+
if (!JS_CallFunctionName(cx, global, "findProxyForURL", 2, args, &rval)) {
473459
print_error("%s %s\n", error_prefix, "Problem in executing findProxyForURL.");
474-
free(sanitized_url);
475-
free(script);
476460
return NULL;
477461
}
478-
free(sanitized_url);
479-
free(script);
480462
return JS_GetStringBytes(JS_ValueToString(cx, rval));
481463
}
482464

tests/proxy.pac

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,36 @@
33
// Go via proxy for all other hosts.
44

55
function FindProxyForURL(url, host) {
6-
7-
if ((isPlainHostName(host) ||
8-
dnsDomainIs(host, ".manugarg.com")) &&
9-
!localHostOrDomainIs(host, "www.manugarg.com"))
10-
return "plainhost/.manugarg.com";
6+
if (
7+
(isPlainHostName(host) || dnsDomainIs(host, '.manugarg.com')) &&
8+
!localHostOrDomainIs(host, 'www.manugarg.com')
9+
)
10+
return 'plainhost/.manugarg.com';
1111

1212
// Test single quote handling in URL.
13-
if (/.*%27.*/.test(url)) {
14-
return "URLHasQuotes";
13+
if (/'/.test(url)) {
14+
return 'URLHasQuotes';
1515
}
1616

1717
// Return externaldomain if host matches .*\.externaldomain\.com
18-
if (/.*\.externaldomain\.com/.test(host))
19-
return "externaldomain";
18+
if (/.*\.externaldomain\.com/.test(host)) return 'externaldomain';
2019

2120
// Test if DNS resolving is working as intended
22-
if (dnsDomainIs(host, ".google.com") &&
23-
isResolvable(host))
24-
return "isResolvable";
21+
if (dnsDomainIs(host, '.google.com') && isResolvable(host))
22+
return 'isResolvable';
2523

2624
// Test if DNS resolving is working as intended
27-
if (dnsDomainIs(host, ".notresolvabledomainXXX.com") &&
28-
!isResolvable(host))
29-
return "isNotResolvable";
25+
if (dnsDomainIs(host, '.notresolvabledomainXXX.com') && !isResolvable(host))
26+
return 'isNotResolvable';
3027

31-
if (/^https:\/\/.*$/.test(url))
32-
return "secureUrl";
28+
if (/^https:\/\/.*$/.test(url)) return 'secureUrl';
3329

34-
if (isInNet(myIpAddress(), '10.10.0.0', '255.255.0.0'))
35-
return '10.10.0.0';
30+
if (isInNet(myIpAddress(), '10.10.0.0', '255.255.0.0')) return '10.10.0.0';
3631

37-
if ((typeof(myIpAddressEx) == "function") &&
38-
isInNetEx(myIpAddressEx(), '3ffe:8311:ffff/48'))
32+
if (
33+
typeof myIpAddressEx == 'function' &&
34+
isInNetEx(myIpAddressEx(), '3ffe:8311:ffff/48')
35+
)
3936
return '3ffe:8311:ffff';
40-
41-
else
42-
return "END-OF-SCRIPT";
37+
else return 'END-OF-SCRIPT';
4338
}

0 commit comments

Comments
 (0)