From a9bc7dc405df04d5a3cb5fe5de43190200dc692d Mon Sep 17 00:00:00 2001 From: Zeno- Date: Mon, 30 May 2016 22:37:40 +1000 Subject: Remove unused code in s_security.cpp (#4172) Note that the macro CHECK_FILE_ERR implements the code removed --- src/script/cpp_api/s_security.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 730235c7b..e117a4811 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -249,8 +249,8 @@ bool ScriptApiSecurity::isSecure(lua_State *L) #define CHECK_FILE_ERR(ret, fp) \ if (ret) { \ - if (fp) std::fclose(fp); \ lua_pushfstring(L, "%s: %s", path, strerror(errno)); \ + if (fp) std::fclose(fp); \ return false; \ } @@ -291,20 +291,12 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path) // Read the file int ret = std::fseek(fp, 0, SEEK_END); CHECK_FILE_ERR(ret, fp); - if (ret) { - std::fclose(fp); - lua_pushfstring(L, "%s: %s", path, strerror(errno)); - return false; - } + size_t size = std::ftell(fp) - start; char *code = new char[size]; ret = std::fseek(fp, start, SEEK_SET); CHECK_FILE_ERR(ret, fp); - if (ret) { - std::fclose(fp); - lua_pushfstring(L, "%s: %s", path, strerror(errno)); - return false; - } + size_t num_read = std::fread(code, 1, size, fp); if (path) { std::fclose(fp); -- cgit v1.2.3 From dac40af6eeeb7205d507046fd4d9ae06ae182095 Mon Sep 17 00:00:00 2001 From: Diego Martinez Date: Mon, 4 Jan 2016 22:49:11 -0300 Subject: Server: Add reason for leave to `on_leaveplayer` callbacks --- doc/lua_api.txt | 3 ++- src/script/cpp_api/s_player.cpp | 6 ++++-- src/script/cpp_api/s_player.h | 2 +- src/server.cpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/script/cpp_api') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index ea47d0044..d89b0bf7b 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1912,8 +1912,9 @@ Call these functions only at load time! * If it returns a string, the player is disconnected with that string as reason * `minetest.register_on_joinplayer(func(ObjectRef))` * Called when a player joins the game -* `minetest.register_on_leaveplayer(func(ObjectRef))` +* `minetest.register_on_leaveplayer(func(ObjectRef, timed_out))` * Called when a player leaves the game + * `timed_out`: True for timeout, false for other reasons. * `minetest.register_on_cheat(func(ObjectRef, cheat))` * Called when a player cheats * `cheat`: `{type=}`, where `` is one of: diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp index 807430678..a8c07476c 100644 --- a/src/script/cpp_api/s_player.cpp +++ b/src/script/cpp_api/s_player.cpp @@ -135,7 +135,8 @@ void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player) runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); } -void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player) +void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player, + bool timeout) { SCRIPTAPI_PRECHECKHEADER @@ -144,7 +145,8 @@ void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player) lua_getfield(L, -1, "registered_on_leaveplayers"); // Call callbacks objectrefGetOrCreate(L, player); - runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); + lua_pushboolean(L, timeout); + runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); } void ScriptApiPlayer::on_cheat(ServerActiveObject *player, diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h index 2e4dc2222..86ee1b024 100644 --- a/src/script/cpp_api/s_player.h +++ b/src/script/cpp_api/s_player.h @@ -38,7 +38,7 @@ public: bool on_prejoinplayer(const std::string &name, const std::string &ip, std::string *reason); void on_joinplayer(ServerActiveObject *player); - void on_leaveplayer(ServerActiveObject *player); + void on_leaveplayer(ServerActiveObject *player, bool timeout); void on_cheat(ServerActiveObject *player, const std::string &cheat_type); bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter, float time_from_last_punch, diff --git a/src/server.cpp b/src/server.cpp index ada45dc68..f7f698d50 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2683,7 +2683,7 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason) PlayerSAO *playersao = player->getPlayerSAO(); assert(playersao); - m_script->on_leaveplayer(playersao); + m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT); playersao->disconnected(); } -- cgit v1.2.3 From 48b3bb980d4a026d32739acc1982f16e3c303c5b Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 28 Jul 2016 08:56:22 +0100 Subject: couple of memory leaks fixes. --- src/script/cpp_api/s_security.cpp | 18 +++++++++++++++++- src/sound_openal.cpp | 1 + src/unittest/test_map_settings_manager.cpp | 4 +++- src/util/areastore.cpp | 1 + src/util/srp.cpp | 2 +- 5 files changed, 23 insertions(+), 3 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index e117a4811..0e64c4c61 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -285,6 +285,10 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path) if (c == LUA_SIGNATURE[0]) { lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); + std::fclose(fp); + if (path) { + delete [] chunk_name; + } return false; } @@ -295,7 +299,15 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path) size_t size = std::ftell(fp) - start; char *code = new char[size]; ret = std::fseek(fp, start, SEEK_SET); - CHECK_FILE_ERR(ret, fp); + if (ret) { + lua_pushfstring(L, "%s: %s", path, strerror(errno)); + std::fclose(fp); + delete [] code; + if (path) { + delete [] chunk_name; + } + return false; + } size_t num_read = std::fread(code, 1, size, fp); if (path) { @@ -303,6 +315,10 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path) } if (num_read != size) { lua_pushliteral(L, "Error reading file to load."); + delete [] code; + if (path) { + delete [] chunk_name; + } return false; } diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp index e2b6d937a..1832a0c77 100644 --- a/src/sound_openal.cpp +++ b/src/sound_openal.cpp @@ -144,6 +144,7 @@ SoundBuffer *load_opened_ogg_file(OggVorbis_File *oggFile, ov_clear(oggFile); infostream << "Audio: Error decoding " << filename_for_logging << std::endl; + delete snd; return NULL; } diff --git a/src/unittest/test_map_settings_manager.cpp b/src/unittest/test_map_settings_manager.cpp index 9292bf87c..4f5ac80f2 100644 --- a/src/unittest/test_map_settings_manager.cpp +++ b/src/unittest/test_map_settings_manager.cpp @@ -75,8 +75,10 @@ std::string read_file_to_string(const std::string &filepath) fseek(f, 0, SEEK_END); long filesize = ftell(f); - if (filesize == -1) + if (filesize == -1) { + fclose(f); return ""; + } rewind(f); buf.resize(filesize); diff --git a/src/util/areastore.cpp b/src/util/areastore.cpp index 58f08a8c2..cef67da2c 100644 --- a/src/util/areastore.cpp +++ b/src/util/areastore.cpp @@ -95,6 +95,7 @@ void AreaStore::deserialize(std::istream &is) is.read(data, data_len); a.data = std::string(data, data_len); insertArea(&a); + delete [] data; } } diff --git a/src/util/srp.cpp b/src/util/srp.cpp index 0d3c938a3..77c1816e8 100644 --- a/src/util/srp.cpp +++ b/src/util/srp.cpp @@ -542,7 +542,7 @@ static SRP_Result fill_buff() if (!fp) return SRP_ERR; - if (fread(g_rand_buff, sizeof(g_rand_buff), 1, fp) != 1) return SRP_ERR; + if (fread(g_rand_buff, sizeof(g_rand_buff), 1, fp) != 1) { fclose(fp); return SRP_ERR; } if (fclose(fp)) return SRP_ERR; #endif return SRP_OK; -- cgit v1.2.3 From e58a55aa82dfc66325a694dcc3519d3c0f3388a6 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 10 Dec 2015 22:58:11 -0800 Subject: Make plantlike drawtype more fun Adds several new ways that the plantlike drawtype mesh can be changed. This requires paramtype2 = "meshoptions" to be set in the node definition. The drawtype for these nodes should be "plantlike". These modifications are all done using param2. This field is now a complex bitfield that allows some or more of the combinations to be chosen, and the mesh draw code will choose the options based as neeeded for each plantlike node. bit layout: bits 0, 1 and 2 (values 0x1 through 0x7) are for choosing the plant mesh shape: 0 - ordinary plantlike plant ("x" shaped) 1 - ordinary plant, but rotated 45 degrees ("+" shaped) 2 - a plant with 3 faces ("*" shaped) 3 - a plant with 4 faces ("#" shaped) 4 - a plant with 4 faces ("#" shaped, leaning outwards) 5 through 7 are unused and reserved for future mesh shapes. bit 3 (0x8) causes the plant to be randomly offset in the x,z plane. The plant should fall within the 1x1x1 nodebox if regularly sized. bit 4 (0x10) causes the plant mesh to grow by sqrt(2), and will cause the plant mesh to fill out 1x1x1, and appear slightly larger. Texture makers will want to make their plant texture 23x16 pixels to have the best visual fit in 1x1x1 size. bit 5 (0x20) causes each face of the plant to have a slight negative Y offset in position, descending up to 0.125 downwards into the node below. Because this is per face, this causes the plant model to be less symmetric. bit 6 (0x40) through bit 7 (0x80) are unused and reserved for future use. !(https://youtu.be/qWuI664krsI) --- doc/lua_api.txt | 16 +++++ src/content_mapblock.cpp | 152 +++++++++++++++++++++++++++++++++++++++--- src/network/networkprotocol.h | 4 +- src/nodedef.cpp | 5 +- src/nodedef.h | 2 + src/script/cpp_api/s_node.cpp | 1 + 6 files changed, 167 insertions(+), 13 deletions(-) (limited to 'src/script/cpp_api') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 38f19aadc..440edd963 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -578,6 +578,22 @@ node definition: ^ The rotation of this node is stored in param2. Plants are rotated this way. Values range 0 - 179. The value stored in param2 is multiplied by two to get the actual rotation of the node. + paramtype2 == "meshoptions" + ^ Only valid for "plantlike". The value of param2 becomes a bitfield which can + be used to change how the client draws plantlike nodes. Bits 0, 1 and 2 form + a mesh selector. Currently the following meshes are choosable: + 0 = a "x" shaped plant (ordinary plant) + 1 = a "+" shaped plant (just rotated 45 degrees) + 2 = a "*" shaped plant with 3 faces instead of 2 + 3 = a "#" shaped plant with 4 faces instead of 2 + 4 = a "#" shaped plant with 4 faces that lean outwards + 5-7 are unused and reserved for future meshes. + Bits 3 through 7 are optional flags that can be combined and give these + effects: + bit 3 (0x08) - Makes the plant slightly vary placement horizontally + bit 4 (0x10) - Makes the plant mesh 1.4x larger + bit 5 (0x20) - Moves each face randomly a small bit down (1/8 max) + bits 6-7 are reserved for future use. collision_box = { type = "fixed", fixed = { diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 6a83bd8f3..b86b97822 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "gamedef.h" #include "log.h" +#include "noise.h" // Create a cuboid. @@ -1104,6 +1105,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data, break;} case NDT_PLANTLIKE: { + PseudoRandom rng(x<<8 | z | y<<16); + TileSpec tile = getNodeTileN(n, p, 0, data); tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; @@ -1111,9 +1114,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data, video::SColor c = MapBlock_LightColor(255, l, f.light_source); float s = BS / 2 * f.visual_scale; + // add sqrt(2) visual scale + if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x10) != 0)) + s *= 1.41421; + + float random_offset_X = .0; + float random_offset_Z = .0; + if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) { + random_offset_X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145); + random_offset_Z = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145); + } - for (int j = 0; j < 2; j++) - { + for (int j = 0; j < 4; j++) { video::S3DVertex vertices[4] = { video::S3DVertex(-s,-BS/2, 0, 0,0,0, c, 0,1), @@ -1121,28 +1133,146 @@ void mapblock_mesh_generate_special(MeshMakeData *data, video::S3DVertex( s,-BS/2 + s*2,0, 0,0,0, c, 1,0), video::S3DVertex(-s,-BS/2 + s*2,0, 0,0,0, c, 0,0), }; + float rotate_degree = 0; + u8 p2mesh = 0; if (f.param_type_2 == CPT2_DEGROTATE) rotate_degree = n.param2 * 2; - - if (j == 0) { - for(u16 i = 0; i < 4; i++) - vertices[i].Pos.rotateXZBy(46 + rotate_degree); - } else if (j == 1) { - for(u16 i = 0; i < 4; i++) - vertices[i].Pos.rotateXZBy(-44 + rotate_degree); + else if (f.param_type_2 != CPT2_MESHOPTIONS) { + if (j == 0) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(46 + rotate_degree); + } else if (j == 1) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(-44 + rotate_degree); + } + } else { + p2mesh = n.param2 & 0x7; + switch (p2mesh) { + case 0: + // x + if (j == 0) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(46); + } else if (j == 1) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(-44); + } + break; + case 1: + // + + if (j == 0) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(91); + } else if (j == 1) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(1); + } + break; + case 2: + // * + if (j == 0) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(121); + } else if (j == 1) { + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(241); + } else { // (j == 2) + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(1); + } + break; + case 3: + // # + switch (j) { + case 0: + for (u16 i = 0; i < 4; i++) { + vertices[i].Pos.rotateXZBy(1); + vertices[i].Pos.Z += BS / 4; + } + break; + case 1: + for (u16 i = 0; i < 4; i++) { + vertices[i].Pos.rotateXZBy(91); + vertices[i].Pos.X += BS / 4; + } + break; + case 2: + for (u16 i = 0; i < 4; i++) { + vertices[i].Pos.rotateXZBy(181); + vertices[i].Pos.Z -= BS / 4; + } + break; + case 3: + for (u16 i = 0; i < 4; i++) { + vertices[i].Pos.rotateXZBy(271); + vertices[i].Pos.X -= BS / 4; + } + break; + } + break; + case 4: + // outward leaning #-like + switch (j) { + case 0: + for (u16 i = 2; i < 4; i++) + vertices[i].Pos.Z -= BS / 2; + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(1); + break; + case 1: + for (u16 i = 2; i < 4; i++) + vertices[i].Pos.Z -= BS / 2; + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(91); + break; + case 2: + for (u16 i = 2; i < 4; i++) + vertices[i].Pos.Z -= BS / 2; + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(181); + break; + case 3: + for (u16 i = 2; i < 4; i++) + vertices[i].Pos.Z -= BS / 2; + for (u16 i = 0; i < 4; i++) + vertices[i].Pos.rotateXZBy(271); + break; + } + break; + } } - for (int i = 0; i < 4; i++) - { + for (int i = 0; i < 4; i++) { vertices[i].Pos *= f.visual_scale; vertices[i].Pos.Y += BS/2 * (f.visual_scale - 1); vertices[i].Pos += intToFloat(p, BS); + // move to a random spot to avoid moire + if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) { + vertices[i].Pos.X += random_offset_X; + vertices[i].Pos.Z += random_offset_Z; + } + // randomly move each face up/down + if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x20) != 0)) { + PseudoRandom yrng(j | x<<16 | z<<8 | y<<24 ); + vertices[i].Pos.Y -= BS * ((yrng.next() % 16 / 16.0) * 0.125); + } } u16 indices[] = {0, 1, 2, 2, 3, 0}; // Add to mesh collector collector.append(tile, vertices, 4, indices, 6); + + // stop adding faces for meshes with less than 4 faces + if (f.param_type_2 == CPT2_MESHOPTIONS) { + if (((p2mesh == 0) || (p2mesh == 1)) && (j == 1)) + break; + else if ((p2mesh == 2) && (j == 2)) + break; + } else if (j == 1) { + break; + } + } break;} case NDT_FIRELIKE: diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 3a9483efb..e3fcae0c6 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -136,9 +136,11 @@ with this program; if not, write to the Free Software Foundation, Inc., backface_culling: backwards compatibility for playing with newer client on pre-27 servers. Add nodedef v3 - connected nodeboxes + PROTOCOL_VERSION 28: + CPT2_MESHOPTIONS */ -#define LATEST_PROTOCOL_VERSION 27 +#define LATEST_PROTOCOL_VERSION 28 // Server's supported network protocol range #define SERVER_PROTOCOL_VERSION_MIN 13 diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 764203efc..646375575 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -387,7 +387,10 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const writeU8(os, post_effect_color.getGreen()); writeU8(os, post_effect_color.getBlue()); writeU8(os, param_type); - writeU8(os, param_type_2); + if ((protocol_version < 28) && (param_type_2 == CPT2_MESHOPTIONS)) + writeU8(os, CPT2_NONE); + else + writeU8(os, param_type_2); writeU8(os, is_ground_content); writeU8(os, light_propagates); writeU8(os, sunlight_propagates); diff --git a/src/nodedef.h b/src/nodedef.h index 1c2f792d8..f17c53727 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -65,6 +65,8 @@ enum ContentParamType2 CPT2_LEVELED, // 2D rotation for things like plants CPT2_DEGROTATE, + // Mesh options for plants + CPT2_MESHOPTIONS }; enum LiquidType diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp index 17f0f0dac..379ed773f 100644 --- a/src/script/cpp_api/s_node.cpp +++ b/src/script/cpp_api/s_node.cpp @@ -58,6 +58,7 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] = {CPT2_WALLMOUNTED, "wallmounted"}, {CPT2_LEVELED, "leveled"}, {CPT2_DEGROTATE, "degrotate"}, + {CPT2_MESHOPTIONS, "meshoptions"}, {0, NULL}, }; -- cgit v1.2.3 From 155288ee981c70f505526347cb2bcda4df1c8e6b Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Thu, 6 Oct 2016 19:20:12 +0200 Subject: use unordered containers where possible (patch 4 on X) Also remove some unused parameters/functions --- src/content_sao.cpp | 28 ++++++++++++++++++---------- src/content_sao.h | 5 +++-- src/guiFormSpecMenu.h | 4 +--- src/map.h | 1 + src/mapblock_mesh.cpp | 24 ++++++++++-------------- src/mapblock_mesh.h | 15 ++++++++------- src/network/serverpackethandler.cpp | 4 +--- src/script/cpp_api/s_async.cpp | 3 ++- src/script/cpp_api/s_async.h | 2 +- src/server.cpp | 21 +++++++++------------ src/server.h | 16 ++++++---------- src/util/numeric.cpp | 2 +- src/util/numeric.h | 37 ++----------------------------------- 13 files changed, 63 insertions(+), 99 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 1e7e788e9..895c26044 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -347,8 +347,10 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) if(m_bone_position_sent == false){ m_bone_position_sent = true; - for(std::map >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + std::string str = gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); @@ -383,8 +385,10 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - os< >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + os << serializeLongString(gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + std::string str = gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } - if(m_attachment_sent == false){ + if (!m_attachment_sent){ m_attachment_sent = true; - std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); + std::string str = gob_cmd_update_attachment(m_attachment_parent_id, + m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); diff --git a/src/content_sao.h b/src/content_sao.h index 44d40d332..ccae90b77 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -112,7 +112,7 @@ private: bool m_animation_loop; bool m_animation_sent; - std::map > m_bone_position; + UNORDERED_MAP > m_bone_position; bool m_bone_position_sent; int m_attachment_parent_id; @@ -321,7 +321,8 @@ private: bool m_animation_loop; bool m_animation_sent; - std::map > m_bone_position; // Stores position and rotation for each bone name + // Stores position and rotation for each bone name + UNORDERED_MAP > m_bone_position; bool m_bone_position_sent; int m_attachment_parent_id; diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 21054b725..153720975 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -409,8 +409,6 @@ protected: std::vector > > m_dropdowns; ItemSpec *m_selected_item; - f32 m_timer1; - f32 m_timer2; u32 m_selected_amount; bool m_selected_dragging; @@ -462,7 +460,7 @@ private: GUITable::TableOptions table_options; GUITable::TableColumns table_columns; // used to restore table selection/scroll/treeview state - std::map table_dyndata; + UNORDERED_MAP table_dyndata; } parserData; typedef struct { diff --git a/src/map.h b/src/map.h index 13775fde1..c73fa92bf 100644 --- a/src/map.h +++ b/src/map.h @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "voxel.h" #include "modifiedstate.h" #include "util/container.h" +#include "util/cpp11_container.h" #include "nodetimer.h" #include "map_settings_manager.h" diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index a11fb5887..00f83e7ab 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -1033,7 +1033,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): m_enable_shaders = data->m_use_shaders; m_use_tangent_vertices = data->m_use_tangent_vertices; m_enable_vbo = g_settings->getBool("enable_vbo"); - + if (g_settings->getBool("enable_minimap")) { m_minimap_mapblock = new MinimapMapblock; m_minimap_mapblock->getMinimapNodes( @@ -1298,10 +1298,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat // Cracks if(crack != m_last_crack) { - for(std::map::iterator - i = m_crack_materials.begin(); - i != m_crack_materials.end(); ++i) - { + for (UNORDERED_MAP::iterator i = m_crack_materials.begin(); + i != m_crack_materials.end(); ++i) { scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first); std::string basename = i->second; @@ -1315,9 +1313,9 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat // If the current material is also animated, // update animation info - std::map::iterator anim_iter = - m_animation_tiles.find(i->first); - if(anim_iter != m_animation_tiles.end()){ + UNORDERED_MAP::iterator anim_iter = + m_animation_tiles.find(i->first); + if (anim_iter != m_animation_tiles.end()){ TileSpec &tile = anim_iter->second; tile.texture = new_texture; tile.texture_id = new_texture_id; @@ -1330,10 +1328,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat } // Texture animation - for(std::map::iterator - i = m_animation_tiles.begin(); - i != m_animation_tiles.end(); ++i) - { + for (UNORDERED_MAP::iterator i = m_animation_tiles.begin(); + i != m_animation_tiles.end(); ++i) { const TileSpec &tile = i->second; // Figure out current frame int frameoffset = m_animation_frame_offsets[i->first]; @@ -1443,7 +1439,7 @@ void MeshCollector::append(const TileSpec &tile, vertices[i].Color, vertices[i].TCoords); p->vertices.push_back(vert); } - } + } for (u32 i = 0; i < numIndices; i++) { u32 j = indices[i] + vertex_count; @@ -1499,7 +1495,7 @@ void MeshCollector::append(const TileSpec &tile, vertices[i].Normal, c, vertices[i].TCoords); p->vertices.push_back(vert); } - } + } for (u32 i = 0; i < numIndices; i++) { u32 j = indices[i] + vertex_count; diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index f89fbe669..8376468da 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include "client/tile.h" #include "voxel.h" +#include "util/cpp11_container.h" #include class IGameDef; @@ -121,7 +122,7 @@ public: if(m_animation_force_timer > 0) m_animation_force_timer--; } - + void updateCameraOffset(v3s16 camera_offset); private: @@ -144,20 +145,20 @@ private: // Last crack value passed to animate() int m_last_crack; // Maps mesh buffer (i.e. material) indices to base texture names - std::map m_crack_materials; + UNORDERED_MAP m_crack_materials; // Animation info: texture animationi // Maps meshbuffers to TileSpecs - std::map m_animation_tiles; - std::map m_animation_frames; // last animation frame - std::map m_animation_frame_offsets; - + UNORDERED_MAP m_animation_tiles; + UNORDERED_MAP m_animation_frames; // last animation frame + UNORDERED_MAP m_animation_frame_offsets; + // Animation info: day/night transitions // Last daynight_ratio value passed to animate() u32 m_last_daynight_ratio; // For each meshbuffer, maps vertex indices to (day,night) pairs std::map > > m_daynight_diffs; - + // Camera offset info -> do we have to translate the mesh? v3s16 m_camera_offset; }; diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index a8bfd9068..f9061cc4f 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1693,9 +1693,7 @@ void Server::handleCommand_RemovedSounds(NetworkPacket* pkt) *pkt >> id; - std::map::iterator i = - m_playing_sounds.find(id); - + UNORDERED_MAP::iterator i = m_playing_sounds.find(id); if (i == m_playing_sounds.end()) continue; diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp index 9bf3fcf49..1fb84fab6 100644 --- a/src/script/cpp_api/s_async.cpp +++ b/src/script/cpp_api/s_async.cpp @@ -81,6 +81,7 @@ bool AsyncEngine::registerFunction(const char* name, lua_CFunction func) if (initDone) { return false; } + functionList[name] = func; return true; } @@ -203,7 +204,7 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) { /******************************************************************************/ void AsyncEngine::prepareEnvironment(lua_State* L, int top) { - for (std::map::iterator it = functionList.begin(); + for (UNORDERED_MAP::iterator it = functionList.begin(); it != functionList.end(); it++) { lua_pushstring(L, it->first.c_str()); lua_pushcfunction(L, it->second); diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index 8d612d58c..016381e5f 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -132,7 +132,7 @@ private: bool initDone; // Internal store for registred functions - std::map functionList; + UNORDERED_MAP functionList; // Internal counter to create job IDs unsigned int jobIdCounter; diff --git a/src/server.cpp b/src/server.cpp index 639e6462a..2dd070b1a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -868,7 +868,7 @@ void Server::AsyncRunStep(bool initial_step) m_clients.unlock(); // Clear buffered_messages - for(UNORDERED_MAP* >::iterator + for (UNORDERED_MAP* >::iterator i = buffered_messages.begin(); i != buffered_messages.end(); ++i) { delete i->second; @@ -2016,16 +2016,15 @@ s32 Server::playSound(const SimpleSoundSpec &spec, void Server::stopSound(s32 handle) { // Get sound reference - std::map::iterator i = - m_playing_sounds.find(handle); - if(i == m_playing_sounds.end()) + UNORDERED_MAP::iterator i = m_playing_sounds.find(handle); + if (i == m_playing_sounds.end()) return; ServerPlayingSound &psound = i->second; NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4); pkt << handle; - for(std::set::iterator i = psound.clients.begin(); + for (UNORDERED_SET::iterator i = psound.clients.begin(); i != psound.clients.end(); ++i) { // Send as reliable m_clients.send(*i, 0, &pkt, true); @@ -2322,7 +2321,7 @@ void Server::sendMediaAnnouncement(u16 peer_id) NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id); pkt << (u16) m_media.size(); - for (std::map::iterator i = m_media.begin(); + for (UNORDERED_MAP::iterator i = m_media.begin(); i != m_media.end(); ++i) { pkt << i->first << i->second.sha1_digest; } @@ -2367,7 +2366,7 @@ void Server::sendRequestedMedia(u16 peer_id, i != tosend.end(); ++i) { const std::string &name = *i; - if(m_media.find(name) == m_media.end()) { + if (m_media.find(name) == m_media.end()) { errorstream<<"Server::sendRequestedMedia(): Client asked for " <<"unknown file \""<<(name)<<"\""<::iterator - i = m_playing_sounds.begin(); - i != m_playing_sounds.end();) - { + for (UNORDERED_MAP::iterator + i = m_playing_sounds.begin(); i != m_playing_sounds.end();) { ServerPlayingSound &psound = i->second; psound.clients.erase(peer_id); - if(psound.clients.empty()) + if (psound.clients.empty()) m_playing_sounds.erase(i++); else ++i; diff --git a/src/server.h b/src/server.h index 3ad894b38..34427a71a 100644 --- a/src/server.h +++ b/src/server.h @@ -157,7 +157,7 @@ struct ServerSoundParams struct ServerPlayingSound { ServerSoundParams params; - std::set clients; // peer ids + UNORDERED_SET clients; // peer ids }; class Server : public con::PeerHandler, public MapEventReceiver, @@ -243,11 +243,9 @@ public: std::wstring getStatusString(); // read shutdown state - inline bool getShutdownRequested() - { return m_shutdown_requested; } + inline bool getShutdownRequested() const { return m_shutdown_requested; } // request server to shutdown - inline void requestShutdown() { m_shutdown_requested = true; } void requestShutdown(const std::string &msg, bool reconnect) { m_shutdown_requested = true; @@ -323,8 +321,7 @@ public: const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); - inline std::string getWorldPath() const - { return m_path_world; } + inline std::string getWorldPath() const { return m_path_world; } inline bool isSingleplayer() { return m_simple_singleplayer_mode; } @@ -356,8 +353,7 @@ public: bool setSky(Player *player, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms); - bool overrideDayNightRatio(Player *player, bool do_override, - float brightness); + bool overrideDayNightRatio(Player *player, bool do_override, float brightness); /* con::PeerHandler implementation. */ void peerAdded(con::Peer *peer); @@ -654,12 +650,12 @@ private: u16 m_ignore_map_edit_events_peer_id; // media files known to server - std::map m_media; + UNORDERED_MAP m_media; /* Sounds */ - std::map m_playing_sounds; + UNORDERED_MAP m_playing_sounds; s32 m_next_sound_id; /* diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index 42ebd9022..6a7bfcac9 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include -std::map > FacePositionCache::m_cache; +UNORDERED_MAP > FacePositionCache::m_cache; Mutex FacePositionCache::m_cache_mutex; // Calculate the borders of a "d-radius" cube // TODO: Make it work without mutex and data races, probably thread-local diff --git a/src/util/numeric.h b/src/util/numeric.h index 615327864..4cdc254c3 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -26,8 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "../irr_v3d.h" #include "../irr_aabb3d.h" #include "../threading/mutex.h" +#include "cpp11_container.h" #include -#include #include @@ -41,26 +41,10 @@ public: static std::vector getFacePositions(u16 d); private: static void generateFacePosition(u16 d); - static std::map > m_cache; + static UNORDERED_MAP > m_cache; static Mutex m_cache_mutex; }; -class IndentationRaiser -{ -public: - IndentationRaiser(u16 *indentation) - { - m_indentation = indentation; - (*m_indentation)++; - } - ~IndentationRaiser() - { - (*m_indentation)--; - } -private: - u16 *m_indentation; -}; - inline s16 getContainerPos(s16 p, s16 d) { return (p>=0 ? p : p-d+1) / d; @@ -149,23 +133,6 @@ inline bool isInArea(v3s16 p, v3s16 d) #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d))) #define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1) -inline v3s16 arealim(v3s16 p, s16 d) -{ - if(p.X < 0) - p.X = 0; - if(p.Y < 0) - p.Y = 0; - if(p.Z < 0) - p.Z = 0; - if(p.X > d-1) - p.X = d-1; - if(p.Y > d-1) - p.Y = d-1; - if(p.Z > d-1) - p.Z = d-1; - return p; -} - // The naive swap performs better than the xor version #define SWAP(t, x, y) do { \ t temp = x; \ -- cgit v1.2.3 From 4b17105dc45976e399dab68f85b3030fa27f0ae2 Mon Sep 17 00:00:00 2001 From: Rogier Date: Mon, 25 Jul 2016 18:39:29 +0200 Subject: Emergeblocks: Fix occasional crash Modification of the emergeblocks internal state was not protected by a lock, causing a race condition. This can be reproduced by repeatedly running emergeblocks for an already-generated section of the map (with multiple emerge threads). --- src/script/cpp_api/s_env.cpp | 4 +++- src/script/lua_api/l_env.cpp | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 82d0d4f0e..913d8539d 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -212,11 +212,13 @@ void ScriptApiEnv::on_emerge_area_completion( { Server *server = getServer(); + // This function should be executed with envlock held. + // The caller (LuaEmergeAreaCallback in src/script/lua_api/l_env.cpp) + // should have obtained the lock. // Note that the order of these locks is important! Envlock must *ALWAYS* // be acquired before attempting to acquire scriptlock, or else ServerThread // will try to acquire scriptlock after it already owns envlock, thus // deadlocking EmergeThread and ServerThread - MutexAutoLock envlock(server->m_env_mutex); SCRIPTAPI_PRECHECKHEADER diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index f6ea23e95..68d10308c 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -137,6 +137,10 @@ void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param) assert(state->script != NULL); assert(state->refcount > 0); + // state must be protected by envlock + Server *server = state->script->getServer(); + MutexAutoLock envlock(server->m_env_mutex); + state->refcount--; state->script->on_emerge_area_completion(blockpos, action, state); -- cgit v1.2.3 From b5c84c34ce283a56317902d24067d9a0795a44c5 Mon Sep 17 00:00:00 2001 From: Zeno- Date: Sat, 5 Nov 2016 15:10:49 +1000 Subject: Fix memory leak in ::safeLoadFile (#4730) --- src/script/cpp_api/s_security.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 0e64c4c61..3a8f724fe 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -323,9 +323,12 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path) } if (luaL_loadbuffer(L, code, size, chunk_name)) { + delete [] code; return false; } + delete [] code; + if (path) { delete [] chunk_name; } -- cgit v1.2.3 From 9e10f9f49a558050d36a49db619bf8f5eb3853c0 Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Thu, 24 Nov 2016 09:58:21 -0500 Subject: Fix secure io.open without mode --- src/script/cpp_api/s_security.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 3a8f724fe..5a64c249c 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -525,14 +525,19 @@ int ScriptApiSecurity::sl_g_require(lua_State *L) int ScriptApiSecurity::sl_io_open(lua_State *L) { + bool with_mode = lua_gettop(L) > 1; + luaL_checktype(L, 1, LUA_TSTRING); const char *path = lua_tostring(L, 1); CHECK_SECURE_PATH(L, path); push_original(L, "io", "open"); lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_call(L, 2, 2); + if (with_mode) { + lua_pushvalue(L, 2); + } + + lua_call(L, with_mode ? 2 : 1, 2); return 2; } -- cgit v1.2.3 From 3af5eef96463510a27cf06b9c3ecc9f1d04cdac6 Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Thu, 24 Nov 2016 10:10:20 -0500 Subject: Fix secure io.lines It used to drop all of the return values from the insecure version of the function. --- src/script/cpp_api/s_security.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 5a64c249c..c9816f89b 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -577,13 +577,13 @@ int ScriptApiSecurity::sl_io_lines(lua_State *L) CHECK_SECURE_PATH(L, path); } + int top_precall = lua_gettop(L); push_original(L, "io", "lines"); lua_pushvalue(L, 1); - int top_precall = lua_gettop(L); lua_call(L, 1, LUA_MULTRET); // Return number of arguments returned by the function, // adjusting for the function being poped. - return lua_gettop(L) - (top_precall - 1); + return lua_gettop(L) - top_precall; } -- cgit v1.2.3 From 59f84ca0a07e50dd5ce050d38ae1aeb529bd25ac Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Mon, 5 Dec 2016 19:59:15 +0000 Subject: Mod security: Allow read-only access to all mod paths --- src/script/cpp_api/s_security.cpp | 82 +++++++++++++++++++++++++++----------- src/script/cpp_api/s_security.h | 21 ++++++---- src/script/lua_api/l_areastore.cpp | 4 +- src/script/lua_api/l_mapgen.cpp | 2 +- src/script/lua_api/l_settings.cpp | 13 ++++-- src/script/lua_api/l_settings.h | 3 +- src/script/lua_api/l_util.cpp | 4 +- src/server.h | 1 + 8 files changed, 89 insertions(+), 41 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index c9816f89b..b915747c6 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -336,8 +336,12 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path) } -bool ScriptApiSecurity::checkPath(lua_State *L, const char *path) +bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, + bool write_required, bool *write_allowed) { + if (write_allowed) + *write_allowed = false; + std::string str; // Transient std::string norel_path = fs::RemoveRelativePathComponents(path); @@ -380,32 +384,53 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path) // Builtin can access anything if (mod_name == BUILTIN_MOD_NAME) { + if (write_allowed) *write_allowed = true; return true; } // Allow paths in mod path - const ModSpec *mod = server->getModSpec(mod_name); - if (mod) { - str = fs::AbsolutePath(mod->path); + // Don't bother if write access isn't important, since it will be handled later + if (write_required || write_allowed != NULL) { + const ModSpec *mod = server->getModSpec(mod_name); + if (mod) { + str = fs::AbsolutePath(mod->path); + if (!str.empty() && fs::PathStartsWith(abs_path, str)) { + if (write_allowed) *write_allowed = true; + return true; + } + } + } + } + lua_pop(L, 1); // Pop mod name + + // Allow read-only access to all mod directories + if (!write_required) { + const std::vector mods = server->getMods(); + for (size_t i = 0; i < mods.size(); ++i) { + str = fs::AbsolutePath(mods[i].path); if (!str.empty() && fs::PathStartsWith(abs_path, str)) { return true; } } } - lua_pop(L, 1); // Pop mod name str = fs::AbsolutePath(server->getWorldPath()); - if (str.empty()) return false; - // Don't allow access to world mods. We add to the absolute path - // of the world instead of getting the absolute paths directly - // because that won't work if they don't exist. - if (fs::PathStartsWith(abs_path, str + DIR_DELIM + "worldmods") || - fs::PathStartsWith(abs_path, str + DIR_DELIM + "game")) { - return false; - } - // Allow all other paths in world path - if (fs::PathStartsWith(abs_path, str)) { - return true; + if (!str.empty()) { + // Don't allow access to other paths in the world mod/game path. + // These have to be blocked so you can't override a trusted mod + // by creating a mod with the same name in a world mod directory. + // We add to the absolute path of the world instead of getting + // the absolute paths directly because that won't work if they + // don't exist. + if (fs::PathStartsWith(abs_path, str + DIR_DELIM + "worldmods") || + fs::PathStartsWith(abs_path, str + DIR_DELIM + "game")) { + return false; + } + // Allow all other paths in world path + if (fs::PathStartsWith(abs_path, str)) { + if (write_allowed) *write_allowed = true; + return true; + } } // Default to disallowing @@ -476,7 +501,7 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L) if (lua_isstring(L, 1)) { path = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path); + CHECK_SECURE_PATH_INTERNAL(L, path, false, NULL); } if (!safeLoadFile(L, path)) { @@ -529,7 +554,16 @@ int ScriptApiSecurity::sl_io_open(lua_State *L) luaL_checktype(L, 1, LUA_TSTRING); const char *path = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path); + + bool write_requested = false; + if (with_mode) { + luaL_checktype(L, 2, LUA_TSTRING); + const char *mode = lua_tostring(L, 2); + write_requested = strchr(mode, 'w') != NULL || + strchr(mode, '+') != NULL || + strchr(mode, 'a') != NULL; + } + CHECK_SECURE_PATH_INTERNAL(L, path, write_requested, NULL); push_original(L, "io", "open"); lua_pushvalue(L, 1); @@ -546,7 +580,7 @@ int ScriptApiSecurity::sl_io_input(lua_State *L) { if (lua_isstring(L, 1)) { const char *path = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path); + CHECK_SECURE_PATH_INTERNAL(L, path, false, NULL); } push_original(L, "io", "input"); @@ -560,7 +594,7 @@ int ScriptApiSecurity::sl_io_output(lua_State *L) { if (lua_isstring(L, 1)) { const char *path = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path); + CHECK_SECURE_PATH_INTERNAL(L, path, true, NULL); } push_original(L, "io", "output"); @@ -574,7 +608,7 @@ int ScriptApiSecurity::sl_io_lines(lua_State *L) { if (lua_isstring(L, 1)) { const char *path = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path); + CHECK_SECURE_PATH_INTERNAL(L, path, false, NULL); } int top_precall = lua_gettop(L); @@ -591,11 +625,11 @@ int ScriptApiSecurity::sl_os_rename(lua_State *L) { luaL_checktype(L, 1, LUA_TSTRING); const char *path1 = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path1); + CHECK_SECURE_PATH_INTERNAL(L, path1, true, NULL); luaL_checktype(L, 2, LUA_TSTRING); const char *path2 = lua_tostring(L, 2); - CHECK_SECURE_PATH(L, path2); + CHECK_SECURE_PATH_INTERNAL(L, path2, true, NULL); push_original(L, "os", "rename"); lua_pushvalue(L, 1); @@ -609,7 +643,7 @@ int ScriptApiSecurity::sl_os_remove(lua_State *L) { luaL_checktype(L, 1, LUA_TSTRING); const char *path = lua_tostring(L, 1); - CHECK_SECURE_PATH(L, path); + CHECK_SECURE_PATH_INTERNAL(L, path, true, NULL); push_original(L, "os", "remove"); lua_pushvalue(L, 1); diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h index 97bc5c067..6876108e8 100644 --- a/src/script/cpp_api/s_security.h +++ b/src/script/cpp_api/s_security.h @@ -23,14 +23,18 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" -#define CHECK_SECURE_PATH(L, path) \ - if (!ScriptApiSecurity::checkPath(L, path)) { \ - throw LuaError(std::string("Attempt to access external file ") + \ - path + " with mod security on."); \ +#define CHECK_SECURE_PATH_INTERNAL(L, path, write_required, ptr) \ + if (!ScriptApiSecurity::checkPath(L, path, write_required, ptr)) { \ + throw LuaError(std::string("Mod security: Blocked attempted ") + \ + (write_required ? "write to " : "read from ") + path); \ } -#define CHECK_SECURE_PATH_OPTIONAL(L, path) \ +#define CHECK_SECURE_PATH(L, path, write_required) \ if (ScriptApiSecurity::isSecure(L)) { \ - CHECK_SECURE_PATH(L, path); \ + CHECK_SECURE_PATH_INTERNAL(L, path, write_required, NULL); \ + } +#define CHECK_SECURE_PATH_POSSIBLE_WRITE(L, path, ptr) \ + if (ScriptApiSecurity::isSecure(L)) { \ + CHECK_SECURE_PATH_INTERNAL(L, path, false, ptr); \ } @@ -43,8 +47,9 @@ public: static bool isSecure(lua_State *L); // Loads a file as Lua code safely (doesn't allow bytecode). static bool safeLoadFile(lua_State *L, const char *path); - // Checks if mods are allowed to read and write to the path - static bool checkPath(lua_State *L, const char *path); + // Checks if mods are allowed to read (and optionally write) to the path + static bool checkPath(lua_State *L, const char *path, bool write_required, + bool *write_allowed=NULL); private: // Syntax: "sl_" '_' diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp index 0912e2ab0..09a5c78f9 100644 --- a/src/script/lua_api/l_areastore.cpp +++ b/src/script/lua_api/l_areastore.cpp @@ -263,7 +263,7 @@ int LuaAreaStore::l_to_file(lua_State *L) AreaStore *ast = o->as; const char *filename = luaL_checkstring(L, 2); - CHECK_SECURE_PATH_OPTIONAL(L, filename); + CHECK_SECURE_PATH(L, filename, true); std::ostringstream os(std::ios_base::binary); ast->serialize(os); @@ -294,7 +294,7 @@ int LuaAreaStore::l_from_file(lua_State *L) LuaAreaStore *o = checkobject(L, 1); const char *filename = luaL_checkstring(L, 2); - CHECK_SECURE_PATH_OPTIONAL(L, filename); + CHECK_SECURE_PATH(L, filename, false); std::ifstream is(filename, std::ios::binary); return deserialization_helper(L, o->as, is); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 281f68e46..bc1c32f03 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -1295,7 +1295,7 @@ int ModApiMapgen::l_create_schematic(lua_State *L) INodeDefManager *ndef = getServer(L)->getNodeDefManager(); const char *filename = luaL_checkstring(L, 4); - CHECK_SECURE_PATH_OPTIONAL(L, filename); + CHECK_SECURE_PATH(L, filename, true); Map *map = &(getEnv(L)->getMap()); Schematic schem; diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index 35b82b435..ea3d50857 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -118,6 +118,11 @@ int LuaSettings::l_write(lua_State* L) NO_MAP_LOCK_REQUIRED; LuaSettings* o = checkobject(L, 1); + if (!o->m_write_allowed) { + throw LuaError("Settings: writing " + o->m_filename + + " not allowed with mod security on."); + } + bool success = o->m_settings->updateConfigFile(o->m_filename.c_str()); lua_pushboolean(L, success); @@ -142,8 +147,9 @@ int LuaSettings::l_to_table(lua_State* L) return 1; } -LuaSettings::LuaSettings(const char* filename) +LuaSettings::LuaSettings(const char* filename, bool write_allowed) { + m_write_allowed = write_allowed; m_filename = std::string(filename); m_settings = new Settings(); @@ -188,9 +194,10 @@ void LuaSettings::Register(lua_State* L) int LuaSettings::create_object(lua_State* L) { NO_MAP_LOCK_REQUIRED; + bool write_allowed; const char* filename = luaL_checkstring(L, 1); - CHECK_SECURE_PATH_OPTIONAL(L, filename); - LuaSettings* o = new LuaSettings(filename); + CHECK_SECURE_PATH_POSSIBLE_WRITE(L, filename, &write_allowed); + LuaSettings* o = new LuaSettings(filename, write_allowed); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); diff --git a/src/script/lua_api/l_settings.h b/src/script/lua_api/l_settings.h index cb0c09a73..bca333e31 100644 --- a/src/script/lua_api/l_settings.h +++ b/src/script/lua_api/l_settings.h @@ -53,11 +53,12 @@ private: // to_table(self) -> {[key1]=value1,...} static int l_to_table(lua_State* L); + bool m_write_allowed; Settings* m_settings; std::string m_filename; public: - LuaSettings(const char* filename); + LuaSettings(const char* filename, bool write_allowed); ~LuaSettings(); // LuaSettings(filename) diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 818c1aeeb..26e2b985c 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -388,7 +388,7 @@ int ModApiUtil::l_mkdir(lua_State *L) { NO_MAP_LOCK_REQUIRED; const char *path = luaL_checkstring(L, 1); - CHECK_SECURE_PATH_OPTIONAL(L, path); + CHECK_SECURE_PATH(L, path, true); lua_pushboolean(L, fs::CreateAllDirs(path)); return 1; } @@ -400,7 +400,7 @@ int ModApiUtil::l_get_dir_list(lua_State *L) const char *path = luaL_checkstring(L, 1); short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1; - CHECK_SECURE_PATH_OPTIONAL(L, path); + CHECK_SECURE_PATH(L, path, false); std::vector list = fs::GetDirListing(path); diff --git a/src/server.h b/src/server.h index cc2bcef25..4425d139b 100644 --- a/src/server.h +++ b/src/server.h @@ -298,6 +298,7 @@ public: IWritableNodeDefManager* getWritableNodeDefManager(); IWritableCraftDefManager* getWritableCraftDefManager(); + const std::vector &getMods() const { return m_mods; } const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); -- cgit v1.2.3 From 0f0502109eac44128e87906fff30b5d049392f1d Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Fri, 16 Dec 2016 17:43:39 -0500 Subject: Security: Fix resolving of some relative paths Trying to resolve a path with RemoveRelativePathComponents that can't be resolved without leaving leading parent components (e.g. "../worlds/foo" or "bar/../../worlds/foo") will fail. To work around this, we leave the relative components and simply remove the trailing components one at a time, and bail out when we find a parent component. This will still fail for paths like "worlds/foo/noexist/../auth.txt" (the path before the last parent component must not exist), but this is fine since you won't be able to open a file with a path like that anyways (the O.S. will determine that the path doesn't exist. Try `cat /a/../etc/passwd`). --- src/script/cpp_api/s_security.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'src/script/cpp_api') diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index b915747c6..1b1f148cd 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -344,8 +344,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, std::string str; // Transient - std::string norel_path = fs::RemoveRelativePathComponents(path); - std::string abs_path = fs::AbsolutePath(norel_path); + std::string abs_path = fs::AbsolutePath(path); if (!abs_path.empty()) { // Don't allow accessing the settings file @@ -356,18 +355,29 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, // If we couldn't find the absolute path (path doesn't exist) then // try removing the last components until it works (to allow // non-existent files/folders for mkdir). - std::string cur_path = norel_path; + std::string cur_path = path; std::string removed; while (abs_path.empty() && !cur_path.empty()) { - std::string tmp_rmed; - cur_path = fs::RemoveLastPathComponent(cur_path, &tmp_rmed); - removed = tmp_rmed + (removed.empty() ? "" : DIR_DELIM + removed); + std::string component; + cur_path = fs::RemoveLastPathComponent(cur_path, &component); + if (component == "..") { + // Parent components can't be allowed or we could allow something like + // /home/user/minetest/worlds/foo/noexist/../../../../../../etc/passwd. + // If we have previous non-relative elements in the path we might be + // able to remove them so that things like worlds/foo/noexist/../auth.txt + // could be allowed, but those paths will be interpreted as nonexistent + // by the operating system anyways. + return false; + } + removed = component + (removed.empty() ? "" : DIR_DELIM + removed); abs_path = fs::AbsolutePath(cur_path); } - if (abs_path.empty()) return false; + if (abs_path.empty()) + return false; // Add the removed parts back so that you can't, eg, create a // directory in worldmods if worldmods doesn't exist. - if (!removed.empty()) abs_path += DIR_DELIM + removed; + if (!removed.empty()) + abs_path += DIR_DELIM + removed; // Get server from registry lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); -- cgit v1.2.3