[radvd/f16] Store PID before daemonizing
Petr Pisar
ppisar at fedoraproject.org
Thu Apr 12 16:05:56 UTC 2012
commit 6608753dbad55119e811634b22188ff4cff36031
Author: Petr Písař <ppisar at redhat.com>
Date: Thu Apr 12 15:58:28 2012 +0200
Store PID before daemonizing
radvd-1.8.2-Use-libdaemon-for-daemonization.patch | 239 +++++++++++++++++++++
radvd.spec | 14 ++-
2 files changed, 252 insertions(+), 1 deletions(-)
---
diff --git a/radvd-1.8.2-Use-libdaemon-for-daemonization.patch b/radvd-1.8.2-Use-libdaemon-for-daemonization.patch
new file mode 100644
index 0000000..adf6479
--- /dev/null
+++ b/radvd-1.8.2-Use-libdaemon-for-daemonization.patch
@@ -0,0 +1,239 @@
+From 4c617f33c6e0b672c4e215af649b967873f799e9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar at redhat.com>
+Date: Thu, 5 Apr 2012 15:24:22 +0200
+Subject: [PATCH] Use libdaemon for daemonization
+
+The libc daemon(3) function suffers from race bewtween exiting parent
+and saving PID into a file.
+
+Using libdaemon library one can avoid this race and can simplify PID
+file manipulation.
+
+The only difference against older implementation is, the PID file will
+be inspected, created, and removed only if daemonization is requested.
+---
+ Makefile.am | 6 +++-
+ README | 2 +
+ configure.in | 2 +
+ radvd.c | 95 ++++++++++++++++++++++++++++++----------------------------
+ 4 files changed, 58 insertions(+), 47 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index cc84f9f..c0f6d82 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -61,8 +61,12 @@ EXTRA_radvd_SOURCES = \
+ privsep-bsd44.c \
+ privsep-linux.c
+
++radvd_CPPFLAGS = \
++ @DAEMON_CFLAGS@
++
+ radvd_LDADD = \
+- @CONDITIONAL_SOURCES@
++ @CONDITIONAL_SOURCES@ \
++ @DAEMON_LIBS@
+
+ radvd_DEPENDENCIES = \
+ @CONDITIONAL_SOURCES@
+diff --git a/README b/README
+index 0867576..21a49a6 100644
+--- a/README
++++ b/README
+@@ -3,6 +3,8 @@ $Id: README,v 1.9 2005/12/31 16:10:05 psavola Exp $
+ Installation:
+ =============
+
++Install 'pkg-config' and 'libdaemon'.
++
+ Run configure, e.g.
+
+ ./configure --prefix=/usr/local --sysconfdir=/etc --mandir=/usr/share/man
+diff --git a/configure.in b/configure.in
+index 1ed2280..cd00a09 100644
+--- a/configure.in
++++ b/configure.in
+@@ -139,6 +139,8 @@ AC_CHECK_LIB(c, inet_ntop,,
+ # prevent caching
+ unset ac_cv_lib_inet6_inet_ntop
+
++PKG_CHECK_MODULES([DAEMON], libdaemon)
++
+ dnl Checks for header files.
+ AC_HEADER_STDC
+ AC_CHECK_HEADERS( \
+diff --git a/radvd.c b/radvd.c
+index 73746d7..7135125 100644
+--- a/radvd.c
++++ b/radvd.c
+@@ -24,6 +24,8 @@
+ #endif
+
+ #include <poll.h>
++#include <libdaemon/dfork.h>
++#include <libdaemon/dpid.h>
+
+ struct Interface *IfaceList = NULL;
+
+@@ -72,6 +74,7 @@ char usage_str[] =
+ extern FILE *yyin;
+
+ char *conf_file = NULL;
++char *pidfile = NULL;
+ char *pname;
+ int sock = -1;
+
+@@ -93,16 +96,15 @@ void usage(void);
+ int drop_root_privileges(const char *);
+ int readin_config(char *);
+ int check_conffile_perm(const char *, const char *);
++const char *get_pidfile(void);
+ void main_loop(void);
+
+ int
+ main(int argc, char *argv[])
+ {
+- char pidstr[16];
+- ssize_t ret;
+ int c, log_method;
+- char *logfile, *pidfile;
+- int facility, fd;
++ char *logfile;
++ int facility;
+ char *username = NULL;
+ char *chrootdir = NULL;
+ int configtest = 0;
+@@ -110,6 +112,7 @@ main(int argc, char *argv[])
+ #ifdef HAVE_GETOPT_LONG
+ int opt_idx;
+ #endif
++ pid_t pid;
+
+ pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];
+
+@@ -282,32 +285,6 @@ main(int argc, char *argv[])
+ }
+ }
+
+- if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
+- {
+- ret = read(fd, pidstr, sizeof(pidstr) - 1);
+- if (ret < 0)
+- {
+- flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
+- exit(1);
+- }
+- pidstr[ret] = '\0';
+- if (!kill((pid_t)atol(pidstr), 0))
+- {
+- flog(LOG_ERR, "radvd already running, terminating.");
+- exit(1);
+- }
+- close(fd);
+- fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
+- }
+- else /* FIXME: not atomic if pidfile is on an NFS mounted volume */
+- fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
+-
+- if (fd < 0)
+- {
+- flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
+- exit(1);
+- }
+-
+ /*
+ * okay, config file is read in, socket and stuff is setup, so
+ * lets fork now...
+@@ -315,9 +292,37 @@ main(int argc, char *argv[])
+
+ if (get_debuglevel() == 0) {
+
+- /* Detach from controlling terminal */
+- if (daemon(0, 0) < 0)
+- perror("daemon");
++ if (daemon_retval_init()) {
++ flog(LOG_ERR, "Could not initialize daemon IPC.");
++ exit(1);
++ }
++
++ pid = daemon_fork();
++ if (-1 == pid) {
++ flog(LOG_ERR, "Could not fork: %s", strerror(errno));
++ daemon_retval_done();
++ exit(1);
++ }
++ if (0 < pid) {
++ if (daemon_retval_wait(0)) {
++ flog(LOG_ERR, "Could not daemonize.");
++ exit(1);
++ }
++ exit(0);
++ }
++
++ daemon_pid_file_proc = get_pidfile;
++ if (daemon_pid_file_is_running() >= 0) {
++ flog(LOG_ERR, "radvd already running, terminating.");
++ daemon_retval_send(1);
++ exit(1);
++ }
++ if (daemon_pid_file_create()) {
++ flog(LOG_ERR, "Cannot create radvd PID file, terminating: %s",
++ strerror(errno));
++ daemon_retval_send(2);
++ exit(1);
++ }
+
+ /* close old logfiles, including stderr */
+ log_close();
+@@ -326,10 +331,12 @@ main(int argc, char *argv[])
+ if (log_method == L_STDERR_SYSLOG)
+ log_method = L_SYSLOG;
+ if (log_open(log_method, pname, logfile, facility) < 0) {
+- perror("log_open");
++ flog(LOG_ERR, "log_open() failed: %s", strerror(errno));
++ daemon_retval_send(3);
+ exit(1);
+ }
+
++ daemon_retval_send(0);
+ }
+
+ /*
+@@ -340,26 +347,22 @@ main(int argc, char *argv[])
+ signal(SIGINT, sigint_handler);
+ signal(SIGUSR1, sigusr1_handler);
+
+- snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
+-
+- ret = write(fd, pidstr, strlen(pidstr));
+- if (ret != strlen(pidstr))
+- {
+- flog(LOG_ERR, "cannot write radvd pid file, terminating: %s", strerror(errno));
+- exit(1);
+- }
+-
+- close(fd);
+-
+ config_interface();
+ kickoff_adverts();
+ main_loop();
+ stop_adverts();
+- unlink(pidfile);
++ if (get_debuglevel() == 0) {
++ flog(LOG_INFO, "removing %s", pidfile);
++ unlink(pidfile);
++ }
+
+ return 0;
+ }
+
++const char *get_pidfile(void) {
++ return pidfile;
++}
++
+ void main_loop(void)
+ {
+ struct pollfd fds[2];
+--
+1.7.7.6
+
diff --git a/radvd.spec b/radvd.spec
index 9b33798..f8be95c 100644
--- a/radvd.spec
+++ b/radvd.spec
@@ -4,7 +4,7 @@
Summary: A Router Advertisement daemon
Name: radvd
Version: 1.8.2
-Release: 2%{?dist}
+Release: 3%{?dist}
# The code includes the advertising clause, so it's GPL-incompatible
License: BSD with advertising
Group: System Environment/Daemons
@@ -17,10 +17,17 @@ Requires(postun): chkconfig, /usr/sbin/userdel, initscripts
Requires(preun): chkconfig, initscripts
Requires(post): chkconfig
Requires(pre): /usr/sbin/useradd
+# autoconf needed for Use-libdaemon-for-daemonization patch
+BuildRequires: autoconf
+BuildRequires: automake
BuildRequires: flex, flex-static, byacc
+BuildRequires: libdaemon-devel
+BuildRequires: pkgconfig
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Patch1: radvd-1.8.2-iface.patch
+# Bug #811997, fixed in upstream after 1.8.5
+Patch2: radvd-1.8.2-Use-libdaemon-for-daemonization.patch
%description
radvd is the router advertisement daemon for IPv6. It listens to router
@@ -37,6 +44,8 @@ services.
%setup -q
%patch1 -p1 -b .iface
+%patch2 -p1 -b .libdaemon
+autoreconf -is
%build
export CFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE -fPIE"
@@ -113,6 +122,9 @@ exit 0
%{_sbindir}/radvdump
%changelog
+* Thu Apr 12 2012 Petr Pisar <ppisar at redhat.com> - 1.8.2-3
+- Store PID before daemonizing (bug #811997)
+
* Mon Oct 10 2011 Jiri Skala <jskala at redhat.com> - 1.8.2-2
- fixes CVE-2011-3602
More information about the scm-commits
mailing list