From 29328cbda5daea22f02e4ca94ca75783f22efc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 29 Sep 2013 14:40:58 +0200 Subject: [PATCH] Fix buffer overrun when enumerating files https://bugs.freedesktop.org/show_bug.cgi?id=69887 Based-on-a-patch-by: Hans Petter Jansson --- src/shared/util.c | 79 +++++++++++++++++----------------------------------- src/test/test-util.c | 10 +++++++ 2 files changed, 36 insertions(+), 53 deletions(-) diff --git a/src/shared/util.c b/src/shared/util.c index 766957a..4f80cc8 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -4412,38 +4412,31 @@ int dirent_ensure_type(DIR *d, struct dirent *de) { } int in_search_path(const char *path, char **search) { - char **i, *parent; + char **i; + _cleanup_free_ char *parent = NULL; int r; r = path_get_parent(path, &parent); if (r < 0) return r; - r = 0; - - STRV_FOREACH(i, search) { - if (path_equal(parent, *i)) { - r = 1; - break; - } - } - - free(parent); + STRV_FOREACH(i, search) + if (path_equal(parent, *i)) + return 1; - return r; + return 0; } int get_files_in_directory(const char *path, char ***list) { - DIR *d; - int r = 0; - unsigned n = 0; - char **l = NULL; + _cleanup_closedir_ DIR *d = NULL; + size_t bufsize = 0, n = 0; + _cleanup_strv_free_ char **l = NULL; assert(path); /* Returns all files in a directory in *list, and the number * of files as return value. If list is NULL returns only the - * number */ + * number. */ d = opendir(path); if (!d) @@ -4455,11 +4448,9 @@ int get_files_in_directory(const char *path, char ***list) { int k; k = readdir_r(d, &buf.de, &de); - if (k != 0) { - r = -k; - goto finish; - } - + assert(k >= 0); + if (k > 0) + return -k; if (!de) break; @@ -4469,43 +4460,25 @@ int get_files_in_directory(const char *path, char ***list) { continue; if (list) { - if ((unsigned) r >= n) { - char **t; - - n = MAX(16, 2*r); - t = realloc(l, sizeof(char*) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } - - l = t; - } - - assert((unsigned) r < n); + /* one extra slot is needed for the terminating NULL */ + if (!GREEDY_REALLOC(l, bufsize, n + 2)) + return -ENOMEM; - l[r] = strdup(de->d_name); - if (!l[r]) { - r = -ENOMEM; - goto finish; - } + l[n] = strdup(de->d_name); + if (!l[n]) + return -ENOMEM; - l[++r] = NULL; + l[++n] = NULL; } else - r++; + n++; } -finish: - if (d) - closedir(d); - - if (r >= 0) { - if (list) - *list = l; - } else - strv_free(l); + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } - return r; + return n; } char *strjoin(const char *x, ...) { diff --git a/src/test/test-util.c b/src/test/test-util.c index ad13d53..c5762ed 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -27,6 +27,7 @@ #include #include "util.h" +#include "strv.h" static void test_streq_ptr(void) { assert_se(streq_ptr(NULL, NULL)); @@ -582,6 +583,14 @@ static void test_fstab_node_to_udev_node(void) { free(n); } +static void test_get_files_in_directory(void) { + _cleanup_strv_free_ char **l = NULL, **t = NULL; + + assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(".", &l) >= 0); + assert_se(get_files_in_directory(".", NULL) >= 0); +} + int main(int argc, char *argv[]) { test_streq_ptr(); test_first_word(); @@ -618,6 +627,7 @@ int main(int argc, char *argv[]) { test_parse_user_at_host(); test_split_pair(); test_fstab_node_to_udev_node(); + test_get_files_in_directory(); return 0; }