On Sun, Aug 14, 2022 at 11:15:16PM +0200, Omar Polo wrote: > I was looking for something different when I stumbled upon this. > > - in server_file_index `escapedpath' is leaked if evbuffer_add_printf > fails, similarly the directory entries in the loop. `escapeduri' > is also leaked if escape_html fails. > > - read_errdoc leaks a file descriptor if fstat fails or if the file > is empty. > > both very unlikely but worth fixing IMHO. > > For server_file_index I decided to just drop the `skip' variable and > just goto fail on errors. There shouldn't be any visible change from > it, except that we don't try to serve half page if we somehow exhaust > memory halfway through. > > ok?
I have no opinion on whether keeping or dropping skip is better. There are a bunch of new problems with your diff, though. > > > Index: server_file.c > =================================================================== > RCS file: /home/cvs/src/usr.sbin/httpd/server_file.c,v > retrieving revision 1.74 > diff -u -p -r1.74 server_file.c > --- server_file.c 4 Mar 2022 01:46:07 -0000 1.74 > +++ server_file.c 14 Aug 2022 21:09:25 -0000 > @@ -474,7 +474,7 @@ server_file_index(struct httpd *env, str > struct http_descriptor *desc = clt->clt_descreq; > struct server_config *srv_conf = clt->clt_srv_conf; > struct dirent **namelist, *dp; namelist should now be initialized to NULL since you can goto abort before it is initialized. > - int namesize, i, ret, fd = -1, namewidth, skip; > + int namesize = 0, i = 0, ret, fd = -1, namewidth; > int code = 500; > struct evbuffer *evb = NULL; > struct media_type *media; > @@ -510,9 +510,6 @@ server_file_index(struct httpd *env, str > if ((namesize = scandir(path, &namelist, NULL, alphasort)) == -1) > goto abort; > > - /* Indicate failure but continue going through the list */ > - skip = 0; > - > if ((escapedpath = escape_html(desc->http_path)) == NULL) > goto fail; > > @@ -535,8 +532,10 @@ server_file_index(struct httpd *env, str > "<body>\n" > "<h1>Index of %s</h1>\n" > "<hr>\n<pre>\n", > - escapedpath, style, escapedpath) == -1) > - skip = 1; > + escapedpath, style, escapedpath) == -1) { > + free(escapedpath); > + goto fail; > + } > > free(escapedpath); > > @@ -545,8 +544,7 @@ server_file_index(struct httpd *env, str > > dp = namelist[i]; > > - if (skip || > - fstatat(fd, dp->d_name, &subst, 0) == -1) { > + if (fstatat(fd, dp->d_name, &subst, 0) == -1) { > free(dp); > continue; > } > @@ -558,8 +556,10 @@ server_file_index(struct httpd *env, str > > if ((escapeduri = url_encode(dp->d_name)) == NULL) > goto fail; > - if ((escapedhtml = escape_html(dp->d_name)) == NULL) > + if ((escapedhtml = escape_html(dp->d_name)) == NULL) { > + free(escapeduri); > goto fail; > + } > > if (dp->d_name[0] == '.' && > !(dp->d_name[1] == '.' && dp->d_name[2] == '\0')) { > @@ -571,7 +571,7 @@ server_file_index(struct httpd *env, str > strchr(escapeduri, ':') != NULL ? "./" : "", > escapeduri, escapedhtml, > MAXIMUM(namewidth, 0), " ", tmstr, "-") == -1) > - skip = 1; > + goto fail; this goto now leaks escapeduri and escapedhtml > } else if (S_ISREG(subst.st_mode)) { > if (evbuffer_add_printf(evb, > "<a href=\"%s%s\">%s</a>%*s%s%20llu\n", > @@ -579,16 +579,16 @@ server_file_index(struct httpd *env, str > escapeduri, escapedhtml, > MAXIMUM(namewidth, 0), " ", > tmstr, subst.st_size) == -1) > - skip = 1; > + goto fail; ditto > } > free(escapeduri); > free(escapedhtml); If I'd want to drop skip, I'd probably add escapeduri = NULL; escapedhtml = NULL; here and free them also in the fail path. Of course you then mustn't free escapeduri if escape_html() fails. > free(dp); > } > free(namelist); > + namelist = NULL; > > - if (skip || > - evbuffer_add_printf(evb, > + if (evbuffer_add_printf(evb, > "</pre>\n<hr>\n</body>\n</html>\n") == -1) > goto abort; > > @@ -629,6 +629,9 @@ server_file_index(struct httpd *env, str > bufferevent_free(clt->clt_bev); > clt->clt_bev = NULL; > abort: > + for (; i < namesize; i++) > + free(namelist[i]); > + free(namelist); > if (fd != -1) > close(fd); > if (evb != NULL) > Index: server_http.c > =================================================================== > RCS file: /home/cvs/src/usr.sbin/httpd/server_http.c,v > retrieving revision 1.150 > diff -u -p -r1.150 server_http.c > --- server_http.c 2 Mar 2022 11:10:43 -0000 1.150 > +++ server_http.c 14 Aug 2022 18:42:33 -0000 > @@ -1777,14 +1777,13 @@ read_errdoc(const char *root, const char > free(path); > if (fstat(fd, &sb) < 0) { > log_warn("%s: stat", __func__); > + close(fd); > return (NULL); > } > > if ((ret = calloc(1, sb.st_size + 1)) == NULL) > fatal("calloc"); > - if (sb.st_size == 0) No strong opinion, but I'd prefer adding a close here. httpd code is already tricky enough to read. > - return (ret); > - if (read(fd, ret, sb.st_size) != sb.st_size) { > + if (sb.st_size != 0 && read(fd, ret, sb.st_size) != sb.st_size) { > log_warn("%s: read", __func__); > close(fd); > free(ret); >