Discussion:
Kill a NIF's process
Robert Harris
2021-04-21 16:05:31 UTC
Permalink
Hello all.

Suppose there is a dirty NIF that is associated with a resource object
initialised with a down callback. Further, the NIF is passed some term
that it spends a long time examining; for the sake of argument, it
repeatedly reads the memory underlying a binary.

If the process is killed, e.g. by exit/2, is the NIF's resource object's
down callback called before the VM releases terms in the victim's
environment (e.g. the term whose memory the NIF is reading)? If so,
does releasing block on the down callback?

Regards,

Robert Harris
Confidentiality Notice | This email and any included attachments may be privileged, confidential and/or otherwise protected from disclosure. Access to this email by anyone other than the intended recipient is unauthorized. If you believe you have received this email in error, please contact the sender immediately and delete all copies. If you are not the intended recipient, you are notified that disclosing, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited.

Disclaimer

The information contained in this communication from the sender is confidential. It is intended solely for use by the recipient and others authorized to receive it. If you are not the recipient, you are hereby notified that any disclosure, copying, distribution or taking action in relation of the contents of this information is strictly prohibited and may be unlawful.

This email has been scanned for viruses and malware, and may have been automatically archived by Mimecast, a leader in email security and cyber resilience. Mimecast integrates email defenses with brand protection, security awareness training, web security, compliance and other essential capabilities. Mimecast helps protect large and small organizations from malicious activity, human error and technology failure; and to lead the movement toward building a more resilient world. To find out more, visit our website.
Sverker Eriksson
2021-04-21 16:37:41 UTC
Permalink
At process termination the deallocation of the heap is delayed until a running
dirty NIF has returned. This to make sure the dirty NIF can safely continue
read its arguments.



The firing of links and monitors (including NIF monitor down calls), on the
other hand, are not delayed by a running dirty NIF.



I hope that answered the question.



/Sverker, Erlang/OTP



From: erlang-questions <erlang-questions-***@erlang.org> On Behalf Of
Robert Harris
Sent: den 21 april 2021 18:06
To: erlang-***@erlang.org
Subject: Kill a NIF's process



Hello all.

Suppose there is a dirty NIF that is associated with a resource object
initialised with a down callback. Further, the NIF is passed some term
that it spends a long time examining; for the sake of argument, it
repeatedly reads the memory underlying a binary.

If the process is killed, e.g. by exit/2, is the NIF's resource object's
down callback called before the VM releases terms in the victim's
environment (e.g. the term whose memory the NIF is reading)? If so,
does releasing block on the down callback?

Regards,

Robert Harris
Confidentiality Notice | This email and any included attachments may be
privileged, confidential and/or otherwise protected from disclosure. Access to
this email by anyone other than the intended recipient is unauthorized. If you
believe you have received this email in error, please contact the sender
immediately and delete all copies. If you are not the intended recipient, you
are notified that disclosing, copying, distributing or taking any action in
reliance on the contents of this information is strictly prohibited.



Disclaimer

The information contained in this communication from the sender is
confidential. It is intended solely for use by the recipient and others
authorized to receive it. If you are not the recipient, you are hereby
notified that any disclosure, copying, distribution or taking action in
relation of the contents of this information is strictly prohibited and may be
unlawful.

This email has been scanned for viruses and malware, and may have been
automatically archived by Mimecast, a leader in email security and cyber
resilience. Mimecast integrates email defenses with brand protection, security
awareness training, web security, compliance and other essential capabilities.
Mimecast helps protect large and small organizations from malicious activity,
human error and technology failure; and to lead the movement toward building a
more resilient world. To find out more, visit our website.
Max Lapshin
2021-04-21 19:37:02 UTC
Permalink
We have a nice hardware that requires asynchronous termination, so we
wrap each NIF object inside a process that "is not supposed to die"
and this process becomes a wrapper that tracks its own erlang-level
ref count.

On Wed, Apr 21, 2021 at 7:37 PM Sverker Eriksson
At process termination the deallocation of the heap is delayed until a running dirty NIF has returned. This to make sure the dirty NIF can safely continue read its arguments.
The firing of links and monitors (including NIF monitor down calls), on the other hand, are not delayed by a running dirty NIF.
I hope that answered the question.
/Sverker, Erlang/OTP
Sent: den 21 april 2021 18:06
Subject: Kill a NIF's process
Hello all.
Suppose there is a dirty NIF that is associated with a resource object
initialised with a down callback. Further, the NIF is passed some term
that it spends a long time examining; for the sake of argument, it
repeatedly reads the memory underlying a binary.
If the process is killed, e.g. by exit/2, is the NIF's resource object's
down callback called before the VM releases terms in the victim's
environment (e.g. the term whose memory the NIF is reading)? If so,
does releasing block on the down callback?
Regards,
Robert Harris
Confidentiality Notice | This email and any included attachments may be privileged, confidential and/or otherwise protected from disclosure. Access to this email by anyone other than the intended recipient is unauthorized. If you believe you have received this email in error, please contact the sender immediately and delete all copies. If you are not the intended recipient, you are notified that disclosing, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited.
Disclaimer
The information contained in this communication from the sender is confidential. It is intended solely for use by the recipient and others authorized to receive it. If you are not the recipient, you are hereby notified that any disclosure, copying, distribution or taking action in relation of the contents of this information is strictly prohibited and may be unlawful.
This email has been scanned for viruses and malware, and may have been automatically archived by Mimecast, a leader in email security and cyber resilience. Mimecast integrates email defenses with brand protection, security awareness training, web security, compliance and other essential capabilities. Mimecast helps protect large and small organizations from malicious activity, human error and technology failure; and to lead the movement toward building a more resilient world. To find out more, visit our website.
Robert Harris
2021-04-22 07:05:00 UTC
Permalink
Hi Sverker,
At process termination the deallocation of the heap is delayed until a running dirty NIF has returned. This to make sure the dirty NIF can safely continue read its arguments.
That makes things somewhat simpler; thank you.
The firing of links and monitors (including NIF monitor down calls), on the other hand, are not delayed by a running dirty NIF.
Is enif_monitor_process() serialised with respect to the delivery of
an exit signal by a concurrent thread? I.e. if the function returns zero
and the caller is later killed then is it guaranteed that its down
callback will be invoked? I am wondering if (absent any documentation
to the contrary) there might exist a race condition in which process A
might kill process B at exactly the time that the latter calls
enif_monitor_process(), e.g. in the (untested) code below.

Regards,

Robert



/* resource object */
typedef struct foo {
int abort;
...
} foo_t;

void
down(ErlNifEnv *env, void *obj, ErlNifPid *pid, ErlNifMonitor *mon)
{
((foo_t *)obj)->abort = 1;
}

ERL_NIF_TERM
some_dirty_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
foo_t *foop;
ErlNifPid pid;
ErlNifMonitor monitor;

enif_get_resource(env, argv[0], foo_resource, (void **)&foop));
foop->abort = 0;

enif_self(env, &pid);
if (enif_monitor_process(env, foop, pid, &monitor) > 0)
/* process already dead; abort */

/* lost a signal here? */

while (/* some very long loop */) {
if (foop->abort) {
/* process waiting to die; abort */
...
}
/* do stuff */
}

/* no longer care about being directed to abort */
enif_demonitor_process(env, foop, &monitor);
/* return */
...
}
Confidentiality Notice | This email and any included attachments may be privileged, confidential and/or otherwise protected from disclosure. Access to this email by anyone other than the intended recipient is unauthorized. If you believe you have received this email in error, please contact the sender immediately and delete all copies. If you are not the intended recipient, you are notified that disclosing, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited.

Disclaimer

The information contained in this communication from the sender is confidential. It is intended solely for use by the recipient and others authorized to receive it. If you are not the recipient, you are hereby notified that any disclosure, copying, distribution or taking action in relation of the contents of this information is strictly prohibited and may be unlawful.

This email has been scanned for viruses and malware, and may have been automatically archived by Mimecast, a leader in email security and cyber resilience. Mimecast integrates email defenses with brand protection, security awareness training, web security, compliance and other essential capabilities. Mimecast helps protect large and small organizations from malicious activity, human error and technology failure; and to lead the movement toward building a more resilient world. To find out more, visit our website.
Sverker Eriksson
2021-04-22 08:56:24 UTC
Permalink
If enif_monitor_process(_, Rsrc, Proc, _) returns 0 (success) then the monitor
is active and the down callback is guaranteed to be called when process Proc
terminates, unless

* the resource Rsrc was deallocated before. The destructor callback will
always be the last callback of a resource object.
* the monitor was cancelled before with enif_demitor_process().



If the target process has already been killed then enif_monitor_process() is
guaranteed to fail. There is no in between race, as with all other monitor and
link creation.



Side note:

A dirty NIF can check the liveness of its process with
enif_is_current_process_alive() without the need of self monitoring.



/Sverker



From: Robert Harris <***@alertlogic.com>
Sent: den 22 april 2021 09:05
To: Sverker Eriksson <***@ericsson.com>
Cc: erlang-***@erlang.org
Subject: Re: Kill a NIF's process



Hi Sverker,
Post by Sverker Eriksson
At process termination the deallocation of the heap is delayed until a
running dirty NIF has returned. This to make sure the dirty NIF can safely
continue read its arguments.
That makes things somewhat simpler; thank you.
Post by Sverker Eriksson
The firing of links and monitors (including NIF monitor down calls), on the
other hand, are not delayed by a running dirty NIF.
Is enif_monitor_process() serialised with respect to the delivery of
an exit signal by a concurrent thread? I.e. if the function returns zero
and the caller is later killed then is it guaranteed that its down
callback will be invoked? I am wondering if (absent any documentation
to the contrary) there might exist a race condition in which process A
might kill process B at exactly the time that the latter calls
enif_monitor_process(), e.g. in the (untested) code below.

Regards,

Robert



/* resource object */
typedef struct foo {
int abort;
...
} foo_t;

void
down(ErlNifEnv *env, void *obj, ErlNifPid *pid, ErlNifMonitor *mon)
{
((foo_t *)obj)->abort = 1;
}

ERL_NIF_TERM
some_dirty_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
foo_t *foop;
ErlNifPid pid;
ErlNifMonitor monitor;

enif_get_resource(env, argv[0], foo_resource, (void **)&foop));
foop->abort = 0;

enif_self(env, &pid);
if (enif_monitor_process(env, foop, pid, &monitor) > 0)
/* process already dead; abort */

/* lost a signal here? */

while (/* some very long loop */) {
if (foop->abort) {
/* process waiting to die; abort */
...
}
/* do stuff */
}

/* no longer care about being directed to abort */
enif_demonitor_process(env, foop, &monitor);
/* return */
...
}
Confidentiality Notice | This email and any included attachments may be
privileged, confidential and/or otherwise protected from disclosure. Access to
this email by anyone other than the intended recipient is unauthorized. If you
believe you have received this email in error, please contact the sender
immediately and delete all copies. If you are not the intended recipient, you
are notified that disclosing, copying, distributing or taking any action in
reliance on the contents of this information is strictly prohibited.



Disclaimer

The information contained in this communication from the sender is
confidential. It is intended solely for use by the recipient and others
authorized to receive it. If you are not the recipient, you are hereby
notified that any disclosure, copying, distribution or taking action in
relation of the contents of this information is strictly prohibited and may be
unlawful.

This email has been scanned for viruses and malware, and may have been
automatically archived by Mimecast, a leader in email security and cyber
resilience. Mimecast integrates email defenses with brand protection, security
awareness training, web security, compliance and other essential capabilities.
Mimecast helps protect large and small organizations from malicious activity,
human error and technology failure; and to lead the movement toward building a
more resilient world. To find out more, visit our website.
Robert Harris
2021-04-22 09:01:12 UTC
Permalink
If enif_monitor_process(_, Rsrc, Proc, _) returns 0 (success) then the monitor is active and the down callback is guaranteed to be called when process Proc terminates, unless
• the resource Rsrc was deallocated before. The destructor callback will always be the last callback of a resource object.
• the monitor was cancelled before with enif_demitor_process().
If the target process has already been killed then enif_monitor_process() is guaranteed to fail. There is no in between race, as with all other monitor and link creation.
Excellent. Thanks once again for the confirmation.
A dirty NIF can check the liveness of its process with enif_is_current_process_alive() without the need of self monitoring.
I am aware of that; thank you. enif_is_current_process_alive() has a (relatively)
high latency and I would prefer to avoid it.

Regards,

Robert


Confidentiality Notice | This email and any included attachments may be privileged, confidential and/or otherwise protected from disclosure. Access to this email by anyone other than the intended recipient is unauthorized. If you believe you have received this email in error, please contact the sender immediately and delete all copies. If you are not the intended recipient, you are notified that disclosing, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited.

Disclaimer

The information contained in this communication from the sender is confidential. It is intended solely for use by the recipient and others authorized to receive it. If you are not the recipient, you are hereby notified that any disclosure, copying, distribution or taking action in relation of the contents of this information is strictly prohibited and may be unlawful.

This email has been scanned for viruses and malware, and may have been automatically archived by Mimecast, a leader in email security and cyber resilience. Mimecast integrates email defenses with brand protection, security awareness training, web security, compliance and other essential capabilities. Mimecast helps protect large and small organizations from malicious activity, human error and technology failure; and to lead the movement toward building a more resilient world. To find out more, visit our website.
Continue reading on narkive:
Loading...