Need to prohibit application:stop/1 with my application on server. There must be only ability to do it with custom specially designated function. Is there any way to do it?
Need something like this:
(node@server.domain)3> application:stop(application_name).
{error,{can_t_stop,"Use application_name:stop/0 function instead"}}
(node@server.domain)3> application_name:stop().
ok
There were different scenarios that been causing troubles when were maintaining projects:
unexperienced employee made hard stop off application via remote shell
security precautions don’t allow to have unapproved application stop
handling cascade application stops on different nodes
etc
All of them related to strict performing some actions before application stopped. Need to have kind of anti-idiot-defence system (Already have this defence system, but all of it is outside Erlang, trying to find solution inside of Erlang). Need to find solution that will be kind of middle man in OTP Application stopping process scenario. And this middle man must be deciding allow or disallow application stop before even trying to stop.
There might be very different cases in real life, but all of them related to something that will allow or disallow application stop. Kind of checker defined parameters that could be customized. By OTP not every case could be done with it. The key point in this:
This function is called whenever an application has stopped. It is intended to be the opposite of Module:start/2 and is to do any necessary cleaning up. The return value is ignored.
Return value ignored … How to make it NOT ignored?
In iOS development the same approach released with Application Lifecycle, when before stopping must be successful few required steps.
unexperienced employee made hard stop off application via remote shell
The same employee could stop the whole node with q(). (I did it on more than one occasion - the muscle memory to log out of the shell was q()., but in case of a remote shell it stopped the remote node). The only way to stop unexperienced employee to make a mess of the live system is to not let them log in.
Partially, the problem seems to be on a higher layer. On one hand, you have some security restrictions by management/customer, on the other hand inexperienced users are given access to the red button.
One solution could be to have a outer perimeter, e.g. a web frontend, where lowly operators can perform simple maintenance tasks, and you give shell access only to senior engineers.
If you cannot do that, the last thing which came to my mind is a restricted shell:
When the restricted shell evaluates an expression and encounters a function call or an operator application, it calls a callback function (with information about the function call in question). This callback function returns true to let the shell go ahead with the evaluation, or false to abort it.
Need to prohibit application:stop/1 with my application
No, once that function is called your application has no way of preventing it being shut down.
You can run xref to ensure there are no static calls to that function, except for your approved call sites, but if the attacker (malice or inexperience) has access to calling code in your server they can call application:stop and it’s game over.
You could patch OTP to enforce your particular logic around application:stop, but that still doesn’t prevent the attacker from killing processes etc.
Security needs to be at the boundaries, once the attacker is inside it’s too late.
I also wonder what’s so special about this application. Having a random node restart shouldn’t be a problem in a cluster with appropriate redundancy.
Thx. Will try to do it. Never been using it. But it is still not about OTP Application. And it is partly outside of Erlang, especially if there are remote node.
Why is in your opinion security is only about outside hacker/attacker??? From my experience (currently processing CEH v12 certification, CEH = “Certified Ethical Hacking”) 75-85 percents of successful attacks performed from inside by using f-wording human factor. And usually companies not declaring about this “success” openly.
Patching OTP - maybe the solution or writing out own 'behavior" cloned and patched in following of our necessity. But it’s huge amount of coding.
It’s actually not a “huge amount of coding”.
Copy application.erl from the exact ERTS that you are using
Inject your own stuff
Compile it and put back into your ERTS
Alternatively, put it into some other directory and load it explicitly after startup (which requires code:unstick_dir on the kernel directory and then code:stick_dir after the reload, see code — kernel v10.1.1 on sticky modules)
You can then check with application:module_info() where it is loaded from.
I’m not saying that any of this is a good idea, though. Erlang’s shell is by default fully empowered to undo every layer that you put between an idiot and a stupid idea.
Using exclusively restricted shells is the only way to go, I think.