From cb737464dc49604d78dde0827d3da5f754f344d1 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 17 Oct 2023 12:05:53 +0200 Subject: [PATCH] launch: list directories alphabetically When enumerating directories ensure that we iterate the entries in alphabetical order. We used to follow what the reference-implementation does, and simply read directories in semi-random on-disk order. This is rather brittle to debug and exposes behavior that we really don't want to expose. Instead, we want predictable enumerations so policy and service-files can be more easily traced and debugged. The downside of ordering directory entries is that we have to collect all entries first, rather than using the streaming API of the kernel. Fortunately, this is what we do, anyway, since we already have 1-to-1 mappings of the directory entries to internal data-structures. Hence, in all our current use-cases, it is not an issue to stream everything into a collection first. Signed-off-by: David Rheinsberg --- src/launch/config.c | 15 +++++++++++---- src/launch/launcher.c | 15 +++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/launch/config.c b/src/launch/config.c index c54f581b..3ca2b518 100644 --- a/src/launch/config.c +++ b/src/launch/config.c @@ -13,6 +13,7 @@ #include "util/common.h" #include "util/dirwatch.h" #include "util/error.h" +#include "util/fs.h" #include "util/selinux.h" #include "util/string.h" @@ -1058,10 +1059,11 @@ static void config_parser_end_fn(void *userdata, const XML_Char *name) { break; case CONFIG_NODE_INCLUDEDIR: { + _c_cleanup_(fs_dirlist_freep) FsDirlist *list = NULL; _c_cleanup_(c_closedirp) DIR *dir = NULL; static const char suffix[] = ".conf"; struct dirent *de; - size_t n; + size_t i, n; r = config_path_new_dir(&state->current->includedir.dir, state->file, @@ -1091,11 +1093,16 @@ static void config_parser_end_fn(void *userdata, const XML_Char *name) { return; } - for (errno = 0, de = readdir(dir); - de; - errno = 0, de = readdir(dir)) { + r = fs_dir_list(dir, &list, 0); + if (r) { + state->error = error_fold(r); + return; + } + + for (i = 0; i < list->n_entries; ++i) { _c_cleanup_(config_node_freep) ConfigNode *node = NULL; + de = list->entries[i]; n = strlen(de->d_name); if (n <= strlen(suffix)) diff --git a/src/launch/launcher.c b/src/launch/launcher.c index 2105a474..9817c606 100644 --- a/src/launch/launcher.c +++ b/src/launch/launcher.c @@ -26,6 +26,7 @@ #include "util/audit.h" #include "util/dirwatch.h" #include "util/error.h" +#include "util/fs.h" #include "util/log.h" #include "util/misc.h" #include "util/string.h" @@ -736,10 +737,11 @@ static int launcher_load_service_file(Launcher *launcher, const char *path, cons static int launcher_load_service_dir(Launcher *launcher, const char *dirpath, NSSCache *nss_cache) { const char suffix[] = ".service"; + _c_cleanup_(fs_dirlist_freep) FsDirlist *list = NULL; _c_cleanup_(c_closedirp) DIR *dir = NULL; struct dirent *de; char *path; - size_t n; + size_t i, n; int r; dir = opendir(dirpath); @@ -767,11 +769,12 @@ static int launcher_load_service_dir(Launcher *launcher, const char *dirpath, NS if (r) return error_fold(r); - for (errno = 0, de = readdir(dir); - de; - errno = 0, de = readdir(dir)) { - if (de->d_name[0] == '.') - continue; + r = fs_dir_list(dir, &list, FS_DIR_FLAG_NO_HIDDEN); + if (r) + return error_fold(r); + + for (i = 0; i < list->n_entries; ++i) { + de = list->entries[i]; n = strlen(de->d_name); if (n <= strlen(suffix))