5

This question may seem a bit silly, but since in Unix-based systems, replacing an executable's image is done in a single step, replacing the currently running process, in the function call execve (and derivatives), the question is:

Why does sudo fork() by default before execve'ing the replacement process?

By forking before, additional kernel elements have to be initiallized, and although fork is quite optimized in some Unices, there are still some unavoidable elements that must be initialized. If fork() did not occur by default, the PID space would increment slower.

If you are curious, this default behaviour can be inspected by issuing a command such as

sudo sleep 30

the current code [1] is quite more complicated to follow, as many features have been added since; but in the version hosted by Apple [2] it is quite clear what it does.

#ifndef PROFILING
    if ((sudo_mode & MODE_BACKGROUND) && fork() > 0)
        exit(0);
    else
        EXEC(safe_cmnd, NewArgv);   /* run the command */
#else
/* Complicated code when profiling is enabled, but we don't care */

I am currently running sudo version 1.8.11p2, and it spawns the sleep either way, with or without the -b switch, so it seems the current code got more complicated.

I am looking for an answer which covers also why is this the default behaviour, and which advantanges it can bring us.

2 Answers 2

3

The PID space on Linux can be raised to 222 with a simple sysctl; that's really not a problem...

Most Linux distributions nowadays use PAM, and sudo is usually compiled with PAM support as well. Among other things it calls pam_open_session() before running your program, therefore it must also call pam_close_session() from within the same process as well, since your program won't know it needs to do that (and likely wouldn't be allowed to do that).

3

The reason for forking is documented in the Process model section of the man page. The relevant content is:

This extra process makes it possible to, for example, suspend and resume the command. Without it, the command would be in what POSIX terms an “orphaned process group” and it would not receive any job control signals. As a special case, if the policy plugin does not define a close function and no pty is required, sudo will execute the command directly instead of calling fork(2) first. The sudoers policy plugin will only define a close function when I/O logging is enabled, a pty is required, or the pam_session or pam_setcred options are enabled. Note that pam_session and pam_setcred are enabled by default on systems using PAM.

2
  • Why could it not pick job control signals? If I type in bash and inside the forked+execve'd new shell I spawn an exec sleep 10, I can still Ctrl.+Z from my parent shell, as the process has been replaced, but its parent is still the same, is it not? Wouldn't orphaning happen if the parent (fork() == 0) exited before recalling its children?
    – ssice
    Jan 2, 2015 at 23:46
  • @ssice I think it is less about handling signals as the other cases: close function, pty, pam_session, and pam_setcred. sudo becomes orphaned on my system, and this may cause signal passing issues on some platforms.
    – BillThor
    Jan 3, 2015 at 0:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .