mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-08 08:11:14 +00:00
add audit hook for fs, network and processes
This commit is contained in:
@@ -14,12 +14,103 @@
|
||||
#include <slic3r/GUI/GUI_App.hpp>
|
||||
#include <slic3r/plugin/PluginFsUtils.hpp>
|
||||
#include <slic3r/plugin/PluginManager.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/event.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// extensive list of audit events can be found at https://docs.python.org/3/library/audit_events.html
|
||||
static const std::unordered_map<std::string, AuditEventCategory> audit_event_categories{
|
||||
// fsread
|
||||
{"glob.glob", AuditEventCategory::FsRead},
|
||||
{"glob.glob/2", AuditEventCategory::FsRead},
|
||||
{"os.fwalk", AuditEventCategory::FsRead},
|
||||
{"os.getxattr", AuditEventCategory::FsRead},
|
||||
{"os.listdir", AuditEventCategory::FsRead},
|
||||
{"os.listdrives", AuditEventCategory::FsRead},
|
||||
{"os.listmounts", AuditEventCategory::FsRead},
|
||||
{"os.listvolumes", AuditEventCategory::FsRead},
|
||||
{"os.listxattr", AuditEventCategory::FsRead},
|
||||
{"os.scandir", AuditEventCategory::FsRead},
|
||||
{"os.walk", AuditEventCategory::FsRead},
|
||||
{"pathlib.Path.glob", AuditEventCategory::FsRead},
|
||||
{"pathlib.Path.rglob", AuditEventCategory::FsRead},
|
||||
|
||||
// fsreadwrite
|
||||
{"os.chflags", AuditEventCategory::FsReadWrite},
|
||||
{"os.chmod", AuditEventCategory::FsReadWrite},
|
||||
{"os.chown", AuditEventCategory::FsReadWrite},
|
||||
{"os.removexattr", AuditEventCategory::FsReadWrite},
|
||||
{"os.rename", AuditEventCategory::FsReadWrite},
|
||||
{"os.setxattr", AuditEventCategory::FsReadWrite},
|
||||
{"os.truncate", AuditEventCategory::FsReadWrite},
|
||||
{"os.utime", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.chown", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.copymode", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.copystat", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.copyfile", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.copytree", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.make_archive", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.move", AuditEventCategory::FsReadWrite},
|
||||
{"shutil.unpack_archive", AuditEventCategory::FsReadWrite},
|
||||
|
||||
// fscreate
|
||||
{"os.link", AuditEventCategory::FsCreate},
|
||||
{"os.mkdir", AuditEventCategory::FsCreate},
|
||||
{"os.symlink", AuditEventCategory::FsCreate},
|
||||
{"tempfile.mkdtemp", AuditEventCategory::FsCreate},
|
||||
{"tempfile.mkstemp", AuditEventCategory::FsCreate},
|
||||
{"_winapi.CreateJunction", AuditEventCategory::FsCreate},
|
||||
|
||||
// fsdelete
|
||||
{"os.remove", AuditEventCategory::FsDelete},
|
||||
{"os.rmdir", AuditEventCategory::FsDelete},
|
||||
{"shutil.rmtree", AuditEventCategory::FsDelete},
|
||||
|
||||
// http
|
||||
{"http.client.connect", AuditEventCategory::Http},
|
||||
{"http.client.send", AuditEventCategory::Http},
|
||||
{"urllib.Request", AuditEventCategory::Http},
|
||||
|
||||
// socket
|
||||
{"socket.__new__", AuditEventCategory::Socket},
|
||||
{"socket.bind", AuditEventCategory::Socket},
|
||||
{"socket.connect", AuditEventCategory::Socket},
|
||||
{"socket.getaddrinfo", AuditEventCategory::Socket},
|
||||
{"socket.gethostbyaddr", AuditEventCategory::Socket},
|
||||
{"socket.gethostbyname", AuditEventCategory::Socket},
|
||||
{"socket.gethostname", AuditEventCategory::Socket},
|
||||
{"socket.getnameinfo", AuditEventCategory::Socket},
|
||||
{"socket.getservbyname", AuditEventCategory::Socket},
|
||||
{"socket.getservbyport", AuditEventCategory::Socket},
|
||||
{"socket.sendmsg", AuditEventCategory::Socket},
|
||||
{"socket.sendto", AuditEventCategory::Socket},
|
||||
|
||||
// processcreate
|
||||
{"os.fork", AuditEventCategory::ProcessCreate},
|
||||
{"os.forkpty", AuditEventCategory::ProcessCreate},
|
||||
{"os.posix_spawn", AuditEventCategory::ProcessCreate},
|
||||
{"os.spawn", AuditEventCategory::ProcessCreate},
|
||||
{"os.system", AuditEventCategory::ProcessCreate},
|
||||
{"os.startfile", AuditEventCategory::ProcessCreate},
|
||||
{"os.startfile/2", AuditEventCategory::ProcessCreate},
|
||||
{"pty.spawn", AuditEventCategory::ProcessCreate},
|
||||
{"subprocess.Popen", AuditEventCategory::ProcessCreate},
|
||||
{"_winapi.CreateProcess", AuditEventCategory::ProcessCreate},
|
||||
{"_posixsubprocess.fork_exec", AuditEventCategory::ProcessCreate},
|
||||
};
|
||||
|
||||
// Returns the category event_name belongs to, or AuditEventCategory::None when it isn't audited.
|
||||
static AuditEventCategory event_category(const std::string& event_name)
|
||||
{
|
||||
const auto it = audit_event_categories.find(event_name);
|
||||
return it == audit_event_categories.end() ? AuditEventCategory::None : it->second;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Path safety
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -344,7 +435,7 @@ void PluginAuditManager::report_violation(const AuditViolation& violation)
|
||||
m_audit_denial_pending = true;
|
||||
|
||||
BOOST_LOG_TRIVIAL(warning) << "[AUDIT BLOCKED] plugin=" << violation.plugin_key << " event=" << violation.event_name
|
||||
<< " path=" << violation.path.string() << " reason=" << violation.reason;
|
||||
<< " reason=" << violation.reason;
|
||||
}
|
||||
|
||||
bool PluginAuditManager::audit_denial_pending() const { return m_audit_denial_pending; }
|
||||
@@ -366,6 +457,34 @@ bool PluginAuditManager::last_violation(AuditViolation& violation) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginAuditManager::has_approved_ancestor(const std::string& plugin_key,
|
||||
const std::vector<std::string>& call_site_ids) const
|
||||
{
|
||||
if (plugin_key.empty() || call_site_ids.empty())
|
||||
return false;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
auto it = m_approved_call_sites.find(plugin_key);
|
||||
if (it == m_approved_call_sites.end())
|
||||
return false;
|
||||
|
||||
for (const auto& id : call_site_ids)
|
||||
if (it->second.count(id))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PluginAuditManager::record_approved_call_sites(const std::string& plugin_key,
|
||||
const std::vector<std::string>& call_site_ids)
|
||||
{
|
||||
if (plugin_key.empty() || call_site_ids.empty())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
auto& approved = m_approved_call_sites[plugin_key];
|
||||
approved.insert(call_site_ids.begin(), call_site_ids.end());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// The C-level audit hook
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -398,38 +517,163 @@ std::string python_path(PyObject* object)
|
||||
return result;
|
||||
}
|
||||
|
||||
void add_filesystem_path(std::vector<boost::filesystem::path>& paths, PyObject* object)
|
||||
std::string python_unicode(PyObject* object)
|
||||
{
|
||||
const std::string path = python_path(object);
|
||||
if (!path.empty())
|
||||
paths.emplace_back(path);
|
||||
if (!object || !PyUnicode_Check(object))
|
||||
return {};
|
||||
const char* text = PyUnicode_AsUTF8(object);
|
||||
if (!text) {
|
||||
PyErr_Clear();
|
||||
return {};
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
std::vector<boost::filesystem::path> filesystem_paths(const std::string& event_name, PyObject* args)
|
||||
std::string python_str(PyObject* object)
|
||||
{
|
||||
std::vector<boost::filesystem::path> paths;
|
||||
if (!object)
|
||||
return {};
|
||||
|
||||
if (event_name == "open") {
|
||||
add_filesystem_path(paths, tuple_item(args, 0));
|
||||
} else if (event_name == "os.rename") {
|
||||
add_filesystem_path(paths, tuple_item(args, 0));
|
||||
add_filesystem_path(paths, tuple_item(args, 1));
|
||||
} else if (event_name == "os.remove") {
|
||||
add_filesystem_path(paths, tuple_item(args, 0));
|
||||
PyObject* str_object = PyObject_Str(object);
|
||||
if (!str_object) {
|
||||
PyErr_Clear();
|
||||
return {};
|
||||
}
|
||||
|
||||
return paths;
|
||||
const std::string result = python_unicode(str_object);
|
||||
Py_DECREF(str_object);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool has_filesystem_permission(const PluginInstallState& state, const boost::filesystem::path& path)
|
||||
std::vector<std::string> call_site_identities(const std::string& plugin_root)
|
||||
{
|
||||
return std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path.string()) !=
|
||||
state.permissions.fs_read.end();
|
||||
std::vector<std::string> ids;
|
||||
if (plugin_root.empty())
|
||||
return ids;
|
||||
|
||||
PyFrameObject* frame = PyEval_GetFrame(); // borrowed reference
|
||||
Py_XINCREF(frame); // normalize to an owned reference for the loop below
|
||||
|
||||
while (frame) {
|
||||
PyCodeObject* code = PyFrame_GetCode(frame); // new reference
|
||||
const std::string filename = python_unicode(reinterpret_cast<PyObject*>(code->co_filename));
|
||||
const bool is_plugin_frame = !filename.empty() && boost::algorithm::starts_with(filename, plugin_root);
|
||||
|
||||
std::string id;
|
||||
if (!is_plugin_frame && !filename.empty()) {
|
||||
const std::string funcname = python_unicode(reinterpret_cast<PyObject*>(code->co_name));
|
||||
id = filename + ":" + funcname + ":" + std::to_string(code->co_firstlineno);
|
||||
}
|
||||
Py_DECREF(code);
|
||||
|
||||
PyFrameObject* back = PyFrame_GetBack(frame); // new reference, or nullptr at the top of the stack
|
||||
Py_DECREF(frame);
|
||||
frame = back;
|
||||
|
||||
if (is_plugin_frame)
|
||||
break;
|
||||
if (!id.empty())
|
||||
ids.push_back(std::move(id));
|
||||
}
|
||||
|
||||
Py_XDECREF(frame); // only holds a reference here if the loop exited via break
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
bool persist_filesystem_permission(const std::string& plugin_key,
|
||||
PluginInstallState& state,
|
||||
const boost::filesystem::path& path)
|
||||
static const std::unordered_set<std::string> two_path_fs_events{
|
||||
"os.rename", "os.link", "os.symlink", "shutil.copyfile",
|
||||
"shutil.copytree", "shutil.copymode", "shutil.copystat", "shutil.move",
|
||||
"shutil.unpack_archive", "_winapi.CreateJunction",
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, std::vector<Py_ssize_t>> audit_target_arg_indices{
|
||||
{"http.client.connect", {1}},
|
||||
{"urllib.Request", {0}},
|
||||
|
||||
{"socket.connect", {1}},
|
||||
{"socket.bind", {1}},
|
||||
{"socket.getaddrinfo", {0}},
|
||||
{"socket.gethostbyname", {0}},
|
||||
{"socket.gethostbyaddr", {0}},
|
||||
{"socket.getnameinfo", {0}},
|
||||
{"socket.getservbyname", {0}},
|
||||
{"socket.getservbyport", {0}},
|
||||
|
||||
{"os.system", {0}},
|
||||
{"subprocess.Popen", {1, 0}},
|
||||
{"os.posix_spawn", {1, 0}},
|
||||
{"os.spawn", {2, 1}},
|
||||
{"os.startfile", {0}},
|
||||
{"pty.spawn", {0}},
|
||||
{"_winapi.CreateProcess", {1, 0}},
|
||||
{"_posixsubprocess.fork_exec", {0}},
|
||||
};
|
||||
|
||||
AuditEventCategory open_category(PyObject* args)
|
||||
{
|
||||
const std::string mode = python_unicode(tuple_item(args, 1));
|
||||
if (!mode.empty() && mode.find_first_of("wax+") == std::string::npos)
|
||||
return AuditEventCategory::FsRead;
|
||||
return AuditEventCategory::FsReadWrite;
|
||||
}
|
||||
|
||||
std::vector<std::string> audit_targets(const std::string& event_name, AuditEventCategory category, PyObject* args)
|
||||
{
|
||||
std::vector<std::string> targets;
|
||||
|
||||
switch (category) {
|
||||
case AuditEventCategory::FsRead:
|
||||
case AuditEventCategory::FsReadWrite:
|
||||
case AuditEventCategory::FsCreate:
|
||||
case AuditEventCategory::FsDelete: {
|
||||
const Py_ssize_t path_count = two_path_fs_events.count(event_name) ? 2 : 1;
|
||||
for (Py_ssize_t index = 0; index < path_count; ++index) {
|
||||
const std::string path = python_path(tuple_item(args, index));
|
||||
if (!path.empty())
|
||||
targets.push_back(path);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const auto it = audit_target_arg_indices.find(event_name);
|
||||
if (it != audit_target_arg_indices.end()) {
|
||||
for (const Py_ssize_t index : it->second) {
|
||||
std::string value = python_str(tuple_item(args, index));
|
||||
if (!value.empty()) {
|
||||
targets.push_back(std::move(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
std::vector<std::string>* permission_list_for(AuditEventCategory category, PluginPermissions& permissions)
|
||||
{
|
||||
switch (category) {
|
||||
case AuditEventCategory::FsRead: return &permissions.fs_read;
|
||||
case AuditEventCategory::FsReadWrite: return &permissions.fs_readwrite;
|
||||
case AuditEventCategory::Http: return &permissions.network_http;
|
||||
case AuditEventCategory::Socket: return &permissions.network_socket;
|
||||
case AuditEventCategory::ProcessCreate: return &permissions.process;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_permission(const std::vector<std::string>& granted, const std::string& target)
|
||||
{
|
||||
return std::find(granted.begin(), granted.end(), target) != granted.end();
|
||||
}
|
||||
|
||||
bool persist_permission(const std::string& plugin_key,
|
||||
PluginInstallState& state,
|
||||
std::vector<std::string>& permission_list,
|
||||
const std::string& target)
|
||||
{
|
||||
PluginDescriptor descriptor;
|
||||
if (!PluginManager::instance().try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty())
|
||||
@@ -445,23 +689,18 @@ bool persist_filesystem_permission(const std::string& plugin_key,
|
||||
state.enabled = true;
|
||||
}
|
||||
|
||||
const std::string path_string = path.string();
|
||||
if (std::find(state.permissions.fs_read.begin(), state.permissions.fs_read.end(), path_string) ==
|
||||
state.permissions.fs_read.end())
|
||||
state.permissions.fs_read.push_back(path_string);
|
||||
if (!has_permission(permission_list, target))
|
||||
permission_list.push_back(target);
|
||||
return write_install_state(boost::filesystem::path(descriptor.plugin_root), state);
|
||||
}
|
||||
|
||||
// Records a blocked event and raises PermissionError in the calling interpreter.
|
||||
int report_denied(PluginAuditManager& mgr,
|
||||
const std::string& event_name,
|
||||
const boost::filesystem::path& target,
|
||||
const AuditDecision& decision)
|
||||
{
|
||||
AuditViolation violation;
|
||||
violation.plugin_key = mgr.current_plugin();
|
||||
violation.event_name = event_name;
|
||||
violation.path = target;
|
||||
violation.reason = decision.reason;
|
||||
mgr.report_violation(violation);
|
||||
|
||||
@@ -469,6 +708,74 @@ int report_denied(PluginAuditManager& mgr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
wxString audit_message(AuditEventCategory category, const wxString& plugin_name, const wxString& event_name,
|
||||
const wxString& target_list)
|
||||
{
|
||||
if (target_list.IsEmpty())
|
||||
return wxString::Format(
|
||||
_L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\".\n\n"
|
||||
"This operation does not expose a target the audit hook can display."),
|
||||
plugin_name, event_name);
|
||||
|
||||
switch (category) {
|
||||
case AuditEventCategory::FsRead:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to read the following file(s):\n%s"), plugin_name, target_list);
|
||||
case AuditEventCategory::FsReadWrite:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to read/write the following file(s):\n%s"), plugin_name, target_list);
|
||||
case AuditEventCategory::FsCreate:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to create the following file(s):\n%s"), plugin_name, target_list);
|
||||
case AuditEventCategory::FsDelete:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to delete the following file(s):\n%s"), plugin_name, target_list);
|
||||
case AuditEventCategory::Http:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to make an HTTP request to:\n%s"), plugin_name, target_list);
|
||||
case AuditEventCategory::Socket:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to open a network connection to:\n%s"), plugin_name, target_list);
|
||||
case AuditEventCategory::ProcessCreate:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting to run the following command(s):\n%s"), plugin_name, target_list);
|
||||
default:
|
||||
return wxString::Format(_L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\"."), plugin_name, event_name);
|
||||
}
|
||||
}
|
||||
|
||||
int decide_audited_event(PluginAuditManager& mgr,
|
||||
PluginInstallState& state,
|
||||
const std::string& plugin_key,
|
||||
const std::string& plugin_name,
|
||||
const std::string& event_name,
|
||||
AuditEventCategory category,
|
||||
const std::vector<std::string>& targets,
|
||||
std::vector<std::string>* permission_list,
|
||||
const std::vector<std::string>& call_site_ids)
|
||||
{
|
||||
std::vector<std::string> unresolved = targets;
|
||||
if (permission_list) {
|
||||
unresolved.clear();
|
||||
for (const auto& target : targets)
|
||||
if (!has_permission(*permission_list, target))
|
||||
unresolved.push_back(target);
|
||||
if (!targets.empty() && unresolved.empty())
|
||||
return 0;
|
||||
}
|
||||
|
||||
wxString target_list;
|
||||
for (const auto& target : unresolved)
|
||||
target_list += wxString::FromUTF8(target.c_str()) + "\n";
|
||||
|
||||
wxMessageDialog dialog(nullptr,
|
||||
audit_message(category, wxString::FromUTF8(plugin_name.c_str()),
|
||||
wxString::FromUTF8(event_name.c_str()), target_list),
|
||||
_L("Plugin permission request"), wxYES_NO | wxICON_WARNING);
|
||||
if (dialog.ShowModal() != wxID_YES)
|
||||
return report_denied(mgr, event_name, {false, "audit permission required"});
|
||||
|
||||
if (permission_list)
|
||||
for (const auto& target : unresolved)
|
||||
persist_permission(plugin_key, state, *permission_list, target);
|
||||
|
||||
mgr.record_approved_call_sites(plugin_key, call_site_ids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace PluginAuditDetail
|
||||
|
||||
int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user_data)
|
||||
@@ -479,12 +786,33 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user
|
||||
|
||||
std::string event_name(event ? event : "");
|
||||
|
||||
if (event_name.empty())
|
||||
return 0;
|
||||
|
||||
// Verbose logging of every audit event (can be noisy)
|
||||
if (mgr->verbose_events) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "[AUDIT EVENT] " << event_name;
|
||||
}
|
||||
|
||||
if (mgr->current_plugin().empty())
|
||||
if (mgr->current_plugin().empty()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "[AUDIT] event=" << event_name << " bypassed (no plugin context)";
|
||||
return 0;
|
||||
}
|
||||
|
||||
PluginDescriptor plugin_descriptor;
|
||||
PluginManager::instance().try_get_plugin_descriptor(mgr->current_plugin(), plugin_descriptor);
|
||||
|
||||
// Some plugins call other audited events, e.g. urlib.request will call socket.connect. So this is so that if urlib.request
|
||||
// was already approved, socket.connect won't trigger another permission dialog.
|
||||
const std::vector<std::string> call_site_ids =
|
||||
PluginAuditDetail::call_site_identities(plugin_descriptor.plugin_root);
|
||||
if (mgr->has_approved_ancestor(mgr->current_plugin(), call_site_ids))
|
||||
return 0;
|
||||
|
||||
// the open function can take in different flags that determine if it is a read or readwrite.
|
||||
const AuditEventCategory event_type =
|
||||
event_name == "open" ? PluginAuditDetail::open_category(args) : event_category(event_name);
|
||||
if (event_type == AuditEventCategory::None)
|
||||
return 0;
|
||||
|
||||
PluginInstallState state;
|
||||
@@ -494,53 +822,16 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user
|
||||
}
|
||||
|
||||
const std::string plugin_name = state.plugin_name.empty() ? mgr->current_plugin() : state.plugin_name;
|
||||
const std::vector<boost::filesystem::path> paths = PluginAuditDetail::filesystem_paths(event_name, args);
|
||||
for (const auto& path : paths) {
|
||||
if (PluginAuditDetail::has_filesystem_permission(state, path))
|
||||
continue;
|
||||
|
||||
wxMessageDialog dialog(
|
||||
nullptr,
|
||||
wxString::Format(_L("Plugin \"%s\" is requesting filesystem access to:\n%s"),
|
||||
wxString::FromUTF8(plugin_name.c_str()),
|
||||
wxString::FromUTF8(path.string().c_str())),
|
||||
_L("Plugin permission request"),
|
||||
wxYES_NO | wxICON_WARNING);
|
||||
if (dialog.ShowModal() == wxID_YES &&
|
||||
PluginAuditDetail::persist_filesystem_permission(mgr->current_plugin(), state, path))
|
||||
continue;
|
||||
const std::vector<std::string> targets = PluginAuditDetail::audit_targets(event_name, event_type, args);
|
||||
std::vector<std::string>* permission_list = PluginAuditDetail::permission_list_for(event_type, state.permissions);
|
||||
|
||||
return PluginAuditDetail::report_denied(
|
||||
*mgr, event_name, path, {false, "filesystem permission required"});
|
||||
}
|
||||
|
||||
if (!paths.empty())
|
||||
return 0;
|
||||
|
||||
wxMessageDialog dialog(
|
||||
nullptr,
|
||||
wxString::Format(
|
||||
_L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\".\n\n"
|
||||
"This operation does not expose a filesystem path to the audit hook."),
|
||||
wxString::FromUTF8(plugin_name.c_str()),
|
||||
wxString::FromUTF8(event_name.c_str())),
|
||||
_L("Plugin permission request"),
|
||||
wxYES_NO | wxICON_WARNING);
|
||||
if (dialog.ShowModal() == wxID_YES)
|
||||
return 0;
|
||||
|
||||
return PluginAuditDetail::report_denied(
|
||||
*mgr, event_name, boost::filesystem::path(), {false, "audit permission required"});
|
||||
return PluginAuditDetail::decide_audited_event(*mgr, state, mgr->current_plugin(), plugin_name, event_name,
|
||||
event_type, targets, permission_list, call_site_ids);
|
||||
}
|
||||
|
||||
void PluginAuditManager::install_hook()
|
||||
{
|
||||
if (PySys_AddAuditHook(audit_hook, this) < 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "[AUDIT] Failed to install CPython audit hook";
|
||||
return;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "[AUDIT] CPython audit hook installed successfully";
|
||||
|
||||
// data_dir() is the only globally-allowed root during plugin execution.
|
||||
// The executable directory and resources directory are intentionally NOT allowed
|
||||
// here: plugins must not access outside data_dir() (G-code plugins additionally get
|
||||
@@ -558,6 +849,12 @@ void PluginAuditManager::install_hook()
|
||||
// (see its comment for why all four config names are denied); the tests seed from it too.
|
||||
for (const auto& name : default_denied_filenames())
|
||||
add_denied_filename(name);
|
||||
|
||||
if (PySys_AddAuditHook(audit_hook, this) < 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "[AUDIT] Failed to install CPython audit hook";
|
||||
return;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "[AUDIT] CPython audit hook installed successfully";
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
Reference in New Issue
Block a user