Idea about implementing a SECCOMP alike mechanism in BEAM

Lukas Larsson lukas@REDACTED
Wed Dec 11 08:38:38 CET 2019


Hello,

It has been a while since it was published but maybe you will find this
interesting: http://www.erlang.se/publications/xjobb/0109-naeser.pdf

Lukas

On Wed, Dec 11, 2019 at 6:07 AM Henrique Marcomini <henrique4win@REDACTED>
wrote:

> Hi,
>
>   I've been working with erlang/elixir for the past year and I really miss
> SECCOMP like features in the BEAM. So I started an implementation based on
> https://github.com/erlang/otp and I wanted to know what you people think
> about
> it.
>
>   The idea is to provide a way to blacklist/whitelist function calls on a
> process level, so for example if I'm evaluating human input for a
> calculation,
> I can guarantee that no other function except the ones that are necessary
> are
> called. Going further, in a case where my erlang cookie is leaked, I know
> that only a limited set of functions are callable using rpc or
> node.spawn/2.
>
>   The way I envision it (and I'm implementing it) is adding a byte to the
> process struct with the following meaning:
>
>    0 1 2 3 4 5 6 7
>   +-+-+-+-+-+-+-+-+
>   |E|M|S|I|U|U|U|U|
>   +-+-+-+-+-+-+-+-+
>
>   Where:
>     E -> Whether the mechanism is active (0:Off/1:On)
>     M -> Operation Mode (0:Whitelist/1:Blacklist)
>     S -> Disable Spawn (0:Can spawn new process/1:Cannot spawn new process)
>     I -> Whether a child process will inherit the
>     U -> Unused
>
>   There are some implicit rule in this byte:
>     - M,S, and I are unused whether E is set to 0
>     - I is unused if S is set to 1
>
>   I choosed to use a byte because bitwise operation are cheap and are the
> least
> expensive way I could think, and bitmasks can be combined in a meaningful
> way.
>
>   The verification of this byte would occur at the apply function, so we
> can
> check the byte every time a function is called. To know which function is
> whitelisted/blacklisted I added an Eterm to the process struct. This Eterm
> is a
> NIL terminated list of tuples, each tuple contains two atoms representing
> the
> module name and the function name which is whitelisted/blacklisted.
>
>   Probably a hashmap, or a binary tree of hashs would be quicker to search.
> But I don't know if there is any good low level way to introduce it without
> adding a lot of code to the code base.
>
>   To implement process inherit capabilites, I added a verification on
> spawn,
> but there are some possible bypasses that would need to be treated latter
> on.
>
>   For example:
>
>
> -------------------------------------------------------------------------------
>
>   If there is a process running as a dynamic supervisor (P1), some other
> process (P2) may send a message to spawn some worker (P5) and the father
> process would be the supervisor (P1), which may not have the mechanism
> active.
>
> Diagram below:
>
>
>              |                              |
>              |  P1 - Dynamic Supervisor     | P2 (With active mechanism)
>              V                              |
>       ===============                       |
>       | P3   | P4                           V
>       V      V
>
>   When P2 asks P1 to spawn a new worker, the diagram will look like the
> following:
>
>
>              |                              |
>              |  P1 - Dynamic Supervisor     | P2 (With active mechanism)
>              V                              |
>       ===============                       |
>       | P3   | P4   | P5                    V
>       V      V      V
>
>   Where P3, P4, and P5 are spawned with P1 as a parent, so it will not
> inherit
> any rules from P2. At this point P5 can execute any code and send a
> message to
> P2, bypassing the mechanism.
>
>
> -------------------------------------------------------------------------------
>
>   On another case a process (P1) on Node 1 which is under this mechanism
> may
> spawn another process (P2) to Node 2, and then P1 spawns another process
> (P3)
> on Node 1. If process generated by spawns of other nodes are less secure
> than
> the process that called the spawn function, it will lead to privilege
> escalation.
>
> Diagram below:
>
>  +---------------+              +---------------+
>  |               |              |               |
>  |    Node 1     |              |    Node 2     |
>  |               |              |               |
>  |        P1     |   spawn/2    |               |
>  |   ------------> -------------> --------+     |
>  |       calls   |              |         |     |
>  |               |              |         | P2  |
>  |               |              |         |     |
>  |        P3     |   spawn/2    |  calls  |     |
>  |   <---------- <------------- <---------+     |
>  |               |              |               |
>  +---------------+              +---------------+
>
>   If P3 restrictions are less strict than P1, then P1 escalated privilege.
>
>
> -------------------------------------------------------------------------------
>
>   The code that I'm working is at
> https://github.com/Supitto/OTP/tree/maint
> and it is built upon the maint branch. It still quite imature and have some
> edges to trim (I'm still figthing with allocations and Eterms). But if this
> idea is apreciated I will implement everything on the main branch. Also if
> you can think of some other scenario where this mechanism is defeated,
> please
> infome me :D
>
> Thanks,
>
> Henrique Almeida Marcomini
>
> Telegram -> @supitto
> IRC (freenode) -> Supitto
>
> Ps. The code on the repo may be not working (depends on the commit), but
> the
>     idea is there.
>
> Pps. I made everything in ASCII so to see it properly use monospace fonts
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20191211/2072aa37/attachment.htm>


More information about the erlang-questions mailing list