diff options
author | savilli <78875209+savilli@users.noreply.github.com> | 2022-09-16 13:20:14 +0200 |
---|---|---|
committer | sfan5 <sfan5@live.de> | 2022-09-16 19:18:51 +0200 |
commit | 1e0520074c24f01a538b376377b178e0ee3d1355 (patch) | |
tree | 5b49073b94e2c59777b298975316d96328788f7e | |
parent | b9f6832347e5a0ca9e10f0d45b2eb1a4c5d82d28 (diff) | |
download | minetest-1e0520074c24f01a538b376377b178e0ee3d1355.tar.gz minetest-1e0520074c24f01a538b376377b178e0ee3d1355.tar.bz2 minetest-1e0520074c24f01a538b376377b178e0ee3d1355.zip |
Fix UAF in craft recipes (#12763)
If you call minetest.clear_craft after minetest.register_alias_force, the craft definition reference may not be removed from m_output_craft_definitions leading to UAF.
-rw-r--r-- | src/craftdef.cpp | 35 |
1 files changed, 20 insertions, 15 deletions
diff --git a/src/craftdef.cpp b/src/craftdef.cpp index c05a0cfb7..053e73bea 100644 --- a/src/craftdef.cpp +++ b/src/craftdef.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes.h" #include "log.h" #include <sstream> -#include <set> +#include <unordered_set> #include <algorithm> #include "gamedef.h" #include "inventory.h" @@ -1026,26 +1026,31 @@ public: // Recipes are not yet hashed at this point std::vector<CraftDefinition *> &defs = m_craft_defs[(int)CRAFT_HASH_TYPE_UNHASHED][0]; + std::unordered_set<const CraftDefinition *> defs_to_remove; std::vector<CraftDefinition *> new_defs; - bool got_hit = false; + for (auto def : defs) { - if (!def->check(input, gamedef)) { + if (def->check(input, gamedef)) + defs_to_remove.insert(def); + else new_defs.push_back(def); - continue; - } - got_hit = true; - std::string output = def->getOutput(input, gamedef).item; - delete def; - auto it = m_output_craft_definitions.find(craftGetItemName(output, gamedef)); - if (it == m_output_craft_definitions.end()) - continue; - std::vector<CraftDefinition *> &outdefs = it->second; - outdefs.erase(std::remove(outdefs.begin(), outdefs.end(), def), outdefs.end()); } - if (got_hit) + + if (!defs_to_remove.empty()) { + for (auto def : defs_to_remove) + delete def; + defs.swap(new_defs); - return got_hit; + for (auto &output : m_output_craft_definitions) { + std::vector<CraftDefinition *> &outdefs = output.second; + outdefs.erase(std::remove_if(outdefs.begin(), outdefs.end(), [&](const CraftDefinition* def) { + return defs_to_remove.find(def) != defs_to_remove.end(); + }), outdefs.end()); + } + } + + return !defs_to_remove.empty(); } virtual std::string dump() const |