lua string math and loadstring

lua string math and loadstring

Postby Kilarin » Sun Mar 31, 2019 5:47 pm

in a project I'm working on, I end up with a string that is a mathematical equation. like:
local equation="8+5"
there should be NOTHING but numbers and mathematical operators in the string, and I can, of course, verify that in the code.
but I need to convert that equation into an actual number.
I had a fancy schmancy Java routine that would handle all kinds of string math. I'm trying to determine how to do this in lua.
It looks like I could accomplish this using loadstring?

BUT, loadstring looks like a very risky thing to implement. With sufficient code checks to ensure there will be no arbitrary lua code execution, is loadstring considered acceptable in minetest mods?

Is there some other built in way to convert string equations into actual numerical results?
Kilarin
Member
 
Posts: 717
Joined: Mon Mar 10, 2014 12:36 am

Re: lua string math and loadstring

Postby Kilarin » Mon Apr 01, 2019 4:25 am

Never mind. I think I worked out a nice routine with a good whitest that should handle the problem. Will post if anyone wishes to critique it.
Kilarin
Member
 
Posts: 717
Joined: Mon Mar 10, 2014 12:36 am

Re: lua string math and loadstring

Postby ShadMOrdre » Mon Apr 01, 2019 3:53 pm

Please do let us view the code.
ShadMOrdre
Member
 
Posts: 272
Joined: Mon Dec 29, 2014 8:07 am
GitHub: ShadMOrdre
In-game: shadmordre

Re: lua string math and loadstring

Postby Kilarin » Mon Apr 01, 2019 11:29 pm

Code: Select all
--does string math
--acceptable values:
--numbers .+-*/^ ()
--math library functions
--this function does this validation so that you can be certain it cant execute arbitrary lua code.
--vars array is optional, if you pass in an array of variables and values they will be substituted before calculation
--********************************
function string_math(str,vars)
    for k,v in pairs(vars) do
      str=string.gsub(str,k,v)
    end --for 
  end --if 
  --now all variables have been substituted, test if string is math ONLY
  --(do not allow arbitrary lua code execution) 
  --is there a reason to define this array globaly or external to the function?   
  local allowed={"math%.abs","math%.acos","math%.asin","math%.atan","math%.ceil",
    "math%.cos","math%.deg","math%.exp","math%.floor","math%.fmod","math%.huge",
    "math%.log","math%.max","math%.maxinteger","math%.min","math%.mininteger",
    "math%.modf","math%.pi","math%.rad","math%.random","math%.randomseed",
    "math%.sin","math%.sqrt","math%.tan","math%.tointeger","math%.type","math%.ult",
    "1","2","3","4","5","6","7","8","9","%.","+","-","*","/","%^","%(","%)",","," "}       
  local test=str 
  for k,v in pairs(allowed) do
    test=string.gsub(test,v,"0")  --change EVERYTHING that is allowed into 0 
  end --for a
  --so why change everything to 0 instead of just ""?  paranoia, it means
  --something like mathmath.pi.floor cant slip through, although I am not
  --certain what someone could do with that anyway
  --math.pi3 CAN slip through, but again, I'm not certain what someone could
  --do with that.
  test=string.gsub(test,"0","")  --remove all zeros
  local rslt=""
  if test=="" then --if the string was good, it should now be empty
    rslt=loadstring("return "..str.."+0")()
  else
    rslt="Invalid String"
  end --if test=="" 
 
return rslt
end  --string_math



---example call:
Code: Select all
local vars={clowns=3,monkeys=5,ringmasters=1}

str="math.floor((clowns+monkeys)/(ringmasters*math.pi))" --this would probably be read in from a settings file
circus=string_math(str,vars)

and now circus=2

So, what is the purpose of this?
I'm using it to allow values as formulas to be put into a settings file instead of having to be coded into the init.lua
So the user can say in the setting file:
tentsize=(monkeys*clowns)/ringmasters
and my lua can read that in and calculate the result on the fly.

I think a settings file is a bit more accessible for many users.
PLUS, it has the advantage that updating the code does not wipe out all of the users settings/preferences.
I just needed a way to be able to do MATH on the settings with variables so the user could enter formulas. But I'm paranoid and wanted to try and limit arbitrary lua code execution
Kilarin
Member
 
Posts: 717
Joined: Mon Mar 10, 2014 12:36 am

Re: lua string math and loadstring

Postby ShadMOrdre » Tue Apr 02, 2019 7:24 am

Thanks for posting.

Try the str_helpers mod. Might be useful for breaking apart strings, or show you how to code something else.
ShadMOrdre
Member
 
Posts: 272
Joined: Mon Dec 29, 2014 8:07 am
GitHub: ShadMOrdre
In-game: shadmordre

Re: lua string math and loadstring

Postby rubenwardy » Tue Apr 02, 2019 10:39 am

Manually parsing strings like that is insecure and really not a good idea.

Use a sandbox instead, see how mesecon's lua controller does it: https://github.com/minetest-mods/meseco ... #L436-L553
rubenwardy
Moderator
 
Posts: 5717
Joined: Tue Jun 12, 2012 6:11 pm
GitHub: rubenwardy
In-game: rubenwardy

Re: lua string math and loadstring

Postby Kilarin » Tue Apr 02, 2019 1:36 pm

THAT is exactly what I came here for.   White listing is certainly better than Black listing, but it still left my nerves on edge.  This will be a better solution.

THANK YOU!
Kilarin
Member
 
Posts: 717
Joined: Mon Mar 10, 2014 12:36 am

Re: lua string math and loadstring

Postby Kilarin » Mon Apr 08, 2019 2:22 am

Is this properly implemented sandboxing?

Code: Select all
--********************************
function luautils.string_math(str,vars)
  if vars~=nil then --substitute variables
    for k,v in pairs(vars) do
      str=string.gsub(str,k,v)
    end --for 
  end --if 
  --sandbox for security (do not allow arbitrary lua code execution) 
  local env = {loadstring=loadstring, math = {
    abs = math.abs,
    acos = math.acos,
    asin = math.asin,
    atan = math.atan,
    atan2 = math.atan2,
    ceil = math.ceil,
    cos = math.cos,
    cosh = math.cosh,
    deg = math.deg,
    exp = math.exp,
    floor = math.floor,
    fmod = math.fmod,
    frexp = math.frexp,
    huge = math.huge,
    ldexp = math.ldexp,
    log = math.log,
    log10 = math.log10,
    max = math.max,
    min = math.min,
    modf = math.modf,
    pi = math.pi,
    pow = math.pow,
    rad = math.rad,
    random = math.random,
    sin = math.sin,
    sinh = math.sinh,
    sqrt = math.sqrt,
    tan = math.tan,
    tanh = math.tanh,
    }}   
   
  local f=function() return loadstring("return "..str.."+0")() end

  setfenv(f,env)
  local rslt=f()
 
  return rslt
end  --string_math
Kilarin
Member
 
Posts: 717
Joined: Mon Mar 10, 2014 12:36 am



Return to Modding Discussion



Who is online

Users browsing this forum: Yandex Bot [Bot] and 0 guests