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.
This commit is contained in:
savilli 2022-09-16 13:20:14 +02:00 committed by sfan5
parent b9f6832347
commit 1e0520074c

@ -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