From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 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) Note: this issue manifests itself only if auditd is disabled and /dev/audit removed (see Bug #131860) If crond is invoked in same scenario (i.e. with closed fd 0) using strace, # cat test.sh #!/bin/sh exec 0<&- /usr/bin/strace -xv -tt -ff -o /tmp/crond.strace /usr/sbin/crond following are some of the observations related to this issue: /tmp/crond.strace.13897:09:21:01.000350 pipe([0, 4]) = 0 /tmp/crond.strace.13897:09:21:01.000453 pipe([5, 6]) = 0 Though pipe using 0 as one of the file descriptors is not an issue in itself, but later fd 0 is specifically closed, and then a dup2 called, which fails as follows .. /tmp/crond.strace.13899:09:21:01.004200 dup2(0, 0) = -1 EBADF (Bad file descriptor) and later the cronjob is executed without a valid fd 0. 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 If laus is enabled and /dev/audit exist, then possibly, when /dev/audit is opened via LAUS_OPEN macro just before acquire_daemonlock(0) in main() in cron.c, it uses up fd 0, this causes acquire_daemonlock(0) to preserve a non 0 fd via static file pointer *fp for the pid file, and due to which the the scenario described above does not occur. Version-Release number of selected component (if applicable): vixie-cron-3.0.1-75.1 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<&- service crond restart 2. Schedule a cronjob which just attempts to open a file, and check the file descriptor allocated */1 * * * * root /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 Additional info:
Created attachment 110129 [details] Patch to open fd 0 if not already open This patch needs to be applied after all the other vixie-cron-3.0.1 patches have been applied
This problem is now fixed in vixie-cron-4.1-2_EL3, which is the latest version for RHEL-3, currently undergoing QA testing, and which should be in RHEL-3-U5. Meanwhile, you can download it from: http://people.redhat.com/~jvdias/vixie-cron/RHEL-3
Thank You Jason, vixie-cron-4.1-2_EL3 works fine. Btw, just to correct my explaination, stdin_pipe[READ_PIPE] is un-intentionally closed not by setsid, but by close(STDIN) called just before dup2(stdin_pipe[READ_PIPE], STDIN) since it was using fd 0.
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHBA-2005-291.html