Extensions: prevent recursive file removal for corrupt repositories

When removing a repository & files a valid module name was assumed.
While this should always be the case, add an additional check so in
the unlikely event of memory/file corruption (especially `..`)
recursively removing files outside the repository is never allowed.
This commit is contained in:
Campbell Barton 2024-06-26 14:22:21 +10:00
parent 2075174496
commit f5aaee39d2
3 changed files with 35 additions and 0 deletions

@ -106,6 +106,13 @@ size_t BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo
char *dirpath,
int dirpath_maxncpy);
/**
* Check the module name is valid, while this should always be the case,
* use this as an additional safely check before performing destructive operations
* such as recursive file removal to prevent file/memory corruption causing user data loss.
*/
bool BKE_preferences_extension_repo_module_is_valid(const bUserExtensionRepo *repo);
bUserExtensionRepo *BKE_preferences_extension_repo_find_index(const UserDef *userdef, int index);
bUserExtensionRepo *BKE_preferences_extension_repo_find_by_module(const UserDef *userdef,
const char *module);

@ -264,6 +264,21 @@ void BKE_preferences_extension_repo_module_set(UserDef *userdef,
sizeof(repo->module));
}
bool BKE_preferences_extension_repo_module_is_valid(const bUserExtensionRepo *repo)
{
/* NOTE: this should only ever return false in the case of corrupt file/memory
* and can be considered an exceptional situation. */
char module_test[sizeof(bUserExtensionRepo::module)];
const size_t module_len = strncpy_py_module(module_test, repo->module, sizeof(repo->module));
if (module_len == 0) {
return false;
}
if (module_len != BLI_strnlen(repo->module, sizeof(repo->module))) {
return false;
}
return true;
}
void BKE_preferences_extension_repo_custom_dirpath_set(bUserExtensionRepo *repo, const char *path)
{
STRNCPY(repo->custom_dirpath, path);

@ -662,6 +662,19 @@ static int preferences_extension_repo_remove_exec(bContext *C, wmOperator *op)
}
}
if (remove_files) {
if (!BKE_preferences_extension_repo_module_is_valid(repo)) {
BKE_reportf(op->reports,
RPT_WARNING,
/* Account for it not being null terminated. */
"Unable to remove files, the module name \"%.*s\" is invalid and "
"could remove non-repository files",
int(sizeof(repo->module)),
repo->module);
remove_files = false;
}
}
if (remove_files) {
char dirpath[FILE_MAX];
BKE_preferences_extension_repo_dirpath_get(repo, dirpath, sizeof(dirpath));