Spawn/fork new process where children do die

463 views
Skip to first unread message

robertj

unread,
Jul 12, 2011, 9:31:41 AM7/12/11
to nod...@googlegroups.com
Hi,

is there a way to spawn/fork/exec a child process in such away that 
if the parent process dies the child process stays alive?

Best regards

Robert

Matt

unread,
Jul 14, 2011, 2:54:37 AM7/14/11
to nod...@googlegroups.com
No. Node lacks a setsid() call, or even a module that provides it, as far as I can find.

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

arlolra

unread,
Jul 14, 2011, 1:52:15 PM7/14/11
to nod...@googlegroups.com

dhruvbird

unread,
Jul 15, 2011, 11:33:06 AM7/15/11
to nodejs

Ben Noordhuis

unread,
Jul 15, 2011, 11:40:19 AM7/15/11
to nod...@googlegroups.com
On Thu, Jul 14, 2011 at 08:54, Matt <hel...@gmail.com> wrote:
> No. Node lacks a setsid() call, or even a module that provides it, as far as
> I can find.

It's there:

require('child_process').spawn(cmd, args, {setsid:true});

http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn

Matt

unread,
Jul 15, 2011, 11:59:14 AM7/15/11
to nod...@googlegroups.com
Ooh, is that new?

Does it work on the new child_process.fork() too?

Matt.

Ben Noordhuis

unread,
Jul 15, 2011, 12:10:12 PM7/15/11
to nod...@googlegroups.com
On Fri, Jul 15, 2011 at 17:59, Matt <hel...@gmail.com> wrote:
> On Fri, Jul 15, 2011 at 4:40 PM, Ben Noordhuis <in...@bnoordhuis.nl> wrote:
>>
>> On Thu, Jul 14, 2011 at 08:54, Matt <hel...@gmail.com> wrote:
>> > No. Node lacks a setsid() call, or even a module that provides it, as
>> > far as
>> > I can find.
>>
>> It's there:
>>
>>  require('child_process').spawn(cmd, args, {setsid:true});
>>
>> http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn
>
> Ooh, is that new?

Added and documented in January of this year. Aeons ago on node's time scale. :)

> Does it work on the new child_process.fork() too?

Yep, fork() is just a thin wrapper around spawn().

Matt

unread,
Jul 15, 2011, 12:56:26 PM7/15/11
to nod...@googlegroups.com
On Fri, Jul 15, 2011 at 5:10 PM, Ben Noordhuis <in...@bnoordhuis.nl> wrote:
>>  require('child_process').spawn(cmd, args, {setsid:true});
>>
>> http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn
>
> Ooh, is that new?

Added and documented in January of this year. Aeons ago on node's time scale. :)

> Does it work on the new child_process.fork() too?

Yep, fork() is just a thin wrapper around spawn().

Oh.... I just read the code... how disappointing...

How come a plain fork() wouldn't work that you had to implement something called fork that isn't?

Matt.

Ben Noordhuis

unread,
Jul 15, 2011, 2:20:56 PM7/15/11
to nod...@googlegroups.com
On Fri, Jul 15, 2011 at 18:56, Matt <hel...@gmail.com> wrote:
> How come a plain fork() wouldn't work that you had to implement something
> called fork that isn't?

On Unices, fork() in multi-threaded programs has awful semantics and
behaviour (google pthread_atfork or fork+epoll or open+FD_CLOEXEC to
see what I mean), that's why we execve() into another process as
quickly as possible. It's a kind of damage control.

hel...@gmail.com

unread,
Jul 15, 2011, 4:15:58 PM7/15/11
to nod...@googlegroups.com
Hmmm. I fork in my libev code (admittedly in perl) and it works fine. Guess it should be tried in a library though - have the node devs tried it so I'm not wasting my time?
Sent from my BlackBerry device on the Rogers Wireless Network

Ben Noordhuis

unread,
Jul 15, 2011, 5:10:30 PM7/15/11
to nod...@googlegroups.com
On Fri, Jul 15, 2011 at 22:15, <hel...@gmail.com> wrote:
> Hmmm. I fork in my libev code (admittedly in perl) and it works fine. Guess it should be tried in a library though - have the node devs tried it so I'm not wasting my time?

The core issue is that fork() opens up a race window in multi-threaded
programs. Consider this single-threaded program running as root:

a. fd = open("/etc/passwd", O_RDWR);
b. fcntl(fd, F_SETFD, FD_CLOEXEC | flags);
c. fork() and drop privileges
d. execve("malicious-program")

No problem there. Now consider the same scenario in a multi-threaded program.

Thread 1:

a. fd = open("/etc/passwd", O_RDWR);
b. fcntl(fd, F_SETFD, FD_CLOEXEC | flags);

Thread 2:

a. fork() and drop privileges
b. execve("malicious-program")

If the call to fork() in 2a runs right between 1a and 1b, the file
descriptor will leak to the new process and - since open file
descriptors survive execve() - to the malicious program.

Linux has open() and socket() calls that lets you create close-on-exec
file descriptors atomically (you pass O_CLOEXEC in the flags arg) but
other Unices don't have such facilities.

Matt

unread,
Jul 15, 2011, 6:03:46 PM7/15/11
to nod...@googlegroups.com
On Fri, Jul 15, 2011 at 10:10 PM, Ben Noordhuis <in...@bnoordhuis.nl> wrote:
On Fri, Jul 15, 2011 at 22:15,  <hel...@gmail.com> wrote:
> Hmmm. I fork in my libev code (admittedly in perl) and it works fine. Guess it should be tried in a library though - have the node devs tried it so I'm not wasting my time?

The core issue is that fork() opens up a race window in multi-threaded
programs. Consider this single-threaded program running as root:

a. fd = open("/etc/passwd", O_RDWR);
b. fcntl(fd, F_SETFD, FD_CLOEXEC | flags);
c. fork() and drop privileges
d. execve("malicious-program")

No problem there. Now consider the same scenario in a multi-threaded program.

Thread 1:

a. fd = open("/etc/passwd", O_RDWR);
b. fcntl(fd, F_SETFD, FD_CLOEXEC | flags);

Thread 2:

a. fork() and drop privileges
b. execve("malicious-program")

If the call to fork() in 2a runs right between 1a and 1b, the file
descriptor will leak to the new process and - since open file
descriptors survive execve() - to the malicious program.

2 issues:

1. The fcntl, open and fork run in the same thread in node. Libev just waits for the responses in another thread, right?

2. Why would you code a node app to call execve("malicious-program")?

And honestly if someone does, that's their problem.

I'd still rather see a real fork (that puts the code pointer at the current place), even if you want to put big warnings around it. This can be emulated under Windows too (see: Perl).

Matt.

Ben Noordhuis

unread,
Jul 15, 2011, 7:11:43 PM7/15/11
to nod...@googlegroups.com

Heaven save us from literal minded people! That example wasn't about
node but fork() in general.

Anyway, it's never going to happen. We need a clean slate after
forking for reasons pointed out in my previous-previous post.

Matt

unread,
Jul 15, 2011, 7:38:00 PM7/15/11
to nod...@googlegroups.com
OK, but the question is about node :)
 
Anyway, it's never going to happen. We need a clean slate after
forking for reasons pointed out in my previous-previous post.

Well you think you do, but I'll put it in a library and try it anyway - I'm more of a fan of tested results than dogmatic presentation of "it's bad so we won't do it". It certainly would be nice for solutions using cluster (or similar) to be able to pre-load libraries and data and then fork, rather than do that in every child.

Matt.

Ryan Dahl

unread,
Jul 15, 2011, 9:23:29 PM7/15/11
to nod...@googlegroups.com
> Well you think you do, but I'll put it in a library and try it anyway - I'm
> more of a fan of tested results than dogmatic presentation of "it's bad so
> we won't do it". It certainly would be nice for solutions using cluster (or
> similar) to be able to pre-load libraries and data and then fork, rather
> than do that in every child.

We're not binding fork because Windows doesn't have it. We do not
consider the emulation hack acceptable.

Also all of the reasons Ben mentioned.

Also the first GC compact you hit will negate any COW win you had.

Reply all
Reply to author
Forward
0 new messages