Skip to content

Instantly share code, notes, and snippets.

@mprymek
Created May 25, 2015 17:36
Show Gist options
  • Save mprymek/c3c3cac7e25404811001 to your computer and use it in GitHub Desktop.
Save mprymek/c3c3cac7e25404811001 to your computer and use it in GitHub Desktop.
Untrusted code compilation experiment in Elixir
defmodule SafeCode do
def compile code do
# we can use [existing_atoms_only: true] here
{:ok, qcode} = code |> Code.string_to_quoted()
unless safe? qcode do
raise "Code is unsafe"
else
qcode |> Code.compile_quoted
end
end
def safe?({:defmodule, _meta, items}) do
items |> Enum.all?(&safe?/1)
end
def safe?([do: x]), do: safe?(x)
# @TODO: do we have to check args?
def safe?({:def, _meta1, [{:main, _meta2, _args},body]}), do: safe?(body)
def safe?({:__block__, _meta, items}) do
items |> Enum.all?(&safe?/1)
end
def safe?({:unless, _meta, [condition, [do: body1, else: body2]]}) do
safe?(condition) and safe?(body1) and safe?(body2)
end
def safe?({:__aliases__, _meta, _args}), do: true
# variable
def safe?({x,_meta,nil}) when is_atom(x) do true end
# unary operators
def safe?({op,_meta,[arg]}) when op in [:!] do
safe? arg
end
# binary operators
def safe?({op,_meta,[arg1,arg2]}) when op in [:>,:<,:>=,:<=,:==,:===,:!=,:!==,:+,:-,:/,:*,:++,:--,:<>] do
safe?(arg1) and safe?(arg2)
end
# safe unary functions
@safe_functions_1 [:length]
def safe?({op,_meta,[arg1]}) when op in @safe_functions_1 do
safe? arg1
end
# lambda
# @TODO: do we have to check args?
def safe?({:fn, _meta1, [{:->, _meta2, [_args, body]}]}) do
safe? body
end
@safe_modfuns [{:Enum,:map}]
def safe?({{:., _meta1, [{:__aliases__, _meta2, [mod]}, fun]}, _meta3, args}) when {mod,fun} in @safe_modfuns do
args |> Enum.all?(&safe?/1)
end
def safe?(l) when is_list(l) do
l |> Enum.all?(&safe?/1)
end
def safe?(x) when is_atom(x) do true end
def safe?(x) when is_integer(x) do true end
def safe?(x) when is_binary(x) do true end
end
code = """
defmodule Main do
def main(x) do
unless length(x)<10 do
x
else
"x too large!"
end
end
end
"""
result = code |> SafeCode.compile
IO.puts inspect(result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment