cliffclick / aa

Cliff Click Language Hacking
Apache License 2.0
272 stars 21 forks source link

Controlling the environment passed to eval #11

Open cliffclick opened 2 years ago

cliffclick commented 2 years ago

Code from https://github.com/AaronGoldman

sys.call(code, locals)

If I want to call a function but inject my environment into the function being called If the env is not specified then the env is the environment where the function was defined

func = {arg1, arg2 -> sys.print( arg1 + arg2 ) }
func2 = { . -> sys.print( arg1, arg2 )}

func(sys=filtered(sys), arg1=1, arg2=2)  \\ could inject extra args to blind call target
func2(sys=filtered(sys)) \\ can't see what func did

my_env = @{}
sys.call(code=func, env=my_env) # all locals defined but not cleared is now in my_env
sys.call(code=func2, env=my_env) # func2 now has access to what func did
if={predicate -> {consequence -> {alternative ->
    if_env = @{}
    sys.call(predicate, if_env)
        ? sys.call(consequence, if_env)
        : sys.call(alternative, if_env)
}}}
Env is a sequence of namespaces
    The local namespace seeded with the args extended by ‘=’ and ‘:=’
        This is the env I want to pass in at call site
        Dependant on the call site
    The closure namespace the environment where the function was defined.
        This is the env that should be filterable at the definition site. Particularly the sys object.
        Same for all call sites

The local namespace shadows the closure namespace and lookup should search them in order.

By shadowing the sys object or any other symbol you have blinded the function to that symbol from the def environment. If the function can get at the sys object from the closure environment you have a security hole.

Does this make any sense?