diff options
-rw-r--r-- | ClientHamr/GuiLua/skang.lua | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua index a8a75ae..81e65af 100644 --- a/ClientHamr/GuiLua/skang.lua +++ b/ClientHamr/GuiLua/skang.lua | |||
@@ -1102,6 +1102,298 @@ GGG GUI Thing, but servlets can access them across the net. | |||
1102 | 1102 | ||
1103 | For servlet only modules from an applet, the applet only loads the skanglet class, using it for all | 1103 | For servlet only modules from an applet, the applet only loads the skanglet class, using it for all |
1104 | access to the module. | 1104 | access to the module. |
1105 | |||
1106 | |||
1107 | Lua Security best practices - | ||
1108 | |||
1109 | From an email by Mike Pall - | ||
1110 | |||
1111 | "The only reasonably safe way to run untrusted/malicious Lua scripts is | ||
1112 | to sandbox it at the process level. Everything else has far too many | ||
1113 | loopholes." | ||
1114 | |||
1115 | http://lua-users.org/lists/lua-l/2011-02/msg01595.html | ||
1116 | http://lua-users.org/lists/lua-l/2011-02/msg01609.html | ||
1117 | http://lua-users.org/lists/lua-l/2011-02/msg01097.html | ||
1118 | http://lua-users.org/lists/lua-l/2011-02/msg01106.html | ||
1119 | |||
1120 | So that's processes, not threads like LuaProc does. B-( | ||
1121 | |||
1122 | However, security in depth is good, so still worthwhile looking at it from other levels as well. | ||
1123 | |||
1124 | General solution is to create a new environment, which we are doing | ||
1125 | anyway, then whitelist the safe stuff into it, instead of blacklisting | ||
1126 | unsafe stuff. Coz you never know if new unsafe stuff might exist. | ||
1127 | |||
1128 | Different between 5.1 (setfenv) and 5.2 (_ENV) | ||
1129 | |||
1130 | http://lua-users.org/wiki/SandBoxes - | ||
1131 | |||
1132 | ------------------------------------------------------ | ||
1133 | -- make environment | ||
1134 | local env = -- add functions you know are safe here | ||
1135 | { | ||
1136 | ipairs = ipairs, | ||
1137 | next = next, | ||
1138 | pairs = pairs, | ||
1139 | pcall = pcall, | ||
1140 | tonumber = tonumber, | ||
1141 | tostring = tostring, | ||
1142 | type = type, | ||
1143 | unpack = unpack, | ||
1144 | coroutine = { create = coroutine.create, resume = coroutine.resume, | ||
1145 | running = coroutine.running, status = coroutine.status, | ||
1146 | wrap = coroutine.wrap }, | ||
1147 | string = { byte = string.byte, char = string.char, find = string.find, | ||
1148 | format = string.format, gmatch = string.gmatch, gsub = string.gsub, | ||
1149 | len = string.len, lower = string.lower, match = string.match, | ||
1150 | rep = string.rep, reverse = string.reverse, sub = string.sub, | ||
1151 | upper = string.upper }, | ||
1152 | table = { insert = table.insert, maxn = table.maxn, remove = table.remove, | ||
1153 | sort = table.sort }, | ||
1154 | math = { abs = math.abs, acos = math.acos, asin = math.asin, | ||
1155 | atan = math.atan, atan2 = math.atan2, ceil = math.ceil, cos = math.cos, | ||
1156 | cosh = math.cosh, deg = math.deg, exp = math.exp, floor = math.floor, | ||
1157 | fmod = math.fmod, frexp = math.frexp, huge = math.huge, | ||
1158 | ldexp = math.ldexp, log = math.log, log10 = math.log10, max = math.max, | ||
1159 | min = math.min, modf = math.modf, pi = math.pi, pow = math.pow, | ||
1160 | rad = math.rad, random = math.random, sin = math.sin, sinh = math.sinh, | ||
1161 | sqrt = math.sqrt, tan = math.tan, tanh = math.tanh }, | ||
1162 | os = { clock = os.clock, difftime = os.difftime, time = os.time }, | ||
1163 | } | ||
1164 | |||
1165 | -- run code under environment [Lua 5.1] | ||
1166 | local function run(untrusted_code) | ||
1167 | if untrusted_code:byte(1) == 27 then return nil, "binary bytecode prohibited" end | ||
1168 | local untrusted_function, message = loadstring(untrusted_code) | ||
1169 | if not untrusted_function then return nil, message end | ||
1170 | setfenv(untrusted_function, env) | ||
1171 | return pcall(untrusted_function) | ||
1172 | end | ||
1173 | |||
1174 | -- run code under environment [Lua 5.2] | ||
1175 | local function run(untrusted_code) | ||
1176 | local untrusted_function, message = load(untrusted_code, nil, 't', env) | ||
1177 | if not untrusted_function then return nil, message end | ||
1178 | return pcall(untrusted_function) | ||
1179 | end | ||
1180 | ------------------------------------------------------ | ||
1181 | |||
1182 | Also includes a table of safe / unsafe stuff. | ||
1183 | |||
1184 | |||
1185 | While whitelisting stuff, could also wrap unsafe stuff to make them more safe. | ||
1186 | |||
1187 | print() -> should reroute to our output widgets. | ||
1188 | rawget/set() -> don't bypass the metatables, but gets tricky and recursive. | ||
1189 | require -> don't allow bypassing the sandbox to get access to restricted modules | ||
1190 | package.loaded -> ditto | ||
1191 | |||
1192 | |||
1193 | Other things to do - | ||
1194 | |||
1195 | debug.sethook() can be used to call a hook every X lines, which can help with endless loops and such. | ||
1196 | Have a custom memory allocater, like edje_lua2 does. | ||
1197 | |||
1198 | ------------------------------------------------------ | ||
1199 | ------------------------------------------------------ | ||
1200 | |||
1201 | The plan - | ||
1202 | |||
1203 | Process level - | ||
1204 | Have a Lua script runner C program / library. | ||
1205 | It does the LuaProc thing, and the edje_lua2 memory allocater thing. | ||
1206 | Other code feeds scripts to it via a pipe. | ||
1207 | Unless they are using this as a library. | ||
1208 | It can be chrooted, ulimited, LXC containered, etc. | ||
1209 | It has an internal watchdog thread. | ||
1210 | The truly paranoid can have a watchdog timer process watch it. | ||
1211 | Watches for a "new Lua state pulled off the queue" signal. | ||
1212 | This could be done from the App that spawned it. | ||
1213 | |||
1214 | It runs a bunch of worker threads, with a queue of ready Lua states. | ||
1215 | Each Lua state being run has lua_sethook() set to run each X lines, AND a watchdog timer set. | ||
1216 | If either is hit, then the Lua state is put back on the queue. | ||
1217 | (Currently LuaProc states go back an the queue when waiting for a "channel message", which does a lua_yeild().) | ||
1218 | NOTE - apparently "compiled code" bypasses hooks, though there's an undocumented LuaJIT compile switch for that. http://lua-users.org/lists/lua-l/2011-02/msg01106.html | ||
1219 | EFL is event based. | ||
1220 | LSL is event based. | ||
1221 | LuaSL is event based. | ||
1222 | Java skang is event based, with anything that has long running stuff overriding runBit(). | ||
1223 | Coz Java AWT is event based, the "events" are over ridden methods in each widget class. | ||
1224 | Should all work if we keep this as event based. | ||
1225 | An "event" is a bit of Lua script in a string, at Input trust level usually. | ||
1226 | Configurable for this script runner is - | ||
1227 | IP address & port, or pipe name. | ||
1228 | Security level to run at, defaults to Network. | ||
1229 | Number of worker threads, defaults to number of CPUs. | ||
1230 | Memory limit per Lua state. | ||
1231 | Lines & time per tick for Lua states. | ||
1232 | |||
1233 | Different levels of script trust - | ||
1234 | System - the local skang and similar stuff. | ||
1235 | -> No security at all. | ||
1236 | App - Lua scripts and C from the running application. | ||
1237 | -> Current module level security. | ||
1238 | Each has it's own environment, with no cross environment leakage. | ||
1239 | Runs in the Apps process, though that might be the script runner as a library. | ||
1240 | Or could be skang's main loop. | ||
1241 | Local - Lua scripts and skang files sent from the client apps running on the same system. | ||
1242 | -> As per App. | ||
1243 | Runs in a script runner, maybe? Or just the Apps script runner. | ||
1244 | Limit OS and file stuff, the client app can do those itself. | ||
1245 | Network - Lua scripts and skang files sent from the network. | ||
1246 | -> Runs in a script runner. | ||
1247 | Option to chroot it, ulimit it, etc. | ||
1248 | Heavily Lua sandboxed via environment. | ||
1249 | It can access nails, but via network derived credentials. | ||
1250 | Can have very limited local storage, not direct file access though, but via some sort of security layer. | ||
1251 | Can have network access. | ||
1252 | Can have GUI access, but only to it's own window. | ||
1253 | Config - Lua scripts run as configuration files. | ||
1254 | -> Almost empty local environment, can really only do math and set Things. | ||
1255 | Input - Lua scripts run as a result of hitting skang widgets on the other end of a socket. | ||
1256 | -> As per Config, but can include function calls. | ||
1257 | Also would need sanitizing, as this can come from the network. | ||
1258 | Microsoft - Not to be trusted at all. | ||
1259 | Apple - Don't expect them to trust us. | ||
1260 | |||
1261 | NOTE - edje_lua2 would be roughly Local trust level. | ||
1262 | |||
1263 | So we need to be able to pass Lua between processes - | ||
1264 | Have to be able to do it from C, from Lua, and from Lua embedded in C. | ||
1265 | edje_lua2 - uses Edje messages / signals. | ||
1266 | LuaSL - uses Ecore_Con, in this case a TCP port, even though it's only local. | ||
1267 | LuaSL mainloop for it's scripts is to basically wait for these messages from LuaProc. | ||
1268 | Which yield's until we get one. | ||
1269 | Eventually gets Lua code as a string -> loadstring() -> setfenv() -> pcall() | ||
1270 | The pcall returns a string that we send back as a LuaProc message. | ||
1271 | Extantz - we want to use stdin/stdout for the pipe, but otherwise LuaSL style semantics. | ||
1272 | |||
1273 | Hmm, Extantz could run external skang modules in two ways - | ||
1274 | Run the module as a separate app, with stdin/stdout. | ||
1275 | Require the module, and run it internally. | ||
1276 | Stuff like the in world editor and radar would be better as module, since they are useless outside Extantz? | ||
1277 | Radar is useless outside Extantz, editor could be used to edit a local file. | ||
1278 | Stuff like woMan would be better off as a separate application, so it can start and stop extantz. | ||
1279 | |||
1280 | ]] | ||
1281 | |||
1282 | |||
1283 | --[[ | ||
1284 | The main loop. | ||
1285 | A Lua skang module is basically a table, with skang managed fields. | ||
1286 | Once it calls moduleEnd(), it's expected to have finished. | ||
1287 | test.lua is currently an exception, it runs test stuff afterwards. | ||
1288 | So their code just registers Things and local variables. | ||
1289 | Some of those Things might be functions for manipulating internal module state. | ||
1290 | A C module has it's variables managed outside of it by Lua. | ||
1291 | So would have to go via LUA_GLOBALSINDEX to get to them. | ||
1292 | Unless they are userdata, which are C things anyway. | ||
1293 | Though it's functions are obviously inside the C module. | ||
1294 | Normal Lua module semantics expect them to return to the require call after setting themselves up. | ||
1295 | So test.lua is really an aberation. | ||
1296 | |||
1297 | Soooo, where does the main loop go? | ||
1298 | The skang module itself could define the main loop. | ||
1299 | Should not actually call it though, coz skang is itself a module. | ||
1300 | |||
1301 | In Java we had different entry points depending on how it was called. | ||
1302 | If it was called as an applet or application, it got it's own thread with a mainloop. | ||
1303 | That main loop just slept and called runBit() on all registered modules. | ||
1304 | If it was loaded as a module, it bypassed that stuff. | ||
1305 | I don't think Lua provides any such mechanism. | ||
1306 | In theory, the first call to moduleBegin would be the one that was started as an application. | ||
1307 | So we could capture that, and test against it in moduleEnd to find when THAT module finally got to the end. | ||
1308 | THEN we can start the main loop (test.lua being the exception that fucks this up). | ||
1309 | Though test.lua could include a runBits() that quits the main loop, then starts the main loop at the very end once more? | ||
1310 | The problem with this is applications that require skang type modules. | ||
1311 | The first one they require() isn't going to return. | ||
1312 | Eventually skang itself will get loaded. It looks at the "arg" global, which SHOULD be the command line. | ||
1313 | Including the name of the application, which we could use to double check. | ||
1314 | Extantz / script runner would set this arg global itself. | ||
1315 | |||
1316 | Skang applications have one main loop per app. | ||
1317 | Skang modules use the main loop of what ever app called them. | ||
1318 | Non skang apps have the option of calling skangs main loop. | ||
1319 | Extantz starts many external skang apps, which each get their own main loop. | ||
1320 | Extantz has it's own Ecore main loop. | ||
1321 | LuaSL still has one main loop per script. | ||
1322 | LSL scripts get their own main loop, but LSL is stupid and doesn't have any real "module" type stuff. | ||
1323 | |||
1324 | What does skang main loop actually do? | ||
1325 | In Java it just slept for a bit, then called runBit() from each module, and the only module that had one was watch. | ||
1326 | Actually better off using Ecore timers for that sort of thing. | ||
1327 | Skang main loop has nothing to do? lol | ||
1328 | Well, except for the "wait for LuaProc channel messages" thing. | ||
1329 | Widget main loop would be Ecore's main loop. | ||
1330 | |||
1331 | Extantz loads a skang module. | ||
1332 | Module runs in extantz script runner. | ||
1333 | Module runs luaproc message main loop from skang. | ||
1334 | Evas / Elm widgets send signals, call C callbacks. | ||
1335 | Extantz sends Lua input scripts via luaproc messages to module. | ||
1336 | Extantz runs separate skang module. | ||
1337 | Module runs in it's own process. | ||
1338 | Module runs it's own message loop on the end of stdin. | ||
1339 | Evas / Elm widgets send signals, call C callbacks. | ||
1340 | Extantz sends Lua Input scripts to module via stdout. | ||
1341 | Module runs stand alone. | ||
1342 | Module runs in it's own process. | ||
1343 | Module has to have widget start Ecore's main loop. | ||
1344 | Module runs it's own message loop, waiting for widget to send it messages. | ||
1345 | Evas / Elm widgets send signals, call C callbacks. | ||
1346 | Widget sends Lua Input scripts to module. | ||
1347 | |||
1348 | Alternate plan - | ||
1349 | Skang has no main loop, modules are just tables. | ||
1350 | OK, so sometimes skang has to start up an Ecore main loop. | ||
1351 | With either Ecore_Con, or Evas and Elm. | ||
1352 | skang.message(string) | ||
1353 | Call it to pass a bit of Lua to skang, which is likely Input. | ||
1354 | Widget twiddles happen in Ecore's main loop, via signals and call backs. | ||
1355 | Eventually these call backs hit the widgets action string. | ||
1356 | Send that action string to skang.message(). | ||
1357 | |||
1358 | Extantz loads a skang module. | ||
1359 | Extantz has a skang Lua state. | ||
1360 | Module is just another table in skang. | ||
1361 | Widget -> callback -> action string -> skang.message() | ||
1362 | Extantz runs separate skang module. | ||
1363 | Skang module C code runs an Ecore main loop. | ||
1364 | Module is just another table in skang. | ||
1365 | Skang C uses Ecore_Con to get messages from Extantz' Ecore_Con. | ||
1366 | Widget -> callback -> action string -> Ecore_Con -> skang.message() | ||
1367 | OOORRRR .... | ||
1368 | Skang runs a main loop reading stdin. | ||
1369 | Widget -> callback -> action string -> stdout -> skang.message() | ||
1370 | Module runs stand alone. | ||
1371 | Skang module C code runs an Ecore main loop. | ||
1372 | Module is just another table in skang. | ||
1373 | Widget -> callback -> action string -> skang.message() | ||
1374 | Extantz loads a skang module from the network. | ||
1375 | Skang module runs on the server with it's own Ecore main loop somehow. | ||
1376 | Module is just another table in skang. | ||
1377 | Extantz uses Ecore_Con to get messages from Extantz' Ecore_Con, via TCP. | ||
1378 | Widget -> callback -> action string -> Ecore_Con -> skang.message() | ||
1379 | OOORRRR .... | ||
1380 | Remember, these are untrusted, so that's what the script runner is for. | ||
1381 | Skang module runs in the script runner, with some sort of luaproc interface. | ||
1382 | Widget -> callback -> action string -> Ecore_Con -> luaproc -> skang.message() | ||
1383 | |||
1384 | Skang running as a web server. | ||
1385 | Skang runs an Ecore main loop. | ||
1386 | Skang has an Ecore_Con server attached to port 80. | ||
1387 | Skang loads modules as usual. | ||
1388 | Skang responds to specific URLs with HTML forms generated from Skang files. | ||
1389 | Skang gets post data back, which kinda looks like Input. B-) | ||
1390 | |||
1391 | Extantz runs a LuaSL / LSL script from the network. | ||
1392 | Send this one to the LuaSL script runner. | ||
1393 | Coz LSL scripts tend to have lots of copies with the same name in different objects. | ||
1394 | Could get too huge to deal with via "just another table". | ||
1395 | In this case, compiling the LSL might be needed to. | ||
1396 | |||
1105 | ]] | 1397 | ]] |
1106 | 1398 | ||
1107 | 1399 | ||