OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::PluginAuditDetail Namespace Reference

Functions

PyObject * tuple_item (PyObject *args, Py_ssize_t index)
std::string python_unicode (PyObject *object)
bool python_text (PyObject *object, std::string &out)
std::string python_path (PyObject *object)
std::string python_str (PyObject *object)
void collect_stdlib_dirs ()
bool is_stdlib_frame (PyObject *frame)
std::vector< PyObject * > stack_frames ()
void take_returned_frames (std::vector< PyObject * > &held, std::vector< PyObject * > &dropped)
AuditEventCategory open_category (PyObject *args)
std::vector< std::string > audit_targets (const std::string &event_name, AuditEventCategory category, PyObject *args)
std::vector< std::string > * permission_list_for (AuditEventCategory category, bool by_event, PluginPermissions &permissions)
std::string event_grant_key (AuditEventCategory category, const std::string &event_name)
bool tree_grant_root (const std::string &grant, boost::filesystem::path &root)
std::string absolute_tree_grant (const std::string &grant)
bool fs_grant_covers (const std::string &grant, const std::string &target)
bool has_permission (AuditEventCategory category, bool by_event, const std::vector< std::string > &granted, const std::string &target)
bool has_network_permission (const PluginPermissions &permissions, const std::string &target)
bool has_any_network_permission (const PluginPermissions &permissions)
void seed_install_metadata (const PluginDescriptor &descriptor, PluginInstallState &state)
bool persist_permission (const std::string &plugin_key, PluginInstallState &state, AuditEventCategory category, bool by_event, std::vector< std::string > &permission_list, const std::string &target)
int report_denied (PluginAuditManager &mgr, const std::string &event_name, const AuditDecision &decision, const std::string &target={})
wxString audit_message (AuditEventCategory category, const wxString &plugin_name, const wxString &event_name, const wxString &target_list, size_t target_count)
bool prompt_for_targets (AuditEventCategory category, const std::string &plugin_name, const std::string &event_name, const std::vector< std::string > &unresolved)
bool prompt_for_permission_message (const wxString &message)
void persist_grant (const std::string &plugin_key, AuditEventCategory category, bool by_event, const std::vector< std::string > &keys)
static const char * audit_category_name (AuditEventCategory category)
bool request_permission (AuditEventCategory category, const std::string &plugin_key, const std::string &plugin_name, const std::string &event_name, bool by_event, const std::vector< std::string > &keys)
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)
int audit_plugin_event (PluginAuditManager &mgr, const std::string &event_name, AuditEventCategory event_type, PyObject *args)

Variables

static std::vector< boost::filesystem::path > s_stdlib_dirs
static std::vector< boost::filesystem::path > s_site_package_dirs
static std::unordered_map< std::string, bool > s_stdlib_file_verdicts
static const std::unordered_set< std::string > two_path_fs_events
static const std::unordered_map< std::string, std::vector< Py_ssize_t > > audit_target_arg_indices
static PluginAuditManager::PermissionPrompt s_permission_prompt_for_testing
static PluginAuditManager::PermissionMessagePrompt s_permission_message_prompt_for_testing

Function Documentation

◆ absolute_tree_grant()

std::string Slic3r::PluginAuditDetail::absolute_tree_grant ( const std::string & grant)
1166{
1167 boost::filesystem::path root;
1168 if (!tree_grant_root(grant, root) || root.is_absolute())
1169 return grant;
1170
1171 boost::system::error_code ec;
1172 const boost::filesystem::path absolute_root = boost::filesystem::absolute(root, ec);
1173 if (ec || !absolute_root.is_absolute())
1174 return grant;
1175
1176 return (absolute_root.lexically_normal() / "*").string();
1177}
bool tree_grant_root(const std::string &grant, boost::filesystem::path &root)
Definition PluginAuditManager.cpp:1129

References tree_grant_root().

Referenced by Slic3r::PluginAuditManager::request_permissions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ audit_category_name()

const char * Slic3r::PluginAuditDetail::audit_category_name ( AuditEventCategory category)
static
1381{
1382 switch (category) {
1383 case AuditEventCategory::FsRead: return "FsRead";
1384 case AuditEventCategory::FsReadWrite: return "FsReadWrite";
1385 case AuditEventCategory::FsCreate: return "FsCreate";
1386 case AuditEventCategory::FsDelete: return "FsDelete";
1387 case AuditEventCategory::Http: return "Http";
1388 case AuditEventCategory::Socket: return "Socket";
1389 case AuditEventCategory::ProcessCreate: return "ProcessCreate";
1390 case AuditEventCategory::ProcessReplace: return "ProcessReplace";
1391 case AuditEventCategory::Threading: return "Threading";
1392 default: return "None";
1393 }
1394}
@ FsRead
Definition PluginAuditManager.hpp:45
@ FsDelete
Definition PluginAuditManager.hpp:48
@ FsCreate
Definition PluginAuditManager.hpp:47
@ Socket
Definition PluginAuditManager.hpp:50
@ Http
Definition PluginAuditManager.hpp:49
@ ProcessCreate
Definition PluginAuditManager.hpp:51
@ ProcessReplace
Definition PluginAuditManager.hpp:52
@ Threading
Definition PluginAuditManager.hpp:53
@ FsReadWrite
Definition PluginAuditManager.hpp:46

References Slic3r::FsCreate, Slic3r::FsDelete, Slic3r::FsRead, Slic3r::FsReadWrite, Slic3r::Http, Slic3r::ProcessCreate, Slic3r::ProcessReplace, Slic3r::Socket, and Slic3r::Threading.

Referenced by request_permission().

Here is the caller graph for this function:

◆ audit_message()

wxString Slic3r::PluginAuditDetail::audit_message ( AuditEventCategory category,
const wxString & plugin_name,
const wxString & event_name,
const wxString & target_list,
size_t target_count )
1291{
1292 if (target_list.IsEmpty())
1293 return wxString::Format(
1294 _L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\".\n\n"
1295 "This operation does not expose a target the audit hook can display."),
1296 plugin_name, event_name);
1297
1298 switch (category) {
1300 return wxString::Format(_L_PLURAL("Plugin \"%s\" is requesting to read the following file:\n%s",
1301 "Plugin \"%s\" is requesting to read the following files:\n%s", target_count),
1302 plugin_name, target_list);
1304 return wxString::Format(_L_PLURAL("Plugin \"%s\" is requesting to read/write the following file:\n%s",
1305 "Plugin \"%s\" is requesting to read/write the following files:\n%s", target_count),
1306 plugin_name, target_list);
1308 return wxString::Format(_L_PLURAL("Plugin \"%s\" is requesting to create the following file:\n%s",
1309 "Plugin \"%s\" is requesting to create the following files:\n%s", target_count),
1310 plugin_name, target_list);
1312 return wxString::Format(_L_PLURAL("Plugin \"%s\" is requesting to delete the following file:\n%s",
1313 "Plugin \"%s\" is requesting to delete the following files:\n%s", target_count),
1314 plugin_name, target_list);
1316 return wxString::Format(
1317 _L("Plugin \"%s\" is requesting network access to:\n%s\n\n"
1318 "Approval covers HTTP or HTTPS access and raw network connections to the listed hosts. "
1319 "It does not restrict ports. A URL with a path, query or port is covered only for that "
1320 "exact URL."),
1321 plugin_name, target_list);
1323 return wxString::Format(
1324 _L("Plugin \"%s\" is requesting network access to:\n%s\n\n"
1325 "Approval covers raw network connections to the listed hosts. It does not restrict ports."),
1326 plugin_name, target_list);
1328 return wxString::Format(_L_PLURAL("Plugin \"%s\" is requesting to run the following command:\n%s",
1329 "Plugin \"%s\" is requesting to run the following commands:\n%s", target_count),
1330 plugin_name, target_list);
1332 return wxString::Format(_L("Plugin \"%s\" is requesting permission to create a thread."), plugin_name);
1334 return wxString::Format(_L("Plugin \"%s\" is requesting to replace the running application with:\n%s"), plugin_name, target_list);
1335 default:
1336 return wxString::Format(_L("Plugin \"%s\" is requesting permission for the Python audit event \"%s\"."), plugin_name, event_name);
1337 }
1338}
#define _L(s)
Definition OBJ.cpp:34
#define _L_PLURAL(s, plural, n)
Definition I18N.hpp:96

References _L, _L_PLURAL, Slic3r::FsCreate, Slic3r::FsDelete, Slic3r::FsRead, Slic3r::FsReadWrite, Slic3r::Http, Slic3r::ProcessCreate, Slic3r::ProcessReplace, Slic3r::Socket, and Slic3r::Threading.

Referenced by prompt_for_targets(), and Slic3r::PluginAuditManager::request_permissions().

Here is the caller graph for this function:

◆ audit_plugin_event()

int Slic3r::PluginAuditDetail::audit_plugin_event ( PluginAuditManager & mgr,
const std::string & event_name,
AuditEventCategory event_type,
PyObject * args )
1489{
1490 const bool fs_category = is_fs_category(event_type);
1491 const std::vector<std::string> targets = audit_targets(event_name, event_type, args);
1492
1493 // A denied path (secrets, certificates, config files -- see is_denied_path) is an
1494 // unconditional block: checked before the running-operation check below, so no granted
1495 // operation can launder access to one, and before the allowed-root shortcut further down,
1496 // so an allowed root (e.g. the read-only resources folder) cannot make a denied path
1497 // underneath it reachable.
1498 if (fs_category) {
1499 for (const auto& target : targets) {
1500 if (mgr.is_denied_path(boost::filesystem::path(target)))
1501 return report_denied(mgr, event_name, {false, "denied path"}, target);
1502 }
1503 }
1504
1505 // A nested event of an operation already granted, e.g. socket.connect inside an approved
1506 // urlopen(), is not asked again. urllib.Request is always judged on its own URL, so a
1507 // redirect or a nested urlopen() inside a running request is not covered by it.
1508 if (event_name != "urllib.Request" && mgr.covered_by_root_frame())
1509 return 0;
1510
1511 // A filesystem target that resolves entirely inside a pre-determined allowed root -- the
1512 // plugin system's own data_dir() tree (which holds each plugin's storage folder and the
1513 // installed/system profile cache), the read-only bundled resources folder, or a per-call
1514 // scoped root such as the current G-code folder -- is part of the plugin system's normal
1515 // workflow and does not need a prompt.
1516 if (fs_category && !targets.empty()) {
1517 const bool is_write = event_type != AuditEventCategory::FsRead;
1518 const bool all_inside_allowed_root =
1519 std::all_of(targets.begin(), targets.end(), [&](const std::string& target) {
1520 return mgr.check_path_access(boost::filesystem::path(target), is_write).allowed;
1521 });
1522 if (all_inside_allowed_root)
1523 return 0;
1524 }
1525
1526 PluginInstallState state;
1527 const bool have_install_state = PluginManager::instance().get_install_state(mgr.current_plugin(), state);
1528 if (!have_install_state) {
1529 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Failed to get install state for " << mgr.current_plugin();
1530 }
1531
1532 const std::string plugin_name = state.plugin_name.empty() ? mgr.current_plugin() : state.plugin_name;
1533
1534 const int result = decide_audited_event(mgr, state, mgr.current_plugin(), plugin_name, event_name, event_type, targets);
1535
1536 // A granted operation covers its nested events while it runs. A targetless grant names no
1537 // operation, so it covers nothing else.
1538 if (result == 0 && !targets.empty() && operation_root_events.count(event_name))
1539 mgr.record_root_frame();
1540 return result;
1541}
bool is_denied_path(const boost::filesystem::path &candidate) const
Definition PluginAuditManager.cpp:704
std::string current_plugin() const
Definition PluginAuditManager.cpp:543
bool covered_by_root_frame() const
Definition PluginAuditManager.cpp:1677
void record_root_frame()
Definition PluginAuditManager.cpp:1666
static PluginManager & instance()
Definition PluginManager.cpp:74
bool get_install_state(const std::string &plugin_key, PluginInstallState &install_state)
Definition PluginManager.cpp:658
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)
Definition PluginAuditManager.cpp:1444
int report_denied(PluginAuditManager &mgr, const std::string &event_name, const AuditDecision &decision, const std::string &target={})
Definition PluginAuditManager.cpp:1268
std::vector< std::string > audit_targets(const std::string &event_name, AuditEventCategory category, PyObject *args)
Definition PluginAuditManager.cpp:1053
static bool is_fs_category(AuditEventCategory category)
Definition PluginAuditManager.cpp:155
static const std::unordered_set< std::string > operation_root_events
Definition PluginAuditManager.cpp:143

References audit_targets(), Slic3r::PluginAuditManager::covered_by_root_frame(), Slic3r::PluginAuditManager::current_plugin(), decide_audited_event(), Slic3r::FsRead, Slic3r::PluginManager::get_install_state(), Slic3r::PluginManager::instance(), Slic3r::PluginAuditManager::is_denied_path(), Slic3r::is_fs_category(), Slic3r::operation_root_events, Slic3r::PluginInstallState::plugin_name, Slic3r::PluginAuditManager::record_root_frame(), and report_denied().

Referenced by Slic3r::PluginAuditManager::audit_hook().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ audit_targets()

std::vector< std::string > Slic3r::PluginAuditDetail::audit_targets ( const std::string & event_name,
AuditEventCategory category,
PyObject * args )
1054{
1055 std::vector<std::string> targets;
1056
1057 switch (category) {
1062 const Py_ssize_t path_count = two_path_fs_events.count(event_name) ? 2 : 1;
1063 for (Py_ssize_t index = 0; index < path_count; ++index) {
1064 const std::string path = python_path(tuple_item(args, index));
1065 if (!path.empty())
1066 targets.push_back(path);
1067 }
1068 return targets;
1069 }
1071 // Thread creation exposes no user-supplied target. Use a fixed sentinel so the grant
1072 // persists per plugin: the permission list matches targets by exact string, and the
1073 // started function's repr embeds an address that changes every run.
1074 targets.emplace_back(kThreadPermissionTarget);
1075 return targets;
1076 default:
1077 break;
1078 }
1079
1080 const auto it = audit_target_arg_indices.find(event_name);
1081 if (it != audit_target_arg_indices.end()) {
1082 for (const Py_ssize_t index : it->second) {
1083 // None is an argument left out (sendmsg without an address), not a target named "None".
1084 PyObject* const item = tuple_item(args, index);
1085 if (item == Py_None)
1086 continue;
1087 std::string value = python_str(item);
1088 if (!value.empty()) {
1089 targets.push_back(std::move(value));
1090 break;
1091 }
1092 }
1093 }
1094
1095 return targets;
1096}
std::string python_str(PyObject *object)
Definition PluginAuditManager.cpp:912
std::string python_path(PyObject *object)
Definition PluginAuditManager.cpp:895
static const std::unordered_set< std::string > two_path_fs_events
Definition PluginAuditManager.cpp:1012
PyObject * tuple_item(PyObject *args, Py_ssize_t index)
Definition PluginAuditManager.cpp:855
static const std::unordered_map< std::string, std::vector< Py_ssize_t > > audit_target_arg_indices
Definition PluginAuditManager.cpp:1018
constexpr const char * kThreadPermissionTarget
Definition PluginAuditManager.hpp:20

References audit_target_arg_indices, Slic3r::FsCreate, Slic3r::FsDelete, Slic3r::FsRead, Slic3r::FsReadWrite, Slic3r::kThreadPermissionTarget, python_path(), python_str(), Slic3r::Threading, tuple_item(), and two_path_fs_events.

Referenced by audit_plugin_event().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ collect_stdlib_dirs()

void Slic3r::PluginAuditDetail::collect_stdlib_dirs ( )
936{
937 s_stdlib_dirs.clear();
938 s_site_package_dirs.clear();
940
941 PyObject* sysconfig = PyImport_ImportModule("sysconfig");
942 PyObject* paths = sysconfig ? PyObject_CallMethod(sysconfig, "get_paths", nullptr) : nullptr;
943 if (paths && PyDict_Check(paths)) {
944 const auto collect = [paths](const char* key, std::vector<boost::filesystem::path>& out) {
945 const std::string dir = python_unicode(PyDict_GetItemString(paths, key)); // borrowed
946 if (dir.empty())
947 return;
948 boost::system::error_code ec;
949 const boost::filesystem::path resolved = boost::filesystem::weakly_canonical(dir, ec);
950 out.push_back(ec ? boost::filesystem::path(dir) : resolved);
951 };
952 collect("stdlib", s_stdlib_dirs);
953 collect("platstdlib", s_stdlib_dirs);
954 collect("purelib", s_site_package_dirs);
955 collect("platlib", s_site_package_dirs);
956 }
957 Py_XDECREF(paths);
958 Py_XDECREF(sysconfig);
959 if (PyErr_Occurred()) {
960 PyErr_Clear();
961 BOOST_LOG_TRIVIAL(error) << "[AUDIT] Failed to read the stdlib folders from sysconfig";
962 }
963}
static std::vector< boost::filesystem::path > s_stdlib_dirs
Definition PluginAuditManager.cpp:931
std::string python_unicode(PyObject *object)
Definition PluginAuditManager.cpp:862
static std::vector< boost::filesystem::path > s_site_package_dirs
Definition PluginAuditManager.cpp:932
static std::unordered_map< std::string, bool > s_stdlib_file_verdicts
Definition PluginAuditManager.cpp:933

References python_unicode(), s_site_package_dirs, s_stdlib_dirs, and s_stdlib_file_verdicts.

Referenced by Slic3r::PluginAuditManager::install_hook().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ decide_audited_event()

int Slic3r::PluginAuditDetail::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 )
1451{
1452 const bool by_event = targets.empty();
1453 const std::vector<std::string> keys = by_event ? std::vector<std::string>{event_grant_key(category, event_name)} : targets;
1454 std::vector<std::string>* permission_list = permission_list_for(category, by_event, state.permissions);
1455
1456 std::vector<std::string> unresolved = keys;
1457 if (permission_list || is_network_category(category)) {
1458 unresolved.clear();
1459 for (const auto& key : keys) {
1460 // A network grant authorizes a specific host, except for a targetless event such as
1461 // http.client.send, which names no host: any network grant covers that.
1462 const bool granted_network =
1463 is_network_category(category) &&
1464 (by_event ? has_any_network_permission(state.permissions)
1465 : has_network_permission(state.permissions, key));
1466 if (!(permission_list && has_permission(category, by_event, *permission_list, key)) && !granted_network)
1467 unresolved.push_back(key);
1468 }
1469 if (unresolved.empty())
1470 return 0;
1471 }
1472
1473 // Letting a root frame go runs finalizers inside a scope destructor or another event's hook,
1474 // where no dialog may open: what they do must already be granted.
1475 if (mgr.releasing_frames())
1476 return report_denied(mgr, event_name, {false, "audit permission required"});
1477
1478 if (!request_permission(category, plugin_key, plugin_name, event_name, by_event, unresolved))
1479 return report_denied(mgr, event_name, {false, "audit permission required"});
1480
1481 if (permission_list)
1482 for (const auto& key : unresolved)
1483 persist_permission(plugin_key, state, category, by_event, *permission_list, key);
1484 return 0;
1485}
bool releasing_frames() const
Definition PluginAuditManager.cpp:1693
std::vector< std::string > * permission_list_for(AuditEventCategory category, bool by_event, PluginPermissions &permissions)
Definition PluginAuditManager.cpp:1101
bool request_permission(AuditEventCategory category, const std::string &plugin_key, const std::string &plugin_name, const std::string &event_name, bool by_event, const std::vector< std::string > &keys)
Definition PluginAuditManager.cpp:1409
std::string event_grant_key(AuditEventCategory category, const std::string &event_name)
Definition PluginAuditManager.cpp:1120
bool has_any_network_permission(const PluginPermissions &permissions)
Definition PluginAuditManager.cpp:1231
bool persist_permission(const std::string &plugin_key, PluginInstallState &state, AuditEventCategory category, bool by_event, std::vector< std::string > &permission_list, const std::string &target)
Definition PluginAuditManager.cpp:1250
bool has_network_permission(const PluginPermissions &permissions, const std::string &target)
Definition PluginAuditManager.cpp:1223
bool has_permission(AuditEventCategory category, bool by_event, const std::vector< std::string > &granted, const std::string &target)
Definition PluginAuditManager.cpp:1206
static bool is_network_category(AuditEventCategory category)
Definition PluginAuditManager.cpp:171
PluginPermissions permissions
Definition PluginFsUtils.hpp:121

References event_grant_key(), has_any_network_permission(), has_network_permission(), has_permission(), Slic3r::is_network_category(), permission_list_for(), Slic3r::PluginInstallState::permissions, persist_permission(), Slic3r::PluginAuditManager::releasing_frames(), report_denied(), and request_permission().

Referenced by audit_plugin_event().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ event_grant_key()

std::string Slic3r::PluginAuditDetail::event_grant_key ( AuditEventCategory category,
const std::string & event_name )
1121{
1122 return std::string(category_name(category)) + ":" + event_name;
1123}
static const char * category_name(AuditEventCategory category)
Definition PluginAuditManager.cpp:348

References Slic3r::category_name().

Referenced by decide_audited_event().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fs_grant_covers()

bool Slic3r::PluginAuditDetail::fs_grant_covers ( const std::string & grant,
const std::string & target )
1190{
1191 if (grant == target)
1192 return true;
1193 if (target.empty())
1194 return false;
1195
1196 boost::filesystem::path root;
1197 if (!tree_grant_root(grant, root))
1198 return false;
1199
1200 return is_inside_allowed_root(boost::filesystem::path(target), root);
1201}
bool is_inside_allowed_root(const boost::filesystem::path &candidate, const boost::filesystem::path &allowed_root)
Definition PluginAuditManager.cpp:463

References Slic3r::is_inside_allowed_root(), and tree_grant_root().

Referenced by has_permission().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_any_network_permission()

bool Slic3r::PluginAuditDetail::has_any_network_permission ( const PluginPermissions & permissions)
1232{
1233 return !permissions.network_http.empty() || !permissions.network_socket.empty();
1234}
std::vector< std::string > network_socket
Definition PluginFsUtils.hpp:107
std::vector< std::string > network_http
Definition PluginFsUtils.hpp:106

References Slic3r::PluginPermissions::network_http, and Slic3r::PluginPermissions::network_socket.

Referenced by decide_audited_event().

Here is the caller graph for this function:

◆ has_network_permission()

bool Slic3r::PluginAuditDetail::has_network_permission ( const PluginPermissions & permissions,
const std::string & target )
1224{
1227}
static bool network_permission_matches(const std::vector< std::string > &granted, const std::string &target)
Definition PluginAuditManager.cpp:295

References Slic3r::PluginPermissions::network_http, Slic3r::PluginAuditManager::network_permission_matches(), and Slic3r::PluginPermissions::network_socket.

Referenced by decide_audited_event(), and Slic3r::PluginAuditManager::request_permissions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_permission()

bool Slic3r::PluginAuditDetail::has_permission ( AuditEventCategory category,
bool by_event,
const std::vector< std::string > & granted,
const std::string & target )
1208{
1209 const bool fs_bucket =
1210 !by_event && (category == AuditEventCategory::FsRead || category == AuditEventCategory::FsReadWrite);
1211 for (const auto& grant : granted) {
1212 if (grant == target)
1213 return true;
1214 if (fs_bucket && fs_grant_covers(grant, target))
1215 return true;
1216 }
1217 return false;
1218}
bool fs_grant_covers(const std::string &grant, const std::string &target)
Definition PluginAuditManager.cpp:1189

References fs_grant_covers(), Slic3r::FsRead, and Slic3r::FsReadWrite.

Referenced by decide_audited_event(), persist_permission(), and Slic3r::PluginAuditManager::request_permissions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_stdlib_frame()

bool Slic3r::PluginAuditDetail::is_stdlib_frame ( PyObject * frame)
966{
967 PyCodeObject* code = PyFrame_GetCode(reinterpret_cast<PyFrameObject*>(frame)); // new reference
968 const std::string filename = python_unicode(code->co_filename);
969 Py_DECREF(code);
970 return PluginAuditManager::is_stdlib_file(filename);
971}
static bool is_stdlib_file(const std::string &filename)
Definition PluginAuditManager.cpp:1695

References Slic3r::PluginAuditManager::is_stdlib_file(), and python_unicode().

Referenced by Slic3r::PluginAuditManager::covered_by_root_frame(), and Slic3r::PluginAuditManager::record_root_frame().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_category()

AuditEventCategory Slic3r::PluginAuditDetail::open_category ( PyObject * args)
1046{
1047 const std::string mode = python_unicode(tuple_item(args, 1));
1048 if (!mode.empty() && mode.find_first_of("wax+") == std::string::npos)
1051}

References Slic3r::FsRead, Slic3r::FsReadWrite, python_unicode(), and tuple_item().

Referenced by Slic3r::PluginAuditManager::audit_hook().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ permission_list_for()

std::vector< std::string > * Slic3r::PluginAuditDetail::permission_list_for ( AuditEventCategory category,
bool by_event,
PluginPermissions & permissions )
1102{
1103 if (by_event)
1104 return &permissions.events;
1105
1106 switch (category) {
1107 case AuditEventCategory::FsRead: return &permissions.fs_read;
1108 case AuditEventCategory::FsReadWrite: return &permissions.fs_readwrite;
1109 case AuditEventCategory::Http: return &permissions.network_http;
1110 case AuditEventCategory::Socket: return &permissions.network_socket;
1111 case AuditEventCategory::ProcessCreate: return &permissions.process;
1112 case AuditEventCategory::Threading: return &permissions.threading;
1113 case AuditEventCategory::ProcessReplace: return &permissions.process;
1114 default: return nullptr;
1115 }
1116}
std::vector< std::string > process
Definition PluginFsUtils.hpp:108
std::vector< std::string > fs_readwrite
Definition PluginFsUtils.hpp:105
std::vector< std::string > events
Definition PluginFsUtils.hpp:112
std::vector< std::string > threading
Definition PluginFsUtils.hpp:109
std::vector< std::string > fs_read
Definition PluginFsUtils.hpp:104

References Slic3r::PluginPermissions::events, Slic3r::PluginPermissions::fs_read, Slic3r::PluginPermissions::fs_readwrite, Slic3r::FsRead, Slic3r::FsReadWrite, Slic3r::Http, Slic3r::PluginPermissions::network_http, Slic3r::PluginPermissions::network_socket, Slic3r::PluginPermissions::process, Slic3r::ProcessCreate, Slic3r::ProcessReplace, Slic3r::Socket, Slic3r::Threading, and Slic3r::PluginPermissions::threading.

Referenced by decide_audited_event(), persist_grant(), and Slic3r::PluginAuditManager::request_permissions().

Here is the caller graph for this function:

◆ persist_grant()

void Slic3r::PluginAuditDetail::persist_grant ( const std::string & plugin_key,
AuditEventCategory category,
bool by_event,
const std::vector< std::string > & keys )
1364{
1365 PluginInstallState state;
1366 if (!PluginManager::instance().get_install_state(plugin_key, state))
1367 return;
1368
1369 std::vector<std::string>* permission_list = permission_list_for(category, by_event, state.permissions);
1370 if (!permission_list)
1371 return;
1372
1373 for (const auto& key : keys)
1374 persist_permission(plugin_key, state, category, by_event, *permission_list, key);
1375}
Definition PluginFsUtils.hpp:115

References Slic3r::PluginManager::instance(), permission_list_for(), Slic3r::PluginInstallState::permissions, and persist_permission().

Referenced by request_permission().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ persist_permission()

bool Slic3r::PluginAuditDetail::persist_permission ( const std::string & plugin_key,
PluginInstallState & state,
AuditEventCategory category,
bool by_event,
std::vector< std::string > & permission_list,
const std::string & target )
1256{
1257 PluginDescriptor descriptor;
1258 if (!PluginManager::instance().try_get_plugin_descriptor(plugin_key, descriptor) || descriptor.plugin_root.empty())
1259 return false;
1260
1261 seed_install_metadata(descriptor, state);
1262
1263 if (!has_permission(category, by_event, permission_list, target))
1264 permission_list.push_back(target);
1265 return write_install_state(boost::filesystem::path(descriptor.plugin_root), state);
1266}
void seed_install_metadata(const PluginDescriptor &descriptor, PluginInstallState &state)
Definition PluginAuditManager.cpp:1238
bool write_install_state(const boost::filesystem::path &plugin_dir, const PluginInstallState &state)
Definition PluginFsUtils.cpp:859
Definition PluginDescriptor.hpp:53
std::string plugin_root
Definition PluginDescriptor.hpp:62

References has_permission(), Slic3r::PluginManager::instance(), Slic3r::PluginDescriptor::plugin_root, seed_install_metadata(), and Slic3r::write_install_state().

Referenced by decide_audited_event(), and persist_grant().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ prompt_for_permission_message()

bool Slic3r::PluginAuditDetail::prompt_for_permission_message ( const wxString & message)
1356{
1357 wxMessageDialog dialog(nullptr, message, _L("Plugin permissions"), wxYES_NO | wxICON_WARNING);
1358 return dialog.ShowModal() == wxID_YES;
1359}

References _L.

Referenced by Slic3r::PluginAuditManager::request_permissions().

Here is the caller graph for this function:

◆ prompt_for_targets()

bool Slic3r::PluginAuditDetail::prompt_for_targets ( AuditEventCategory category,
const std::string & plugin_name,
const std::string & event_name,
const std::vector< std::string > & unresolved )
1343{
1344 wxString target_list;
1345 for (const auto& target : unresolved)
1346 target_list += wxString::FromUTF8(target.c_str()) + "\n";
1347
1348 return show_permission_dialog(
1349 audit_message(category, wxString::FromUTF8(plugin_name.c_str()), wxString::FromUTF8(event_name.c_str()),
1350 target_list, unresolved.size()),
1351 _L("Plugin permission request"));
1352}
wxString audit_message(AuditEventCategory category, const wxString &plugin_name, const wxString &event_name, const wxString &target_list, size_t target_count)
Definition PluginAuditManager.cpp:1289

References _L, and audit_message().

Referenced by request_permission().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ python_path()

std::string Slic3r::PluginAuditDetail::python_path ( PyObject * object)
896{
897 if (!object)
898 return {};
899
900 PyObject* path_object = PyOS_FSPath(object);
901 if (!path_object) {
902 PyErr_Clear();
903 return {};
904 }
905
906 std::string result;
907 python_text(path_object, result);
908 Py_DECREF(path_object);
909 return result;
910}
bool python_text(PyObject *object, std::string &out)
Definition PluginAuditManager.cpp:876

References python_text().

Referenced by audit_targets().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ python_str()

std::string Slic3r::PluginAuditDetail::python_str ( PyObject * object)
913{
914 if (!object)
915 return {};
916
917 PyObject* str_object = PyObject_Str(object);
918 if (!str_object) {
919 PyErr_Clear();
920 return {};
921 }
922
923 const std::string result = python_unicode(str_object);
924 Py_DECREF(str_object);
925 return result;
926}

References python_unicode().

Referenced by audit_targets().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ python_text()

bool Slic3r::PluginAuditDetail::python_text ( PyObject * object,
std::string & out )
877{
878 if (PyUnicode_Check(object)) {
879 out = python_unicode(object);
880 return true;
881 }
882 if (PyBytes_Check(object)) {
883 const char* value = PyBytes_AsString(object);
884 if (!value) {
885 PyErr_Clear();
886 out.clear();
887 return true;
888 }
889 out = value;
890 return true;
891 }
892 return false;
893}

References python_unicode().

Referenced by python_path().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ python_unicode()

std::string Slic3r::PluginAuditDetail::python_unicode ( PyObject * object)
863{
864 if (!object || !PyUnicode_Check(object))
865 return {};
866 const char* text = PyUnicode_AsUTF8(object);
867 if (!text) {
868 PyErr_Clear();
869 return {};
870 }
871 return text;
872}

Referenced by collect_stdlib_dirs(), is_stdlib_frame(), open_category(), python_str(), and python_text().

Here is the caller graph for this function:

◆ report_denied()

int Slic3r::PluginAuditDetail::report_denied ( PluginAuditManager & mgr,
const std::string & event_name,
const AuditDecision & decision,
const std::string & target = {} )
1271 {})
1272{
1273 AuditViolation violation;
1274 violation.plugin_key = mgr.current_plugin();
1275 violation.event_name = event_name;
1276 violation.reason = decision.reason;
1277 mgr.report_violation(violation);
1278
1279 std::string message = "Plugin attempted audited operation \"" + event_name + "\" without permission";
1280 if (!decision.reason.empty())
1281 message += ": " + decision.reason;
1282 if (!target.empty())
1283 message += ": " + target;
1284
1285 PyErr_SetString(PyExc_PermissionError, message.c_str());
1286 return -1;
1287}
void report_violation(const AuditViolation &violation)
Definition PluginAuditManager.cpp:820
std::string reason
Definition PluginAuditManager.hpp:24
std::string event_name
Definition PluginAuditManager.hpp:29
std::string reason
Definition PluginAuditManager.hpp:30
std::string plugin_key
Definition PluginAuditManager.hpp:28
Definition PluginAuditManager.hpp:27

Referenced by audit_plugin_event(), and decide_audited_event().

Here is the caller graph for this function:

◆ request_permission()

bool Slic3r::PluginAuditDetail::request_permission ( AuditEventCategory category,
const std::string & plugin_key,
const std::string & plugin_name,
const std::string & event_name,
bool by_event,
const std::vector< std::string > & keys )
1411{
1412 const std::vector<std::string> shown = by_event ? std::vector<std::string>{} : keys;
1413 std::string targets_text = by_event ? "<none>" : "";
1414 for (const auto& target : shown) {
1415 if (!targets_text.empty())
1416 targets_text += ", ";
1417 targets_text += target;
1418 }
1419
1420 BOOST_LOG_TRIVIAL(info) << "[AUDIT PROMPT] plugin=" << plugin_key << " event=" << event_name
1421 << " category=" << audit_category_name(category) << " targets=[" << targets_text << "]"
1422 << (by_event && !keys.empty() ? " grant=" + keys.front() : std::string{});
1423
1425 return s_permission_prompt_for_testing(event_name, shown);
1426
1427 if (wxTheApp == nullptr || GUI::wxGetApp().is_closing())
1428 return false;
1429
1430 if (wxIsMainThread())
1431 return prompt_for_targets(category, plugin_name, event_name, shown);
1432
1433 GUI::wxGetApp().CallAfter([category, plugin_key, plugin_name, event_name, by_event, keys, shown]() {
1434 if (wxTheApp == nullptr || GUI::wxGetApp().is_closing())
1435 return;
1436 if (prompt_for_targets(category, plugin_name, event_name, shown))
1437 persist_grant(plugin_key, category, by_event, keys);
1438 });
1439 return false;
1440}
static const char * audit_category_name(AuditEventCategory category)
Definition PluginAuditManager.cpp:1380
void persist_grant(const std::string &plugin_key, AuditEventCategory category, bool by_event, const std::vector< std::string > &keys)
Definition PluginAuditManager.cpp:1363
bool prompt_for_targets(AuditEventCategory category, const std::string &plugin_name, const std::string &event_name, const std::vector< std::string > &unresolved)
Definition PluginAuditManager.cpp:1341
static PluginAuditManager::PermissionPrompt s_permission_prompt_for_testing
Definition PluginAuditManager.cpp:1377

References audit_category_name(), persist_grant(), prompt_for_targets(), and s_permission_prompt_for_testing.

Referenced by decide_audited_event().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ seed_install_metadata()

void Slic3r::PluginAuditDetail::seed_install_metadata ( const PluginDescriptor & descriptor,
PluginInstallState & state )
1239{
1240 if (!state.plugin_name.empty())
1241 return;
1242
1243 state.installed_from = descriptor.is_cloud_plugin() ? "cloud" : "local";
1244 state.installed_version = !descriptor.installed_version.empty() ? descriptor.installed_version : descriptor.version;
1245 state.plugin_name = descriptor.name;
1246 state.cloud_uuid = descriptor.cloud_uuid();
1247 state.enabled = true;
1248}
std::string installed_from
Definition PluginFsUtils.hpp:116
std::string cloud_uuid
Definition PluginFsUtils.hpp:119
std::string plugin_name
Definition PluginFsUtils.hpp:118
bool enabled
Definition PluginFsUtils.hpp:123
std::string installed_version
Definition PluginFsUtils.hpp:117
bool is_cloud_plugin() const
Definition PluginDescriptor.hpp:82
std::string version
Definition PluginDescriptor.hpp:58
std::string name
Definition PluginDescriptor.hpp:55
std::string installed_version
Definition PluginDescriptor.hpp:60
std::string cloud_uuid() const
Definition PluginDescriptor.hpp:83

References Slic3r::PluginDescriptor::cloud_uuid(), Slic3r::PluginInstallState::cloud_uuid, Slic3r::PluginInstallState::enabled, Slic3r::PluginInstallState::installed_from, Slic3r::PluginDescriptor::installed_version, Slic3r::PluginInstallState::installed_version, Slic3r::PluginDescriptor::is_cloud_plugin(), Slic3r::PluginDescriptor::name, Slic3r::PluginInstallState::plugin_name, and Slic3r::PluginDescriptor::version.

Referenced by persist_permission(), and Slic3r::PluginAuditManager::request_permissions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stack_frames()

std::vector< PyObject * > Slic3r::PluginAuditDetail::stack_frames ( )
976{
977 std::vector<PyObject*> frames;
978 PyFrameObject* frame = PyEval_GetFrame(); // borrowed reference
979 Py_XINCREF(frame); // normalize to an owned reference for the loop below
980 while (frame) {
981 frames.push_back(reinterpret_cast<PyObject*>(frame));
982 PyFrameObject* back = PyFrame_GetBack(frame); // new reference, or nullptr at the top of the stack
983 Py_DECREF(frame);
984 frame = back;
985 }
986 return frames;
987}

Referenced by Slic3r::PluginAuditManager::covered_by_root_frame(), and take_returned_frames().

Here is the caller graph for this function:

◆ take_returned_frames()

void Slic3r::PluginAuditDetail::take_returned_frames ( std::vector< PyObject * > & held,
std::vector< PyObject * > & dropped )
993{
994 if (held.empty())
995 return;
996
997 const std::vector<PyObject*> stack = stack_frames();
998 const auto running = [&stack](PyObject* frame) {
999 if (std::find(stack.begin(), stack.end(), frame) != stack.end())
1000 return true;
1001 // NULL once the generator has finished or been deleted: its frame then owns its own data.
1002 PyObject* generator = PyFrame_GetGenerator(reinterpret_cast<PyFrameObject*>(frame)); // new reference
1003 const bool suspended = generator != nullptr;
1004 Py_XDECREF(generator);
1005 return suspended;
1006 };
1007 const auto returned = std::stable_partition(held.begin(), held.end(), running);
1008 dropped.insert(dropped.end(), returned, held.end());
1009 held.erase(returned, held.end());
1010}
std::vector< PyObject * > stack_frames()
Definition PluginAuditManager.cpp:975

References stack_frames().

Referenced by Slic3r::PluginAuditManager::audit_hook().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tree_grant_root()

bool Slic3r::PluginAuditDetail::tree_grant_root ( const std::string & grant,
boost::filesystem::path & root )
1130{
1131 if (grant.size() < 2 || grant.back() != '*' || grant.find('*') != grant.size() - 1)
1132 return false;
1133
1134 const boost::filesystem::path path(grant);
1135 if (path.filename() != "*")
1136 return false;
1137
1138 const boost::filesystem::path parent = path.parent_path();
1139 if (parent.empty())
1140 return false;
1141
1142 // Never resolve ".." here: a grant shown to the user as "/a/../*" must not silently become
1143 // the root or another ancestor. Without a wildcard the string still matches verbatim.
1144 for (const boost::filesystem::path& component : parent) {
1145 if (component == "..")
1146 return false;
1147 }
1148
1149 // Rebuild from the components so "." and duplicate separators do not affect the canonical
1150 // comparison below.
1151 boost::filesystem::path normalized;
1152 for (const boost::filesystem::path& component : parent.lexically_normal()) {
1153 if (!component.empty())
1154 normalized /= component;
1155 }
1156 root = std::move(normalized);
1157 return !root.empty();
1158}

Referenced by absolute_tree_grant(), and fs_grant_covers().

Here is the caller graph for this function:

◆ tuple_item()

PyObject * Slic3r::PluginAuditDetail::tuple_item ( PyObject * args,
Py_ssize_t index )
856{
857 if (!args || !PyTuple_Check(args) || index < 0 || index >= PyTuple_GET_SIZE(args))
858 return nullptr;
859 return PyTuple_GET_ITEM(args, index);
860}

Referenced by audit_targets(), and open_category().

Here is the caller graph for this function:

Variable Documentation

◆ audit_target_arg_indices

const std::unordered_map<std::string, std::vector<Py_ssize_t> > Slic3r::PluginAuditDetail::audit_target_arg_indices
static
Initial value:
{
{"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}},
{"socket.sendto", {1}},
{"socket.sendmsg", {1}},
{"os.system", {0}},
{"subprocess.Popen", {1, 0}},
{"os.posix_spawn", {1, 0}},
{"os.spawn", {2, 1}},
{"os.startfile", {0}},
{"os.startfile/2", {0}},
{"pty.spawn", {0}},
{"_winapi.CreateProcess", {1, 0}},
{"_posixsubprocess.fork_exec", {0}},
{"os.exec", {0}},
}
1018 {
1019 {"http.client.connect", {1}},
1020 {"urllib.Request", {0}},
1021
1022 {"socket.connect", {1}},
1023 {"socket.bind", {1}},
1024 {"socket.getaddrinfo", {0}},
1025 {"socket.gethostbyname", {0}},
1026 {"socket.gethostbyaddr", {0}},
1027 {"socket.getnameinfo", {0}},
1028 {"socket.getservbyname", {0}},
1029 {"socket.getservbyport", {0}},
1030 {"socket.sendto", {1}},
1031 {"socket.sendmsg", {1}},
1032
1033 {"os.system", {0}},
1034 {"subprocess.Popen", {1, 0}},
1035 {"os.posix_spawn", {1, 0}},
1036 {"os.spawn", {2, 1}},
1037 {"os.startfile", {0}},
1038 {"os.startfile/2", {0}},
1039 {"pty.spawn", {0}},
1040 {"_winapi.CreateProcess", {1, 0}},
1041 {"_posixsubprocess.fork_exec", {0}},
1042 {"os.exec", {0}},
1043};

Referenced by audit_targets().

◆ s_permission_message_prompt_for_testing

◆ s_permission_prompt_for_testing

PluginAuditManager::PermissionPrompt Slic3r::PluginAuditDetail::s_permission_prompt_for_testing
static

◆ s_site_package_dirs

std::vector<boost::filesystem::path> Slic3r::PluginAuditDetail::s_site_package_dirs
static

◆ s_stdlib_dirs

std::vector<boost::filesystem::path> Slic3r::PluginAuditDetail::s_stdlib_dirs
static

◆ s_stdlib_file_verdicts

std::unordered_map<std::string, bool> Slic3r::PluginAuditDetail::s_stdlib_file_verdicts
static

◆ two_path_fs_events

const std::unordered_set<std::string> Slic3r::PluginAuditDetail::two_path_fs_events
static
Initial value:
{
"os.rename", "os.link", "os.symlink", "shutil.copyfile",
"shutil.copytree", "shutil.copymode", "shutil.copystat", "shutil.move",
"shutil.unpack_archive", "_winapi.CreateJunction",
}
1012 {
1013 "os.rename", "os.link", "os.symlink", "shutil.copyfile",
1014 "shutil.copytree", "shutil.copymode", "shutil.copystat", "shutil.move",
1015 "shutil.unpack_archive", "_winapi.CreateJunction",
1016};

Referenced by audit_targets().