config: Hardened config logic against Time-Of-Check race conditions (#11368)

This commit is contained in:
David Baucum
2025-08-12 15:11:21 -04:00
committed by GitHub
parent 449d5e1113
commit 2b6e2ceb2e

View File

@@ -873,11 +873,15 @@ CConfigManager::CConfigManager() {
std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
std::string parentPath = std::filesystem::path(configPath).parent_path();
if (!std::filesystem::is_directory(parentPath)) {
Debug::log(WARN, "Creating config home directory");
try {
std::filesystem::create_directories(parentPath);
} catch (std::exception& e) { throw e; }
if (!parentPath.empty()) {
std::error_code ec;
bool created = std::filesystem::create_directories(parentPath, ec);
if (ec) {
Debug::log(ERR, "Couldn't create config home directory ({}): {}", ec.message(), parentPath);
return "Config could not be generated.";
}
if (created)
Debug::log(WARN, "Creating config home directory");
}
Debug::log(WARN, "No config file found; attempting to generate.");
@@ -886,7 +890,7 @@ std::optional<std::string> CConfigManager::generateConfig(std::string configPath
ofs << AUTOGENERATED_PREFIX << EXAMPLE_CONFIG;
ofs.close();
if (!std::filesystem::exists(configPath))
if (ofs.fail())
return "Config could not be generated.";
return configPath;
@@ -3040,28 +3044,31 @@ std::optional<std::string> CConfigManager::handleSource(const std::string& comma
std::string errorsFromParsing;
for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
auto value = absolutePath(glob_buf->gl_pathv[i], m_configCurrentPath);
auto value = absolutePath(glob_buf->gl_pathv[i], m_configCurrentPath);
if (!std::filesystem::is_regular_file(value)) {
if (std::filesystem::exists(value)) {
Debug::log(WARN, "source= skipping non-file {}", value);
continue;
}
std::error_code ec;
auto file_status = std::filesystem::status(value, ec);
Debug::log(ERR, "source= file doesn't exist: {}", value);
return "source= file " + value + " doesn't exist!";
if (ec) {
Debug::log(ERR, "source= file from glob result is inaccessible ({}): {}", ec.message(), value);
return "source= file " + value + " is inaccessible!";
}
m_configPaths.emplace_back(value);
auto configCurrentPathBackup = m_configCurrentPath;
m_configCurrentPath = value;
const auto THISRESULT = m_config->parseFile(value.c_str());
m_configCurrentPath = configCurrentPathBackup;
if (THISRESULT.error && errorsFromParsing.empty())
errorsFromParsing += THISRESULT.getError();
if (std::filesystem::is_regular_file(file_status)) {
m_configPaths.emplace_back(value);
auto configCurrentPathBackup = m_configCurrentPath;
m_configCurrentPath = value;
const auto THISRESULT = m_config->parseFile(value.c_str());
m_configCurrentPath = configCurrentPathBackup;
if (THISRESULT.error && errorsFromParsing.empty())
errorsFromParsing += THISRESULT.getError();
} else if (std::filesystem::is_directory(file_status)) {
Debug::log(WARN, "source= skipping directory {}", value);
continue;
} else {
Debug::log(WARN, "source= skipping non-regular-file {}", value);
continue;
}
}
if (errorsFromParsing.empty())