Skip to content

Commit

Permalink
Fixed: Security issue when running with SUID bit set
Browse files Browse the repository at this point in the history
  • Loading branch information
aristocratos committed Nov 2, 2021
1 parent 98ae5e8 commit 0f566ae
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/btop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/btop_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/btop_shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 {
Expand Down
13 changes: 13 additions & 0 deletions src/btop_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,26 @@ 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);
}

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) {
Expand Down

0 comments on commit 0f566ae

Please sign in to comment.