From 4057e0f876c486b3e9c712771350083107421b27 Mon Sep 17 00:00:00 2001 From: Ritchie Cunningham Date: Thu, 6 Nov 2025 19:47:35 +0000 Subject: [PATCH] [Add] Enforce file permissions. --- common/src/lua_api.cpp | 20 ++++++++++++++++++++ common/src/session.cpp | 11 +++++++++++ common/src/session.h | 3 +++ common/src/vfs.cpp | 24 ++++++++++++++++++++++++ common/src/vfs.h | 6 ++++++ 5 files changed, 64 insertions(+) diff --git a/common/src/lua_api.cpp b/common/src/lua_api.cpp index 8d9a739..8239bcf 100644 --- a/common/src/lua_api.cpp +++ b/common/src/lua_api.cpp @@ -27,6 +27,11 @@ std::string rm(Session& context, const std::string& filename) { return "rm: cannot remove '" + filename + "': Is a directory."; } + vfs_node* parent_dir = it->second->parent; + if(parent_dir && !has_permission(parent_dir, context, WRITE_PERM)) { + return "rm: cannot remove '" + filename + "': Permission denied"; + } + delete it->second; /* Free the memory for the node. */ current_dir->children.erase(it); /* Remove from map. */ return ""; @@ -65,6 +70,10 @@ std::string write_file(Session& context, const std::string& path, return "write: cannot create file in '" + get_full_path(parent_dir) + "': Not a directory"; } + if(!has_permission(parent_dir, context, WRITE_PERM)) { + return "write: cannot create file '" + path + "': Permission denied"; + } + auto it = parent_dir->children.find(filename); if(it != parent_dir->children.end()) { if(it->second->type == DIR_NODE) { @@ -114,6 +123,10 @@ std::string create_executable(Session& context, const std::string& path, + "': Not a directory"; } + if(!has_permission(parent_dir, context, WRITE_PERM)) { + return "create_executable: cannot create file '" + path + "': Permission denied"; + } + /* Overwrite if exists. */ auto it = parent_dir->children.find(filename); if(it != parent_dir->children.end()) { @@ -129,6 +142,10 @@ std::string create_executable(Session& context, const std::string& path, } std::string read_file(Session& context, const std::string& path) { + vfs_node* node = find_node_by_path(context.get_session_machine()->vfs_root, path); + if(node && !has_permission(node, context, READ_PERM)) { + return "cat: " + path + ": Permission denied"; + } return context.read_file(path); } @@ -142,6 +159,9 @@ std::string cd(Session& context, const std::string& path) { } else { auto it = current_dir->children.find(path); if(it != current_dir->children.end() && it->second->type == DIR_NODE) { + if(!has_permission(it->second, context, EXEC_PERM)) { + return "cd: " + path + ": Permission denied"; + } context.set_current_dir(it->second); } else { return "cd: no such file or directory: " + path; diff --git a/common/src/session.cpp b/common/src/session.cpp index 451a42d..1b0054d 100644 --- a/common/src/session.cpp +++ b/common/src/session.cpp @@ -70,6 +70,14 @@ void Session::set_session_machine(Machine* machine) { } } +uint32_t Session::get_current_uid(void) { + return _home_machine->owner_id; +} + +uint32_t Session::get_current_gid(void) { + return _home_machine->owner_id; +} + std::string Session::process_command(const std::string& command) { /* * Creating the Lua processor on-demand to ensure it exists on the same @@ -113,6 +121,9 @@ std::string Session::process_command(const std::string& command) { if(command_node) { if(command_node->type == EXEC_NODE) { + if(!has_permission(command_node, *this, EXEC_PERM)) { + return "Cannot execute '" + command_name + "': Permission denied."; + } bool is_remote = (_session_machine != _home_machine); std::string deobfuscated_content = util::xor_string(command_node->content); sol::object result = lua.execute(deobfuscated_content, *this, args, is_remote); diff --git a/common/src/session.h b/common/src/session.h index 5ca7b36..a4ff547 100644 --- a/common/src/session.h +++ b/common/src/session.h @@ -28,6 +28,9 @@ public: DatabaseManager* get_db_manager(void); MachineManager* get_machine_manager(void); INetworkBridge* get_network_bridge(void); + + uint32_t get_current_uid(void); + uint32_t get_current_gid(void); void set_current_dir(vfs_node* node); void set_session_machine(Machine* machine); diff --git a/common/src/vfs.cpp b/common/src/vfs.cpp index f4f152f..73cc95b 100644 --- a/common/src/vfs.cpp +++ b/common/src/vfs.cpp @@ -1,6 +1,30 @@ #include #include "vfs.h" +#include "session.h" + +bool has_permission(vfs_node* node, Session& context, uint8_t required_perm) { + uint32_t uid = context.get_current_uid(); + if(uid == 0) { /* Root user. */ + return true; + } + + uint32_t gid = context.get_current_gid(); + uint16_t perms = node->permissions; + + if(node->owner_id == uid) { + /* Check owner permissions. */ + return ((perms >> 6) & required_perm) == required_perm; + } else if(node->group_id == gid) { + /* Check group permissions. */ + return ((perms >> 3) & required_perm) == required_perm; + } else { + /* Check other permissions. */ + return (perms & required_perm) == required_perm; + } + + return false; +} /* Create a new node. */ vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent, diff --git a/common/src/vfs.h b/common/src/vfs.h index 756c56b..1c7a35f 100644 --- a/common/src/vfs.h +++ b/common/src/vfs.h @@ -4,6 +4,7 @@ #include #include +class Session; struct vfs_node; /* Store children for quick lookup by name. */ @@ -33,6 +34,11 @@ struct vfs_node { vfs_node* parent; }; +const uint8_t READ_PERM = 4; +const uint8_t WRITE_PERM = 2; +const uint8_t EXEC_PERM = 1; + +bool has_permission(vfs_node* node, Session& context, uint8_t required_perm); vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent, uint32_t owner_id = 0, uint32_t group_id = 0, uint16_t permissions=0755); vfs_node* find_node_by_id(vfs_node* root, long long id);