1From aea56f4bcb9948d456f3fae4d044fd3fa2e19706 Mon Sep 17 00:00:00 2001
2From: Frank Denis <github@pureftpd.org>
3Date: Mon, 30 Dec 2019 17:40:04 +0100
4Subject: [PATCH] listdir(): reuse a single buffer to store every file name to
5 display
6
7Allocating a new buffer for each entry is useless.
8
9And as these buffers are allocated on the stack, on systems with a
10small stack size, with many entries, the limit can easily be reached,
11causing a stack exhaustion and aborting the user session.
12
13Reported by Antonio Morales from the GitHub Security Lab team, thanks!
14[Retrieved from:
15https://github.com/jedisct1/pure-ftpd/commit/aea56f4bcb9948d456f3fae4d044fd3fa2e19706]
16Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
17---
18 src/ls.c | 15 ++++++++-------
19 1 file changed, 8 insertions(+), 7 deletions(-)
20
21diff --git a/src/ls.c b/src/ls.c
22index cf804c7..f8a588f 100644
23--- a/src/ls.c
24+++ b/src/ls.c
25@@ -661,6 +661,8 @@ static void listdir(unsigned int depth, int f, void * const tls_fd,
26     char *names;
27     PureFileInfo *s;
28     PureFileInfo *r;
29+    char *alloca_subdir;
30+    size_t sizeof_subdir;
31     int d;
32
33     if (depth >= max_ls_depth || matches >= max_ls_files) {
34@@ -690,14 +692,12 @@ static void listdir(unsigned int depth, int f, void * const tls_fd,
35     }
36     outputfiles(f, tls_fd);
37     r = dir;
38+    sizeof_subdir = PATH_MAX + 1U;
39+    if ((alloca_subdir = ALLOCA(sizeof_subdir)) == NULL) {
40+        goto toomany;
41+    }
42     while (opt_R && r != s) {
43         if (r->name_offset != (size_t) -1 && !chdir(FI_NAME(r))) {
44-            char *alloca_subdir;
45-            const size_t sizeof_subdir = PATH_MAX + 1U;
46-
47-            if ((alloca_subdir = ALLOCA(sizeof_subdir)) == NULL) {
48-                goto toomany;
49-            }
50             if (SNCHECK(snprintf(alloca_subdir, sizeof_subdir, "%s/%s",
51                                  name, FI_NAME(r)), sizeof_subdir)) {
52                 goto nolist;
53@@ -706,8 +706,8 @@ static void listdir(unsigned int depth, int f, void * const tls_fd,
54             wrstr(f, tls_fd, alloca_subdir);
55             wrstr(f, tls_fd, ":\r\n\r\n");
56             listdir(depth + 1U, f, tls_fd, alloca_subdir);
57+
58             nolist:
59-            ALLOCA_FREE(alloca_subdir);
60             if (matches >= max_ls_files) {
61                 goto toomany;
62             }
63@@ -720,6 +720,7 @@ static void listdir(unsigned int depth, int f, void * const tls_fd,
64         r++;
65     }
66     toomany:
67+    ALLOCA_FREE(alloca_subdir);
68     free(names);
69     free(dir);
70     names = NULL;
71