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?


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;
-       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;
                } 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;
                }
                free(escapeduri);
                free(escapedhtml);
                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)
-               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);

Reply via email to