s_security.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "cpp_api/s_security.h"
  17. #include "filesys.h"
  18. #include "porting.h"
  19. #include "server.h"
  20. #include "settings.h"
  21. #include <cerrno>
  22. #include <string>
  23. #include <iostream>
  24. #define SECURE_API(lib, name) \
  25. lua_pushcfunction(L, sl_##lib##_##name); \
  26. lua_setfield(L, -2, #name);
  27. static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int from=-2, int to=-1)
  28. {
  29. if (from < 0) from = lua_gettop(L) + from + 1;
  30. if (to < 0) to = lua_gettop(L) + to + 1;
  31. for (unsigned i = 0; i < (len / sizeof(list[0])); i++) {
  32. lua_getfield(L, from, list[i]);
  33. lua_setfield(L, to, list[i]);
  34. }
  35. }
  36. // Pushes the original version of a library function on the stack, from the old version
  37. static inline void push_original(lua_State *L, const char *lib, const char *func)
  38. {
  39. lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
  40. lua_getfield(L, -1, lib);
  41. lua_remove(L, -2); // Remove globals_backup
  42. lua_getfield(L, -1, func);
  43. lua_remove(L, -2); // Remove lib
  44. }
  45. void ScriptApiSecurity::initializeSecurity()
  46. {
  47. static const char *whitelist[] = {
  48. "assert",
  49. "core",
  50. "collectgarbage",
  51. "DIR_DELIM",
  52. "error",
  53. "getfenv",
  54. "getmetatable",
  55. "ipairs",
  56. "next",
  57. "pairs",
  58. "pcall",
  59. "print",
  60. "rawequal",
  61. "rawget",
  62. "rawset",
  63. "select",
  64. "setfenv",
  65. "setmetatable",
  66. "tonumber",
  67. "tostring",
  68. "type",
  69. "unpack",
  70. "_VERSION",
  71. "xpcall",
  72. // Completely safe libraries
  73. "coroutine",
  74. "string",
  75. "table",
  76. "math",
  77. };
  78. static const char *io_whitelist[] = {
  79. "close",
  80. "flush",
  81. "read",
  82. "type",
  83. "write",
  84. };
  85. static const char *os_whitelist[] = {
  86. "clock",
  87. "date",
  88. "difftime",
  89. "getenv",
  90. "setlocale",
  91. "time",
  92. "tmpname",
  93. };
  94. static const char *debug_whitelist[] = {
  95. "gethook",
  96. "traceback",
  97. "getinfo",
  98. "getmetatable",
  99. "setupvalue",
  100. "setmetatable",
  101. "upvalueid",
  102. "upvaluejoin",
  103. "sethook",
  104. "debug",
  105. "setlocal",
  106. };
  107. static const char *package_whitelist[] = {
  108. "config",
  109. "cpath",
  110. "path",
  111. "searchpath",
  112. };
  113. #if USE_LUAJIT
  114. static const char *jit_whitelist[] = {
  115. "arch",
  116. "flush",
  117. "off",
  118. "on",
  119. "opt",
  120. "os",
  121. "status",
  122. "version",
  123. "version_num",
  124. };
  125. #endif
  126. m_secure = true;
  127. lua_State *L = getStack();
  128. int old_globals = backupGlobals(L);
  129. // Copy safe base functions
  130. lua_getglobal(L, "_G");
  131. copy_safe(L, whitelist, sizeof(whitelist));
  132. // And replace unsafe ones
  133. SECURE_API(g, dofile);
  134. SECURE_API(g, load);
  135. SECURE_API(g, loadfile);
  136. SECURE_API(g, loadstring);
  137. SECURE_API(g, require);
  138. lua_pop(L, 1);
  139. // Copy safe IO functions
  140. lua_getfield(L, old_globals, "io");
  141. lua_newtable(L);
  142. copy_safe(L, io_whitelist, sizeof(io_whitelist));
  143. // And replace unsafe ones
  144. SECURE_API(io, open);
  145. SECURE_API(io, input);
  146. SECURE_API(io, output);
  147. SECURE_API(io, lines);
  148. lua_setglobal(L, "io");
  149. lua_pop(L, 1); // Pop old IO
  150. // Copy safe OS functions
  151. lua_getfield(L, old_globals, "os");
  152. lua_newtable(L);
  153. copy_safe(L, os_whitelist, sizeof(os_whitelist));
  154. // And replace unsafe ones
  155. SECURE_API(os, remove);
  156. SECURE_API(os, rename);
  157. lua_setglobal(L, "os");
  158. lua_pop(L, 1); // Pop old OS
  159. // Copy safe debug functions
  160. lua_getfield(L, old_globals, "debug");
  161. lua_newtable(L);
  162. copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
  163. lua_setglobal(L, "debug");
  164. lua_pop(L, 1); // Pop old debug
  165. // Copy safe package fields
  166. lua_getfield(L, old_globals, "package");
  167. lua_newtable(L);
  168. copy_safe(L, package_whitelist, sizeof(package_whitelist));
  169. lua_setglobal(L, "package");
  170. lua_pop(L, 1); // Pop old package
  171. #if USE_LUAJIT
  172. // Copy safe jit functions, if they exist
  173. lua_getfield(L, -1, "jit");
  174. if (!lua_isnil(L, -1)) {
  175. lua_newtable(L);
  176. copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
  177. lua_setglobal(L, "jit");
  178. }
  179. lua_pop(L, 1); // Pop old jit
  180. #endif
  181. lua_pop(L, 1); // Pop globals_backup
  182. }
  183. void ScriptApiSecurity::initializeSecurityClient()
  184. {
  185. static const char *whitelist[] = {
  186. "assert",
  187. "core",
  188. "collectgarbage",
  189. "DIR_DELIM",
  190. "error",
  191. "getfenv",
  192. "ipairs",
  193. "next",
  194. "pairs",
  195. "pcall",
  196. "print",
  197. "rawequal",
  198. "rawget",
  199. "rawset",
  200. "select",
  201. "setfenv",
  202. "setmetatable",
  203. "tonumber",
  204. "tostring",
  205. "type",
  206. "unpack",
  207. "_VERSION",
  208. "xpcall",
  209. // Completely safe libraries
  210. "coroutine",
  211. "string",
  212. "table",
  213. "math",
  214. };
  215. static const char *os_whitelist[] = {
  216. "clock",
  217. "date",
  218. "difftime",
  219. "time"
  220. };
  221. static const char *debug_whitelist[] = {
  222. "getinfo",
  223. };
  224. #if USE_LUAJIT
  225. static const char *jit_whitelist[] = {
  226. "arch",
  227. "flush",
  228. "off",
  229. "on",
  230. "opt",
  231. "os",
  232. "status",
  233. "version",
  234. "version_num",
  235. };
  236. #endif
  237. m_secure = true;
  238. lua_State *L = getStack();
  239. int old_globals = backupGlobals(L);
  240. // Copy safe base functions
  241. lua_getglobal(L, "_G");
  242. copy_safe(L, whitelist, sizeof(whitelist));
  243. // And replace unsafe ones
  244. SECURE_API(g, dofile);
  245. SECURE_API(g, loadstring);
  246. SECURE_API(g, require);
  247. lua_pop(L, 1);
  248. // Copy safe OS functions
  249. lua_getfield(L, old_globals, "os");
  250. lua_newtable(L);
  251. copy_safe(L, os_whitelist, sizeof(os_whitelist));
  252. lua_setglobal(L, "os");
  253. lua_pop(L, 1); // Pop old OS
  254. // Copy safe debug functions
  255. lua_getfield(L, old_globals, "debug");
  256. lua_newtable(L);
  257. copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
  258. lua_setglobal(L, "debug");
  259. lua_pop(L, 1); // Pop old debug
  260. #if USE_LUAJIT
  261. // Copy safe jit functions, if they exist
  262. lua_getfield(L, -1, "jit");
  263. if (!lua_isnil(L, -1)) {
  264. lua_newtable(L);
  265. copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
  266. lua_setglobal(L, "jit");
  267. }
  268. lua_pop(L, 1); // Pop old jit
  269. #endif
  270. lua_pop(L, 1); // Pop globals_backup
  271. }
  272. int ScriptApiSecurity::backupGlobals(lua_State *L)
  273. {
  274. // Backup globals to the registry
  275. lua_getglobal(L, "_G");
  276. lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
  277. // Replace the global environment with an empty one
  278. #if LUA_VERSION_NUM <= 501
  279. int is_main = lua_pushthread(L); // Push the main thread
  280. FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
  281. "isn't the main Lua thread!");
  282. #endif
  283. lua_newtable(L); // Create new environment
  284. lua_pushvalue(L, -1);
  285. lua_setfield(L, -2, "_G"); // Set _G of new environment
  286. #if LUA_VERSION_NUM >= 502 // Lua >= 5.2
  287. // Set the global environment
  288. lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
  289. #else // Lua <= 5.1
  290. // Set the environment of the main thread
  291. FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
  292. "environment of the main Lua thread!");
  293. lua_pop(L, 1); // Pop thread
  294. #endif
  295. // Get old globals
  296. lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
  297. return lua_gettop(L);
  298. }
  299. bool ScriptApiSecurity::isSecure(lua_State *L)
  300. {
  301. lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
  302. bool secure = !lua_isnil(L, -1);
  303. lua_pop(L, 1);
  304. return secure;
  305. }
  306. #define CHECK_FILE_ERR(ret, fp) \
  307. if (ret) { \
  308. lua_pushfstring(L, "%s: %s", path, strerror(errno)); \
  309. if (fp) std::fclose(fp); \
  310. return false; \
  311. }
  312. bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path)
  313. {
  314. FILE *fp;
  315. char *chunk_name;
  316. if (path == NULL) {
  317. fp = stdin;
  318. chunk_name = const_cast<char *>("=stdin");
  319. } else {
  320. fp = fopen(path, "rb");
  321. if (!fp) {
  322. lua_pushfstring(L, "%s: %s", path, strerror(errno));
  323. return false;
  324. }
  325. chunk_name = new char[strlen(path) + 2];
  326. chunk_name[0] = '@';
  327. chunk_name[1] = '\0';
  328. strcat(chunk_name, path);
  329. }
  330. size_t start = 0;
  331. int c = std::getc(fp);
  332. if (c == '#') {
  333. // Skip the first line
  334. while ((c = std::getc(fp)) != EOF && c != '\n');
  335. if (c == '\n') c = std::getc(fp);
  336. start = std::ftell(fp);
  337. }
  338. if (c == LUA_SIGNATURE[0]) {
  339. lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
  340. std::fclose(fp);
  341. if (path) {
  342. delete [] chunk_name;
  343. }
  344. return false;
  345. }
  346. // Read the file
  347. int ret = std::fseek(fp, 0, SEEK_END);
  348. if (ret) {
  349. lua_pushfstring(L, "%s: %s", path, strerror(errno));
  350. std::fclose(fp);
  351. if (path) {
  352. delete [] chunk_name;
  353. }
  354. return false;
  355. }
  356. size_t size = std::ftell(fp) - start;
  357. char *code = new char[size];
  358. ret = std::fseek(fp, start, SEEK_SET);
  359. if (ret) {
  360. lua_pushfstring(L, "%s: %s", path, strerror(errno));
  361. std::fclose(fp);
  362. delete [] code;
  363. if (path) {
  364. delete [] chunk_name;
  365. }
  366. return false;
  367. }
  368. size_t num_read = std::fread(code, 1, size, fp);
  369. if (path) {
  370. std::fclose(fp);
  371. }
  372. if (num_read != size) {
  373. lua_pushliteral(L, "Error reading file to load.");
  374. delete [] code;
  375. if (path) {
  376. delete [] chunk_name;
  377. }
  378. return false;
  379. }
  380. if (luaL_loadbuffer(L, code, size, chunk_name)) {
  381. delete [] code;
  382. return false;
  383. }
  384. delete [] code;
  385. if (path) {
  386. delete [] chunk_name;
  387. }
  388. return true;
  389. }
  390. bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
  391. bool write_required, bool *write_allowed)
  392. {
  393. if (write_allowed)
  394. *write_allowed = false;
  395. std::string str; // Transient
  396. std::string abs_path = fs::AbsolutePath(path);
  397. if (!abs_path.empty()) {
  398. // Don't allow accessing the settings file
  399. str = fs::AbsolutePath(g_settings_path);
  400. if (str == abs_path) return false;
  401. }
  402. // If we couldn't find the absolute path (path doesn't exist) then
  403. // try removing the last components until it works (to allow
  404. // non-existent files/folders for mkdir).
  405. std::string cur_path = path;
  406. std::string removed;
  407. while (abs_path.empty() && !cur_path.empty()) {
  408. std::string component;
  409. cur_path = fs::RemoveLastPathComponent(cur_path, &component);
  410. if (component == "..") {
  411. // Parent components can't be allowed or we could allow something like
  412. // /home/user/minetest/worlds/foo/noexist/../../../../../../etc/passwd.
  413. // If we have previous non-relative elements in the path we might be
  414. // able to remove them so that things like worlds/foo/noexist/../auth.txt
  415. // could be allowed, but those paths will be interpreted as nonexistent
  416. // by the operating system anyways.
  417. return false;
  418. }
  419. removed = component + (removed.empty() ? "" : DIR_DELIM + removed);
  420. abs_path = fs::AbsolutePath(cur_path);
  421. }
  422. if (abs_path.empty())
  423. return false;
  424. // Add the removed parts back so that you can't, eg, create a
  425. // directory in worldmods if worldmods doesn't exist.
  426. if (!removed.empty())
  427. abs_path += DIR_DELIM + removed;
  428. // Get server from registry
  429. lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
  430. ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
  431. lua_pop(L, 1);
  432. const IGameDef *gamedef = script->getGameDef();
  433. if (!gamedef)
  434. return false;
  435. // Get mod name
  436. lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
  437. if (lua_isstring(L, -1)) {
  438. std::string mod_name = lua_tostring(L, -1);
  439. // Builtin can access anything
  440. if (mod_name == BUILTIN_MOD_NAME) {
  441. if (write_allowed) *write_allowed = true;
  442. return true;
  443. }
  444. // Allow paths in mod path
  445. // Don't bother if write access isn't important, since it will be handled later
  446. if (write_required || write_allowed != NULL) {
  447. const ModSpec *mod = gamedef->getModSpec(mod_name);
  448. if (mod) {
  449. str = fs::AbsolutePath(mod->path);
  450. if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
  451. if (write_allowed) *write_allowed = true;
  452. return true;
  453. }
  454. }
  455. }
  456. }
  457. lua_pop(L, 1); // Pop mod name
  458. // Allow read-only access to all mod directories
  459. if (!write_required) {
  460. const std::vector<ModSpec> mods = gamedef->getMods();
  461. for (size_t i = 0; i < mods.size(); ++i) {
  462. str = fs::AbsolutePath(mods[i].path);
  463. if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
  464. return true;
  465. }
  466. }
  467. }
  468. str = fs::AbsolutePath(gamedef->getWorldPath());
  469. if (!str.empty()) {
  470. // Don't allow access to other paths in the world mod/game path.
  471. // These have to be blocked so you can't override a trusted mod
  472. // by creating a mod with the same name in a world mod directory.
  473. // We add to the absolute path of the world instead of getting
  474. // the absolute paths directly because that won't work if they
  475. // don't exist.
  476. if (fs::PathStartsWith(abs_path, str + DIR_DELIM + "worldmods") ||
  477. fs::PathStartsWith(abs_path, str + DIR_DELIM + "game")) {
  478. return false;
  479. }
  480. // Allow all other paths in world path
  481. if (fs::PathStartsWith(abs_path, str)) {
  482. if (write_allowed) *write_allowed = true;
  483. return true;
  484. }
  485. }
  486. // Default to disallowing
  487. return false;
  488. }
  489. int ScriptApiSecurity::sl_g_dofile(lua_State *L)
  490. {
  491. int nret = sl_g_loadfile(L);
  492. if (nret != 1) {
  493. lua_error(L);
  494. // code after this function isn't executed
  495. }
  496. int top_precall = lua_gettop(L);
  497. lua_call(L, 0, LUA_MULTRET);
  498. // Return number of arguments returned by the function,
  499. // adjusting for the function being poped.
  500. return lua_gettop(L) - (top_precall - 1);
  501. }
  502. int ScriptApiSecurity::sl_g_load(lua_State *L)
  503. {
  504. size_t len;
  505. const char *buf;
  506. std::string code;
  507. const char *chunk_name = "=(load)";
  508. luaL_checktype(L, 1, LUA_TFUNCTION);
  509. if (!lua_isnone(L, 2)) {
  510. luaL_checktype(L, 2, LUA_TSTRING);
  511. chunk_name = lua_tostring(L, 2);
  512. }
  513. while (true) {
  514. lua_pushvalue(L, 1);
  515. lua_call(L, 0, 1);
  516. int t = lua_type(L, -1);
  517. if (t == LUA_TNIL) {
  518. break;
  519. } else if (t != LUA_TSTRING) {
  520. lua_pushnil(L);
  521. lua_pushliteral(L, "Loader didn't return a string");
  522. return 2;
  523. }
  524. buf = lua_tolstring(L, -1, &len);
  525. code += std::string(buf, len);
  526. lua_pop(L, 1); // Pop return value
  527. }
  528. if (code[0] == LUA_SIGNATURE[0]) {
  529. lua_pushnil(L);
  530. lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
  531. return 2;
  532. }
  533. if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) {
  534. lua_pushnil(L);
  535. lua_insert(L, lua_gettop(L) - 1);
  536. return 2;
  537. }
  538. return 1;
  539. }
  540. int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
  541. {
  542. const char *path = NULL;
  543. if (lua_isstring(L, 1)) {
  544. path = lua_tostring(L, 1);
  545. CHECK_SECURE_PATH_INTERNAL(L, path, false, NULL);
  546. }
  547. if (!safeLoadFile(L, path)) {
  548. lua_pushnil(L);
  549. lua_insert(L, -2);
  550. return 2;
  551. }
  552. return 1;
  553. }
  554. int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
  555. {
  556. const char *chunk_name = "=(load)";
  557. luaL_checktype(L, 1, LUA_TSTRING);
  558. if (!lua_isnone(L, 2)) {
  559. luaL_checktype(L, 2, LUA_TSTRING);
  560. chunk_name = lua_tostring(L, 2);
  561. }
  562. size_t size;
  563. const char *code = lua_tolstring(L, 1, &size);
  564. if (size > 0 && code[0] == LUA_SIGNATURE[0]) {
  565. lua_pushnil(L);
  566. lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
  567. return 2;
  568. }
  569. if (luaL_loadbuffer(L, code, size, chunk_name)) {
  570. lua_pushnil(L);
  571. lua_insert(L, lua_gettop(L) - 1);
  572. return 2;
  573. }
  574. return 1;
  575. }
  576. int ScriptApiSecurity::sl_g_require(lua_State *L)
  577. {
  578. lua_pushliteral(L, "require() is disabled when mod security is on.");
  579. return lua_error(L);
  580. }
  581. int ScriptApiSecurity::sl_io_open(lua_State *L)
  582. {
  583. bool with_mode = lua_gettop(L) > 1;
  584. luaL_checktype(L, 1, LUA_TSTRING);
  585. const char *path = lua_tostring(L, 1);
  586. bool write_requested = false;
  587. if (with_mode) {
  588. luaL_checktype(L, 2, LUA_TSTRING);
  589. const char *mode = lua_tostring(L, 2);
  590. write_requested = strchr(mode, 'w') != NULL ||
  591. strchr(mode, '+') != NULL ||
  592. strchr(mode, 'a') != NULL;
  593. }
  594. CHECK_SECURE_PATH_INTERNAL(L, path, write_requested, NULL);
  595. push_original(L, "io", "open");
  596. lua_pushvalue(L, 1);
  597. if (with_mode) {
  598. lua_pushvalue(L, 2);
  599. }
  600. lua_call(L, with_mode ? 2 : 1, 2);
  601. return 2;
  602. }
  603. int ScriptApiSecurity::sl_io_input(lua_State *L)
  604. {
  605. if (lua_isstring(L, 1)) {
  606. const char *path = lua_tostring(L, 1);
  607. CHECK_SECURE_PATH_INTERNAL(L, path, false, NULL);
  608. }
  609. push_original(L, "io", "input");
  610. lua_pushvalue(L, 1);
  611. lua_call(L, 1, 1);
  612. return 1;
  613. }
  614. int ScriptApiSecurity::sl_io_output(lua_State *L)
  615. {
  616. if (lua_isstring(L, 1)) {
  617. const char *path = lua_tostring(L, 1);
  618. CHECK_SECURE_PATH_INTERNAL(L, path, true, NULL);
  619. }
  620. push_original(L, "io", "output");
  621. lua_pushvalue(L, 1);
  622. lua_call(L, 1, 1);
  623. return 1;
  624. }
  625. int ScriptApiSecurity::sl_io_lines(lua_State *L)
  626. {
  627. if (lua_isstring(L, 1)) {
  628. const char *path = lua_tostring(L, 1);
  629. CHECK_SECURE_PATH_INTERNAL(L, path, false, NULL);
  630. }
  631. int top_precall = lua_gettop(L);
  632. push_original(L, "io", "lines");
  633. lua_pushvalue(L, 1);
  634. lua_call(L, 1, LUA_MULTRET);
  635. // Return number of arguments returned by the function,
  636. // adjusting for the function being poped.
  637. return lua_gettop(L) - top_precall;
  638. }
  639. int ScriptApiSecurity::sl_os_rename(lua_State *L)
  640. {
  641. luaL_checktype(L, 1, LUA_TSTRING);
  642. const char *path1 = lua_tostring(L, 1);
  643. CHECK_SECURE_PATH_INTERNAL(L, path1, true, NULL);
  644. luaL_checktype(L, 2, LUA_TSTRING);
  645. const char *path2 = lua_tostring(L, 2);
  646. CHECK_SECURE_PATH_INTERNAL(L, path2, true, NULL);
  647. push_original(L, "os", "rename");
  648. lua_pushvalue(L, 1);
  649. lua_pushvalue(L, 2);
  650. lua_call(L, 2, 2);
  651. return 2;
  652. }
  653. int ScriptApiSecurity::sl_os_remove(lua_State *L)
  654. {
  655. luaL_checktype(L, 1, LUA_TSTRING);
  656. const char *path = lua_tostring(L, 1);
  657. CHECK_SECURE_PATH_INTERNAL(L, path, true, NULL);
  658. push_original(L, "os", "remove");
  659. lua_pushvalue(L, 1);
  660. lua_call(L, 1, 2);
  661. return 2;
  662. }