Preventing atom exhaustion
Erlang
- Use list_to_existing_atom/1 instead of list_to_atom/1
- Use binary_to_existing_atom/1,2 instead of binary_to_atom/1,2
- Use the
safe
option when calling binary_to_term/2 on untrusted input (see also Serialisation and deserialisation) - Do not use file:consult/1 or file:path_consult/2 on untrusted input (see also Serialisation and deserialisation)
Elixir
- Use String.to_existing_atom/1 instead of String.to_atom/1
- Use List.to_existing_atom/1 instead of List.to_atom/1
- Use Module.safe_concat/1,2 instead of Module.concat/1,2
- Do not use interpolation to create atoms:
:"new_atom_#{index}"
:'new_atom_#{index}'
~w[row_#{index} column_#{index}]a
- Use the
:safe
option when calling :erlang.binary_to_term/2 on untrusted input (see also Serialisation and deserialisation)
Background
Each unique atom value in use in the virtual machine takes up an entry in the global atom table. New atom values are appended to this table as needed, but entries are never removed. The size of the table is determined at startup, based on the +t
emulator flag, with a default of 1.048.576 entries. If an attempt is made to add a new value while the table is at capacity, the virtual machine crashes.
Because of the above, care should be taken to not create an unbounded number of atoms. In particular, creating atoms from untrusted input can lead to denial-of-service (DoS) vulnerabilities.
The best way to prevent atom exhaustion is by ensuring no new atom values are created at runtime: as long as any atom value required by the application is referenced in code, that value will be defined in the atom table when the code is loaded (e.g. at release startup). The conversion of other types into atoms can then be constrained to only allow existing values using the ...to_existing_atom/1
function variants.
Beware of functions in applications/libraries that create atoms from input values. For instance, the xmerl_scan XML parser that comes with Erlang/OTP generates atoms from XML tag and attribute names (see Erlang standard library: xmerl), and the http_uri:parse/1 function in the ‘inets’ application converts the URI scheme to an atom (see Erlang standard library: inets).
Consider using instrumentation to monitor the value of erlang:system_info(atom_count) relative to erlang:system_info(atom_limit), and generate an alert when the atom count continues to increase after startup or when it crosses a threshold.
Next: Serialisation and deserialisation »