Increase safety/security of random user scripts

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
RonanZero
Citizen
Posts: 90
Joined: Mon Oct 20, 2014 3:33 am

Increase safety/security of random user scripts

Post by RonanZero »

One of my game's main features is that you can add your own code, graphics, sound etc. to the game and distribute it through an in game content browser. I want to give as much freedom as possible for the coders. For example they should be able to download assets including code from an external server too, so I don't waste so much expensive server space on user content.

But I need to keep the average user 99% safe from anything that could harm their running game/files or computer. There are also a few global variables (involving for example user log-in stuff) that I don't want external scripts to be able to read at all.

I know it's nearly impossible to be 100% safe against every possible piece of code but how can I make it the game can run require and run random .lua files with abritrary code in them and be 99% safe, by limiting what they can do?
while true do end;
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Increase safety/security of random user scripts

Post by Nixola »

lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Increase safety/security of random user scripts

Post by ivan »

If you're just loading data or assets it's fine. If you want to run Lua code then its gets tricky.

setfenv can help if you are running untrusted code.
Basically, it will limit the scope of the script so that you can't exploit the system through io. or os.execute.
It's good if you are only going to run pure Lua code - but how useful is that going to be in a game?
should be able to download assets including code from an external server too
Doesn't sound like a safe idea at all. I think it will be nearly impossible to make something like that secure.
Last edited by ivan on Sun Dec 24, 2017 2:27 pm, edited 1 time in total.
User avatar
RonanZero
Citizen
Posts: 90
Joined: Mon Oct 20, 2014 3:33 am

Re: Increase safety/security of random user scripts

Post by RonanZero »

Nixola wrote: Fri Dec 22, 2017 7:24 am setfenv.
Am I misunderstanding something or is setfenv really just for functions... because files can have more than just functions? How would I use that when requiring files?
while true do end;
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Increase safety/security of random user scripts

Post by zorg »

RonanZero wrote: Fri Dec 22, 2017 7:58 pm
Nixola wrote: Fri Dec 22, 2017 7:24 am setfenv.
Am I misunderstanding something or is setfenv really just for functions... because files can have more than just functions? How would I use that when requiring files?
Files are chunks, lua loads in chunks as functions, which, if you execute, will actually get the file processed and get back anything it returned at the end (or not).

Now, i'm not 100% sure if doing love.filesystem.load, then setfenv, and then executing the chunk would actually do what one might expect; that said, the PiL says this:
When you create a new function, it inherits its environment from the function creating it. Therefore, if a chunk changes its own environment, all functions it defines afterward will share this same environment. This is a useful mechanism for creating namespaces, as we will see in the next chapter.
Which to me seems like defining the environment on a loaded-but-not-yet-executed chunk will work as intended, making all functions inside it adhere to the set environment. (Also, technically, you can't use require anymore since that automatically executes the chunk after loading it, among other things...)

I feel like i must also mention that i once tried my hand at sandboxing in my own game engine prototype maybe 1-2 years back, but for some reason that i can't recall, using only setfenv didn't work for me, and i needed to do some other trickery as well, maybe something with metatables... sadly i cannot look at the code anymore so i can't be more helpful and/or specific. (It might have been just my own blunder that necessitated that though)

Oh, and you should probably sanitize out require (and any other potentially dangerous stuff) from the scripts you load, since it modifies globals, having the potential to break out of your sandbox.

Do enjoy the read: http://lua-users.org/wiki/SandBoxes
Last edited by zorg on Sun Dec 24, 2017 3:43 pm, edited 1 time in total.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Increase safety/security of random user scripts

Post by ivan »

Zorg, require is a global function so it will be locked out by setfenv too.
Personally, I use setfenv to load options/progress files saves in the appdata directory.

Pure Lua code:

Code: Select all

--- Loads Lua file from untrusted location
-- @param fn filename
-- @return boolean status and file return value
function _pdofile(fn)
  -- read and parse the file
  local f = io.open(fn, "r")
  if not f then
    -- cannot open file
    return false, "Cannot open:"..fn
  end
  local c = f:read("*all")
  f:close()
  local func, err = loadstring(c)
  if not func then
    -- syntax error
    return false, err
  end
  -- lock out the environment
  setfenv(func, {})
  -- execute
  return pcall(func)
end
Love2d version:

Code: Select all

--- Loads Lua file from untrusted location
-- @param fn filename
-- @return boolean status and file return value
function _pdofile(fn)
  -- read and parse the file
  local func, err = love.filesystem.load(fn)
  if not func then
    -- syntax error
    return false, err
  end
  -- lock out the environment
  setfenv(func, {})
  -- execute
  return pcall(func)
end
Of course an infinite loop would still crash the app, but it should be safe for the rest of the system.
So far I have NOT found any exploits in this code, but would love to get more feedback.

As I mentioned before, note that it's very hard to make your game logic completely safe to execute. :)
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Increase safety/security of random user scripts

Post by zorg »

ivan wrote: Sun Dec 24, 2017 2:48 pm Zorg, require is a global function so it will be locked out by setfenv too.
Whoops, i'll chalk that up to me being tired and at work :P
I edited my message accordingly, thanks for the correction.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 208 guests