summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraristocratos <gnmjpl@gmail.com>2021-11-02 21:10:41 +0100
committeraristocratos <gnmjpl@gmail.com>2021-11-02 21:10:41 +0100
commit0f566ae688f4b58f6b0dc52a7ec80f870f00a69a (patch)
tree679dc0fb7e36a525305c9d98038de84b88f1af34
parent98ae5e8f460769a12253c40566b0b609213e5093 (diff)
Fixed: Security issue when running with SUID bit set
-rw-r--r--src/btop.cpp27
-rw-r--r--src/btop_config.cpp1
-rw-r--r--src/btop_shared.hpp2
-rw-r--r--src/btop_tools.cpp13
4 files changed, 43 insertions, 0 deletions
diff --git a/src/btop.cpp b/src/btop.cpp
index 208da4a..c6a7b9c 100644
--- a/src/btop.cpp
+++ b/src/btop.cpp
@@ -64,6 +64,7 @@ namespace Global {
string fg_green = "\x1b[1;92m";
string fg_red = "\x1b[0;91m";
+ uid_t real_uid, set_uid;
fs::path self_path;
@@ -298,6 +299,18 @@ namespace Runner {
~thread_lock() { if (status == 0) pthread_mutex_unlock(&pt_mutex); }
};
+ //* Wrapper for raising priviliges when using SUID bit
+ class gain_priv {
+ int status = -1;
+ public:
+ gain_priv() {
+ if (Global::real_uid != Global::set_uid) this->status = seteuid(Global::set_uid);
+ }
+ ~gain_priv() {
+ if (status == 0) status = seteuid(Global::real_uid);
+ }
+ };
+
string output;
string empty_bg;
bool pause_output = false;
@@ -385,6 +398,9 @@ namespace Runner {
//? Atomic lock used for blocking non thread-safe actions in main thread
atomic_lock lck(active);
+ //? Set effective user if SUID bit is set
+ gain_priv powers{};
+
auto& conf = current_conf;
//! DEBUG stats
@@ -616,6 +632,17 @@ int main(int argc, char **argv) {
Global::start_time = time_s();
+ //? Save real and effective userid's and drop priviliges until needed if running with SUID bit set
+ Global::real_uid = getuid();
+ Global::set_uid = geteuid();
+ if (Global::real_uid != Global::set_uid) {
+ if (seteuid(Global::real_uid) != 0) {
+ Global::real_uid = Global::set_uid;
+ Global::exit_error_msg = "Failed to change effective user ID. Unset btop SUID bit to ensure security on this system. Quitting!";
+ clean_quit(1);
+ }
+ }
+
//? Call argument parser if launched with arguments
if (argc > 1) argumentParser(argc, argv);
diff --git a/src/btop_config.cpp b/src/btop_config.cpp
index ca3e66a..b0edcde 100644
--- a/src/btop_config.cpp
+++ b/src/btop_config.cpp
@@ -589,6 +589,7 @@ namespace Config {
void write() {
if (conf_file.empty() or not write_new) return;
Logger::debug("Writing new config file");
+ if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return;
std::ofstream cwrite(conf_file, std::ios::trunc);
if (cwrite.good()) {
cwrite << "#? Config file for btop v. " << Global::Version;
diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp
index 832208c..b5eaf6b 100644
--- a/src/btop_shared.hpp
+++ b/src/btop_shared.hpp
@@ -27,6 +27,7 @@ tab-size = 4
#include <array>
#include <ifaddrs.h>
#include <tuple>
+#include <unistd.h>
using std::string, std::vector, std::deque, robin_hood::unordered_flat_map, std::atomic, std::array, std::tuple;
@@ -43,6 +44,7 @@ namespace Global {
extern atomic<bool> resized;
extern string overlay;
extern string clock;
+ extern uid_t real_uid, set_uid;
}
namespace Runner {
diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp
index 8778dbe..061e43f 100644
--- a/src/btop_tools.cpp
+++ b/src/btop_tools.cpp
@@ -406,6 +406,18 @@ namespace Logger {
size_t loglevel;
fs::path logfile;
+ //* Wrapper for lowering priviliges if using SUID bit and currently isn't using real userid
+ class lose_priv {
+ int status = -1;
+ public:
+ lose_priv() {
+ if (geteuid() != Global::real_uid) this->status = seteuid(Global::real_uid);
+ }
+ ~lose_priv() {
+ if (status == 0) status = seteuid(Global::set_uid);
+ }
+ };
+
void set(const string& level) {
loglevel = v_index(log_levels, level);
}
@@ -413,6 +425,7 @@ namespace Logger {
void log_write(const size_t level, const string& msg) {
if (loglevel < level or logfile.empty()) return;
atomic_lock lck(busy, true);
+ lose_priv neutered{};
std::error_code ec;
try {
if (fs::exists(logfile) and fs::file_size(logfile, ec) > 1024 << 10 and not ec) {