Avoid out-of-bounds memory access in attached node placement prediction (#13038)

This commit is contained in:
Jude Melton-Houghton
2022-12-10 09:00:27 -05:00
committed by GitHub
parent 504e43e0da
commit 1798ad0ec4

View File

@ -3556,24 +3556,23 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
const ContentFeatures &predicted_f = nodedef->get(id); const ContentFeatures &predicted_f = nodedef->get(id);
// Predict param2 for facedir and wallmounted nodes // Compare core.item_place_node() for what the server does with param2
// Compare core.item_place_node() for what the server does MapNode predicted_node(id, 0, 0);
u8 param2 = 0;
const u8 place_param2 = selected_def.place_param2; const u8 place_param2 = selected_def.place_param2;
if (place_param2) { if (place_param2) {
param2 = place_param2; predicted_node.setParam2(place_param2);
} else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || } else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
v3s16 dir = nodepos - neighborpos; v3s16 dir = nodepos - neighborpos;
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) { if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
param2 = dir.Y < 0 ? 1 : 0; predicted_node.setParam2(dir.Y < 0 ? 1 : 0);
} else if (abs(dir.X) > abs(dir.Z)) { } else if (abs(dir.X) > abs(dir.Z)) {
param2 = dir.X < 0 ? 3 : 2; predicted_node.setParam2(dir.X < 0 ? 3 : 2);
} else { } else {
param2 = dir.Z < 0 ? 5 : 4; predicted_node.setParam2(dir.Z < 0 ? 5 : 4);
} }
} else if (predicted_f.param_type_2 == CPT2_FACEDIR || } else if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR || predicted_f.param_type_2 == CPT2_COLORED_FACEDIR ||
@ -3582,9 +3581,9 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS); v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
if (abs(dir.X) > abs(dir.Z)) { if (abs(dir.X) > abs(dir.Z)) {
param2 = dir.X < 0 ? 3 : 1; predicted_node.setParam2(dir.X < 0 ? 3 : 1);
} else { } else {
param2 = dir.Z < 0 ? 2 : 0; predicted_node.setParam2(dir.Z < 0 ? 2 : 0);
} }
} }
@ -3599,17 +3598,16 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
pp = p + v3s16(0, 1, 0); pp = p + v3s16(0, 1, 0);
} else if (an == 2) { } else if (an == 2) {
if (predicted_f.param_type_2 == CPT2_FACEDIR || if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) { predicted_f.param_type_2 == CPT2_COLORED_FACEDIR ||
pp = p + facedir_dirs[param2]; predicted_f.param_type_2 == CPT2_4DIR ||
} else if (predicted_f.param_type_2 == CPT2_4DIR || predicted_f.param_type_2 == CPT2_COLORED_4DIR) {
predicted_f.param_type_2 == CPT2_COLORED_4DIR ) { pp = p + facedir_dirs[predicted_node.getFaceDir(nodedef)];
pp = p + fourdir_dirs[param2];
} else { } else {
pp = p; pp = p;
} }
} else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || } else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
pp = p + wallmounted_dirs[param2]; pp = p + predicted_node.getWallMountedDir(nodedef);
} else { } else {
pp = p + v3s16(0, -1, 0); pp = p + v3s16(0, -1, 0);
} }
@ -3632,36 +3630,34 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
if (!indexstr.empty()) { if (!indexstr.empty()) {
s32 index = mystoi(indexstr); s32 index = mystoi(indexstr);
if (predicted_f.param_type_2 == CPT2_COLOR) { if (predicted_f.param_type_2 == CPT2_COLOR) {
param2 = index; predicted_node.setParam2(index);
} else if (predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { } else if (predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
// param2 = pure palette index + other // param2 = pure palette index + other
param2 = (index & 0xf8) | (param2 & 0x07); predicted_node.setParam2((index & 0xf8) | (predicted_node.getParam2() & 0x07));
} else if (predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) { } else if (predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
// param2 = pure palette index + other // param2 = pure palette index + other
param2 = (index & 0xe0) | (param2 & 0x1f); predicted_node.setParam2((index & 0xe0) | (predicted_node.getParam2() & 0x1f));
} else if (predicted_f.param_type_2 == CPT2_COLORED_4DIR) { } else if (predicted_f.param_type_2 == CPT2_COLORED_4DIR) {
// param2 = pure palette index + other // param2 = pure palette index + other
param2 = (index & 0xfc) | (param2 & 0x03); predicted_node.setParam2((index & 0xfc) | (predicted_node.getParam2() & 0x03));
} }
} }
} }
// Add node to client map // Add node to client map
MapNode n(id, 0, param2);
try { try {
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
// Don't place node when player would be inside new node // Don't place node when player would be inside new node
// NOTE: This is to be eventually implemented by a mod as client-side Lua // NOTE: This is to be eventually implemented by a mod as client-side Lua
if (!nodedef->get(n).walkable || if (!predicted_f.walkable ||
g_settings->getBool("enable_build_where_you_stand") || g_settings->getBool("enable_build_where_you_stand") ||
(client->checkPrivilege("noclip") && g_settings->getBool("noclip")) || (client->checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
(nodedef->get(n).walkable && (predicted_f.walkable &&
neighborpos != player->getStandingNodePos() + v3s16(0, 1, 0) && neighborpos != player->getStandingNodePos() + v3s16(0, 1, 0) &&
neighborpos != player->getStandingNodePos() + v3s16(0, 2, 0))) { neighborpos != player->getStandingNodePos() + v3s16(0, 2, 0))) {
// This triggers the required mesh update too // This triggers the required mesh update too
client->addNode(p, n); client->addNode(p, predicted_node);
// Report to server // Report to server
client->interact(INTERACT_PLACE, pointed); client->interact(INTERACT_PLACE, pointed);
// A node is predicted, also play a sound // A node is predicted, also play a sound