Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Feb 2001 22:34:06 +0100 (CET)
From:      mkamm@gmx.net
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/25462: daemon(3) fails if called by a session leader
Message-ID:  <200102282134.f1SLY6f26052@homebox.kammerhofer.org>

next in thread | raw e-mail | index | archive | help

>Number:         25462
>Category:       bin
>Synopsis:       daemon(3) fails if called by a session leader
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Feb 28 13:50:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Martin Kammerhofer
>Release:        FreeBSD 4.2-STABLE i386
>Organization:
TU Graz
>Environment:
Any FreeBSD system.
>Description:

The C library routine daemon(3) has a subtle bug:

If the calling process is a session leader (i.e. pid == pgid)
then a hangup signal will be delivered immediately to the
created child process (daemon).
The reason can be read in the _exit(2) manpage.

I guess this bug is rarely triggered during normal operation
but I can think of several scenarios were it will show up:
 - starting a daemon from /etc/passwd (as a login shell)
 - exec'ing a daemon from any login shell
 - exec'ing a daemon from a daemon
 - controlling a daemon with expect(1) from ports/lang/expect
 - giving a daemon as argument to script(1)

>How-To-Repeat:

~/tmp$ cat daemontest.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

int
main (void) {
    unlink("SUCCESS");
    printf("I want to become a daemon\n");
    if (daemon(1, 1))
	perror("daemon");
    open("SUCCESS", O_CREAT | O_TRUNC | O_WRONLY, 0666);
    printf("I'm a daemon now\n");
    return (0);
}
~/tmp$ make daemontest
cc -Wall daemontest.c -o daemontest
~/tmp$ ./daemontest 
I want to become a daemon
~/tmp$ I'm a daemon now

~/tmp$ script -q logfile ./daemontest
I want to become a daemon
~/tmp$ ls SUCCESS
ls: SUCCESS: No such file or directory
~/tmp$ cat logfile
I want to become a daemon
~/tmp$ 


>Fix:

There are several options here. I guess the most simple
approach is ignoring SIGHUP until setsid(2) has been
called.
Of course, this doesn't fix daemons using fork && _exit
instead of daemon(3).

Index: daemon.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/gen/daemon.c,v
retrieving revision 1.4
diff -u -r1.4 daemon.c
--- daemon.c	2001/01/24 12:59:21	1.4
+++ daemon.c	2001/02/28 19:32:40
@@ -41,6 +41,7 @@
 #include <fcntl.h>
 #include <paths.h>
 #include <unistd.h>
+#include <signal.h>
 #include "un-namespace.h"
 
 int
@@ -48,7 +49,13 @@
 	int nochdir, noclose;
 {
 	int fd;
+	struct sigaction sa_ign, sa_save;
+	pid_t newgrp;
 
+	sa_ign.sa_handler = SIG_IGN;
+	sa_ign.sa_flags = 0;
+	(void) sigaction(SIGHUP, &sa_ign, &sa_save);
+
 	switch (fork()) {
 	case -1:
 		return (-1);
@@ -58,7 +65,9 @@
 		_exit(0);
 	}
 
-	if (setsid() == -1)
+	newgrp = setsid();
+	(void) sigaction(SIGHUP, &sa_save, (struct sigaction *) 0);
+	if (newgrp == -1)
 		return (-1);
 
 	if (!nochdir)
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200102282134.f1SLY6f26052>