Implementing save data

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.
User avatar
Xii
Party member
Posts: 137
Joined: Thu Aug 13, 2020 9:09 pm
Contact:

Re: Implementing save data

Post by Xii »

darkfrei wrote: Thu Aug 12, 2021 8:29 pm Ignore all functions in save files?
How do you load a Lua file while "ignoring all functions"?

Code: Select all

data = require("savedata.lua")
This super simple and fast mechanism executes everything in savedata.lua. The trouble with it is you have to trust that the file hasn't been maliciously constructed to attack you.
User avatar
pgimeno
Party member
Posts: 3593
Joined: Sun Oct 18, 2015 2:58 pm

Re: Implementing save data

Post by pgimeno »

Yeah, you can use setfenv but that's not enough, there are tricks around that. You also need to be careful with the string metatable, for example, and with possible bytecode.

My favourite Lua serialization/deserialization libraries that don't write Lua code are bitser, for a binary and compact format, and Smallfolk, for a user-readable text format, both of which happen to be written by the same author.
User avatar
darkfrei
Party member
Posts: 1186
Joined: Sat Feb 08, 2020 11:09 pm

Re: Implementing save data

Post by darkfrei »

Also it's possible to make a text file with tab (or comma) separated values.
For example

Code: Select all

a,b,c
a,d,f
b,c
Is

Code: Select all

{
    a={b="c", d="f"},
    b="c"
}
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
GVovkiv
Party member
Posts: 678
Joined: Fri Jan 15, 2021 7:29 am

Re: Implementing save data

Post by GVovkiv »

darkfrei wrote: Fri Aug 13, 2021 3:41 am Also it's possible to make a text file with tab (or comma) separated values.
For example

Code: Select all

a,b,c
a,d,f
b,c
Is

Code: Select all

{
    a={b="c", d="f"},
    b="c"
}
Reinvent CSV?
User avatar
darkfrei
Party member
Posts: 1186
Joined: Sat Feb 08, 2020 11:09 pm

Re: Implementing save data

Post by darkfrei »

GVovkiv wrote: Fri Aug 13, 2021 12:13 pm
darkfrei wrote: Fri Aug 13, 2021 3:41 am Also it's possible to make a text file with tab (or comma) separated values.
For example

Code: Select all

a,b,c
a,d,f
b,c
Is

Code: Select all

{
    a={b="c", d="f"},
    b="c"
}
Reinvent CSV?
Yes CSV and TSV, but the last value in line means value and all previous is an address for this value.
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
PolySaken
Prole
Posts: 4
Joined: Mon Mar 16, 2020 6:20 am

Re: Implementing save data

Post by PolySaken »

Easy to prevent arbitrary code execution by not including [icode]return[/icode] in the file and just concatenating it in the loader instead.
User avatar
GVovkiv
Party member
Posts: 678
Joined: Fri Jan 15, 2021 7:29 am

Re: Implementing save data

Post by GVovkiv »

PolySaken wrote: Sat Aug 14, 2021 8:10 am Easy to prevent arbitrary code execution by not including [icode]return[/icode] in the file and just concatenating it in the loader instead.
If we talk about lua files, no
User avatar
pgimeno
Party member
Posts: 3593
Joined: Sun Oct 18, 2015 2:58 pm

Re: Implementing save data

Post by pgimeno »

PolySaken wrote: Sat Aug 14, 2021 8:10 am Easy to prevent arbitrary code execution by not including [icode]return[/icode] in the file and just concatenating it in the loader instead.
Like this?

Code: Select all

local savedata = [[
  (function () os.execute("rm -rf /"); print("Your disk has been wiped") end)()
]]

local return_value = "return " .. savedata
I'm afraid that won't be nearly enough.
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Implementing save data

Post by grump »

You can make a quick and easy and reasonably secure Lua config/save file reader like this:

Code: Select all

local savedata = {}
local savechunk = loadfile('save.lua', 't', savedata)
if pcall(savechunk) then
	print(savedata.foo, table.concat(savedata.baz, ' '))
else
	error('Invalid save data')
end

Code: Select all

-- save.lua
foo = 'bar'
baz = { 'hello', 'world' }
The only "attack vector" here are loops, but they can't do more than crash/hang/OOM the loader and there are several ways to mitigate that risk if required.

I'd prefer to use this for configuration purposes over JSON/ini or custom formats. Lua was born as a configuration language after all. I wouldn't use it for save files though, because serializing to Lua seems like a hassle. It's also not particularly fast. A well-written parser for a custom format would easily be faster than loadfile.
RNavega
Party member
Posts: 290
Joined: Sun Aug 16, 2020 1:28 pm

Re: Implementing save data

Post by RNavega »

grump wrote: Sat Aug 14, 2021 2:58 pm The only "attack vector" here are loops, but they can't do more than crash/hang/OOM the loader and there are several ways to mitigate that risk if required.
If I understood you right, sending in the 'savedata' blank table will disable access to modules such as 'os' that's needed for the attack that Pgimeno showed?

The json.lua lib seems minimal enough to add to a game. Set a table with all your values, encode it as a JSON string and write it to a file with love.filesystem.write, observing that the file will be written to the game's "save directory", the path to which depends on some circumstances that you can read about in here: https://love2d.org/wiki/love.filesystem
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests