quark has a 1 byte NULL stack overflow triggered by an HTTP request for a folder path not ending with '/' and having length PATH_MAX-1. Relevant code from http.c:http_send_response()
if (S_ISDIR(st.st_mode)) { /* add / to target if not present */ len = strlen(realtarget); if (len == PATH_MAX - 2) { return http_send_status(fd, S_REQUEST_TOO_LARGE); } if (len && realtarget[len - 1] != '/') { realtarget[len] = '/'; realtarget[len + 1] = '\0'; } } The issue is mitigated by changing the second conditional to if (len >= PATH_MAX - 2) { There are two ways to trigger the bug. On my system, PATH_MAX = 4096 and the default quark config has HEADER_MAX = 4096. The bug is triggered by folder paths of length 4095. The `-m` option lets me increase the path length despite the HEADER_MAX constraint. Something like, # mkdir -p $(ruby -e 'puts "#{("/"+"X"*99)*40 + "/" + "X"*94}"') # ./quark -h 127.0.0.1 -p 10000 -d / -m "foo /X $(ruby -e 'puts "/" + "X"*17')" # curl -vvvv -X GET -H 'Host:' -H 'User-Agent:' -H 'Accept:' $(ruby -e 'puts "http://127.0.0.1:10000#{"/" + "X"*83 + ("/"+"X"*99)*39 + "/" + "X"*94}"') Seventeen bytes are used for 'GET', 'HTTP/1.1' and whitespace. The longest queryable path in a valid HTTP header is 4096-17=4079 bytes. The quark map increases the path length by 16 bytes. The forward slash appending code writes a NULL byte to realtarget[4079+16+1=4096], which is out of bounds. Alternatively, the bug can be triggered without `-m` if the system has a 'small' PATH_MAX or the configuration has a 'large' HEADER_MAX. The sufficient condition is, HEADER_MAX >= (PATH_MAX - 1) + 17 I set HEADER_MAX to 8192 (allows me to leave the request headers) and triggered the bug like this, # mkdir -p $(ruby -e 'puts "#{("/"+"X"*99)*40 + "/" + "X"*94}"') # ./quark -h 127.0.0.1 -p 10000 -d / # curl -vvvv -X GET $(ruby -e 'puts "http://127.0.0.1:10000#{("/"+"X"*99)*40 + "/" + "X"*94}"') quark version, $ git log -n 1 commit 9ff3f780e1d1912b89727140df7c1529ab8c5146 Author: Laslo Hunhold Date: Mon Jul 2 18:43:06 2018 +0200 Send a relative redirection header wherever possible This makes quark much more flexible when it is run behind a network filter or other kind of tunnel. Only send an absolute redirection when we are handling vhosts. PATH_MAX, $ grep PATH_MAX /usr/include/linux/limits.h #define PATH_MAX 4096 /* # chars in a path name including nul */ patch, Fix one byte NULL stack overflow. Don't append a forward slash if the length of a folder is PATH_MAX-1. This can happen if HEADER_MAX is larger than PATH_MAX or if the `-m` option is used to increase the path length. --- http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http.c b/http.c index f0b84b1..7a801a5 100644 --- a/http.c +++ b/http.c @@ -430,7 +430,7 @@ http_send_response(int fd, struct request *r) if (S_ISDIR(st.st_mode)) { /* add / to target if not present */ len = strlen(realtarget); - if (len == PATH_MAX - 2) { + if (len >= PATH_MAX - 2) { return http_send_status(fd, S_REQUEST_TOO_LARGE); } if (len && realtarget[len - 1] != '/') { -- burrows