Package: cron
Version: 3.0pl1-86

Description of problem:
The result of crond not explicitly opening file descriptor 0, is that
the cronjobs inherit a closed fd 0 (stdin), which tends to be an issue
in some cases. eg. if apache is periodically restarted from cron
(quite common in web hosting environments) and cron does not open
stdin i.e. fd 0 for it, then apache spams the apache error_log with
following error:

[error] (88)Socket operation on non-socket: apr_accept: (client socket)

Analyzing the source of vixie-cron-3.0.1-75.1, this is how it probably
happens ..

acquire_daemonlock(0) in main() of cron.c uses fd 0 for the pid file
(since fd 0 was not available when cron started) this is then
converted to a file pointer using fdopen() and preserved via static
file pointer *fp (check misc.c)

later in do_command() of do_command.c (this is where the actual
execution of cronjob is handled) acquire_daemonlock(1) is called which
closes the static file pointer *fp, this inturn releases fd 0

later from child_process() pipe(stdin_pipe) and pipe(stdout_pipe)
calls are made to communicate with the future child (the cronjob).
here the file descriptor for reading of pipe(stdin_pipe) is 0 since fd
0 has been made available as the lowest file descriptor due to call of
acquire_daemonlock(1). This corresponds to the pipe calls seen in
strace above.

Then after fork(), intentionally, the not required (in child) ends of
the inherited pipes are closed via calls close(stdin_pipe[WRITE_PIPE])
and close(stdout_pipe[READ_PIPE])

But just before this, via the setsid() call, un-intentionally, the
file descriptor for reading of stdin_pipe  i.e. stdin_pipe[READ_PIPE]
gets closed since it was using fd 0 (check compat.c for details on setsid)

Due to this dup2(stdin_pipe[READ_PIPE], STDIN) which ties (duplicates)
the stdin_pipe[READ_PIPE] to the STDIN of the child (i.e. the cronjob)
fails with EBADF (Bad file descriptor) as seen in strace above.

And hence the cronjob is executed without a valid i.e. closed STDIN

How reproducible:
Always

Steps to Reproduce:
1. Ensure auditd is disabled and /dev/audit is removed as per Bug #131860
1. Restart crond from a shell script after closing file descriptor zero

# cat test1.sh
#!/bin/sh
exec 0<&-
/etc/init.d/cron restart

2. Schedule a cronjob which just attempts to open a file, and check
the file descriptor allocated

*/1 * * * * /root/test2 >> /tmp/test2

test2 is created from test2.c

# cat test2.c
#include <errno.h>
#include <fcntl.h>
extern int errno;
int main(int argc, char *argv[]) {
        int fd;
        if((fd = open("/etc/hosts",O_RDONLY)) == -1)
                printf("Error No %d\n",errno);
        else
                printf("FD - %d\n", fd);
        close(fd);
        return 0;
}

Compiled using:
# gcc -o test2 test2.c

Check (tail -f) /tmp/test2

Actual Results:  FD - 0

Expected Results:  FD - 3


This patch should fix the problem:

--- cron.c      2005-12-28 13:22:35.590274128 -0600
+++ cron.c.orig 2005-12-28 13:22:24.395975920 -0600
@@ -83,6 +83,8 @@
#endif
        (void) signal(SIGHUP, sighup_handler);
+       if (fdopen(0,"r") == NULL) (void) open("/dev/null",0);
+
        acquire_daemonlock(0);
        set_cron_uid();
        set_cron_cwd();



--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to