From 59d09c2c1281cb678d98e925c94b987d31280d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20Schl=C3=B6mer?= Date: Mon, 27 Apr 2026 11:29:03 +0200 Subject: [PATCH 1/2] fix various toctou bugs in battery.cpp --- src/modules/battery.cpp | 92 +++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index 30be3857..25436baf 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -117,24 +117,16 @@ void waybar::modules::Battery::refreshBatteries() { if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) && (fs::exists(node.path() / "capacity") || fs::exists(node.path() / "charge_now")) && fs::exists(node.path() / "uevent") && - (fs::exists(node.path() / "status") || bat_compatibility) && - fs::exists(node.path() / "type")) { + (fs::exists(node.path() / "status") || bat_compatibility)) { std::string type; - std::ifstream(node.path() / "type") >> type; - - if (!type.compare("Battery")) { + if (std::ifstream{node.path() / "type"} >> type && !type.compare("Battery")) { // Ignore non-system power supplies unless explicitly requested - if (!bat_defined && fs::exists(node.path() / "scope")) { + if (!bat_defined) { std::string scope; - try { - // for hotplug-in device, access it is always unstable because you may remove the - // device anytime so just allow failure happen and do nothing - std::ifstream(node.path() / "scope") >> scope; - } catch (const std::ifstream::failure& e) { - scope.clear(); - continue; - } - if (g_ascii_strcasecmp(scope.data(), "device") == 0) { + // for hotplug-in device, access it is always unstable because you may remove the + // device anytime so just allow failure happen and do nothing + if (std::ifstream{node.path() / "scope"} >> scope && + g_ascii_strcasecmp(scope.data(), "device") == 0) { continue; } } @@ -282,11 +274,11 @@ waybar::modules::Battery::getInfos() { auto bat = item.first; std::string _status; - /* Check for adapter status if battery is not available */ - if (!std::ifstream(bat / "status")) { - std::getline(std::ifstream(adapter_ / "status"), _status); - } else { - std::getline(std::ifstream(bat / "status"), _status); + { + std::ifstream f{bat / "status"}; + if (!std::getline(f, _status)) { + std::getline(std::ifstream(adapter_ / "status"), _status); + } } // Some battery will report current and charge in μA/μAh. @@ -295,64 +287,64 @@ waybar::modules::Battery::getInfos() { uint32_t current_now = 0; int32_t _current_now_int = 0; bool current_now_exists = false; - if (fs::exists(bat / "current_now")) { + if (std::ifstream current_now_f{bat / "current_now"}) { current_now_exists = true; - std::ifstream(bat / "current_now") >> _current_now_int; - } else if (fs::exists(bat / "current_avg")) { + current_now_f >> _current_now_int; + } else if (std::ifstream current_avg_f{bat / "current_avg"}) { current_now_exists = true; - std::ifstream(bat / "current_avg") >> _current_now_int; + current_avg_f >> _current_now_int; } // Documentation ABI allows a negative value when discharging, positive // value when charging. current_now = std::abs(_current_now_int); - if (fs::exists(bat / "time_to_empty_now")) { + if (std::ifstream f{bat / "time_to_empty_now"}) { time_to_empty_now_exists = true; - std::ifstream(bat / "time_to_empty_now") >> time_to_empty_now; + f >> time_to_empty_now; } - if (fs::exists(bat / "time_to_full_now")) { + if (std::ifstream f{bat / "time_to_full_now"}) { time_to_full_now_exists = true; - std::ifstream(bat / "time_to_full_now") >> time_to_full_now; + f >> time_to_full_now; } uint32_t voltage_now = 0; bool voltage_now_exists = false; - if (fs::exists(bat / "voltage_now")) { + if (std::ifstream voltage_now_f{bat / "voltage_now"}) { voltage_now_exists = true; - std::ifstream(bat / "voltage_now") >> voltage_now; - } else if (fs::exists(bat / "voltage_avg")) { + voltage_now_f >> voltage_now; + } else if (std::ifstream voltage_avg_f{bat / "voltage_avg"}) { voltage_now_exists = true; - std::ifstream(bat / "voltage_avg") >> voltage_now; + voltage_avg_f >> voltage_now; } uint32_t charge_full = 0; bool charge_full_exists = false; - if (fs::exists(bat / "charge_full")) { + if (std::ifstream f{bat / "charge_full"}) { charge_full_exists = true; - std::ifstream(bat / "charge_full") >> charge_full; + f >> charge_full; } uint32_t charge_full_design = 0; bool charge_full_design_exists = false; - if (fs::exists(bat / "charge_full_design")) { + if (std::ifstream f{bat / "charge_full_design"}) { charge_full_design_exists = true; - std::ifstream(bat / "charge_full_design") >> charge_full_design; + f >> charge_full_design; } uint32_t charge_now = 0; bool charge_now_exists = false; - if (fs::exists(bat / "charge_now")) { + if (std::ifstream f{bat / "charge_now"}) { charge_now_exists = true; - std::ifstream(bat / "charge_now") >> charge_now; + f >> charge_now; } uint32_t power_now = 0; int32_t _power_now_int = 0; bool power_now_exists = false; - if (fs::exists(bat / "power_now")) { + if (std::ifstream f{bat / "power_now"}) { power_now_exists = true; - std::ifstream(bat / "power_now") >> _power_now_int; + f >> _power_now_int; } // Some drivers (example: Qualcomm) exposes use a negative value when // discharging, positive value when charging. @@ -360,28 +352,28 @@ waybar::modules::Battery::getInfos() { uint32_t energy_now = 0; bool energy_now_exists = false; - if (fs::exists(bat / "energy_now")) { + if (std::ifstream f{bat / "energy_now"}) { energy_now_exists = true; - std::ifstream(bat / "energy_now") >> energy_now; + f >> energy_now; } uint32_t energy_full = 0; bool energy_full_exists = false; - if (fs::exists(bat / "energy_full")) { + if (std::ifstream f{bat / "energy_full"}) { energy_full_exists = true; - std::ifstream(bat / "energy_full") >> energy_full; + f >> energy_full; } uint32_t energy_full_design = 0; bool energy_full_design_exists = false; - if (fs::exists(bat / "energy_full_design")) { + if (std::ifstream f{bat / "energy_full_design"}) { energy_full_design_exists = true; - std::ifstream(bat / "energy_full_design") >> energy_full_design; + f >> energy_full_design; } uint16_t cycleCount = 0; - if (fs::exists(bat / "cycle_count")) { - std::ifstream(bat / "cycle_count") >> cycleCount; + if (std::ifstream f{bat / "cycle_count"}) { + f >> cycleCount; } if (charge_full_design >= largestDesignCapacity) { largestDesignCapacity = charge_full_design; @@ -411,9 +403,9 @@ waybar::modules::Battery::getInfos() { } else if (energy_now_exists && energy_full_exists && energy_full != 0) { capacity_exists = true; capacity = 100 * (uint64_t)energy_now / (uint64_t)energy_full; - } else if (fs::exists(bat / "capacity")) { + } else if (std::ifstream f{bat / "capacity"}) { capacity_exists = true; - std::ifstream(bat / "capacity") >> capacity; + f >> capacity; } if (!voltage_now_exists) { From 5af324f375edf8a6a033869d5386e711b4e49f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20Schl=C3=B6mer?= Date: Mon, 27 Apr 2026 11:41:09 +0200 Subject: [PATCH 2/2] two more toctou bugs --- src/AAppIconLabel.cpp | 26 +++++++++++++------------- src/modules/cpu_frequency/linux.cpp | 18 ++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/AAppIconLabel.cpp b/src/AAppIconLabel.cpp index b72906c3..784f30c2 100644 --- a/src/AAppIconLabel.cpp +++ b/src/AAppIconLabel.cpp @@ -33,21 +33,21 @@ std::string toLowerCase(const std::string& input) { std::optional getFileBySuffix(const std::string& dir, const std::string& suffix, bool check_lower_case) { - if (!std::filesystem::exists(dir)) { - return {}; - } - for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) { - if (entry.is_regular_file()) { - std::string filename = entry.path().filename().string(); - if (filename.size() < suffix.size()) { - continue; - } - if ((filename.compare(filename.size() - suffix.size(), suffix.size(), suffix) == 0) || - (check_lower_case && filename.compare(filename.size() - suffix.size(), suffix.size(), - toLowerCase(suffix)) == 0)) { - return entry.path().string(); + try { + for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) { + if (entry.is_regular_file()) { + std::string filename = entry.path().filename().string(); + if (filename.size() < suffix.size()) { + continue; + } + if ((filename.compare(filename.size() - suffix.size(), suffix.size(), suffix) == 0) || + (check_lower_case && filename.compare(filename.size() - suffix.size(), suffix.size(), + toLowerCase(suffix)) == 0)) { + return entry.path().string(); + } } } + } catch (const std::filesystem::filesystem_error&) { } return {}; diff --git a/src/modules/cpu_frequency/linux.cpp b/src/modules/cpu_frequency/linux.cpp index 83f06aa5..7b927cdc 100644 --- a/src/modules/cpu_frequency/linux.cpp +++ b/src/modules/cpu_frequency/linux.cpp @@ -23,23 +23,21 @@ std::vector waybar::modules::CpuFrequency::parseCpuFrequencies() { if (frequencies.size() <= 0) { std::string cpufreq_dir = "/sys/devices/system/cpu/cpufreq"; - if (std::filesystem::exists(cpufreq_dir)) { + try { std::vector frequency_files = {"/cpuinfo_min_freq", "/cpuinfo_max_freq"}; for (auto& p : std::filesystem::directory_iterator(cpufreq_dir)) { for (const auto& freq_file : frequency_files) { std::string freq_file_path = p.path().string() + freq_file; - if (std::filesystem::exists(freq_file_path)) { - std::string freq_value; - std::ifstream freq(freq_file_path); - if (freq.is_open()) { - getline(freq, freq_value); - float frequency = std::strtol(freq_value.c_str(), nullptr, 10); - frequencies.push_back(frequency / 1000); - freq.close(); - } + std::string freq_value; + std::ifstream freq(freq_file_path); + if (freq.is_open()) { + getline(freq, freq_value); + float frequency = std::strtol(freq_value.c_str(), nullptr, 10); + frequencies.push_back(frequency / 1000); } } } + } catch (const std::filesystem::filesystem_error&) { } }