Commit [3995cb] Maximize Restore History

Limit the number of simultanious children

Make sure minidlna cannot fork more than 5 children, to avoid becoming a
fork bomb.

Reported-by: Rinat Ibragimov <ibragimovrinat@mail.ru>

Benoît Knecht Benoît Knecht 2013-06-13

changed Makefile.am
changed minidlna.c
changed upnphttp.c
copied daemonize.c -> process.c
copied daemonize.h -> process.h
Makefile.am Diff Switch to side-by-side view
Loading...
minidlna.c Diff Switch to side-by-side view
Loading...
upnphttp.c Diff Switch to side-by-side view
Loading...
daemonize.c to process.c
--- a/daemonize.c
+++ b/process.c
@@ -1,7 +1,8 @@
-/* MiniUPnP project
- * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+/* Process handling
  *
- * Copyright (c) 2006, Thomas Bernard
+ * Copyright © 2006, Thomas Bernard
+ * Copyright © 2013, Benoît Knecht <benoit.knecht@fsfe.org>
+ *
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,48 +36,74 @@
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
+#include <sys/wait.h>
 
-#include "daemonize.h"
+#include "process.h"
 #include "config.h"
 #include "log.h"
 
+static const int max_number_of_children = 5;
+static int number_of_children = 0;
+
+pid_t
+process_fork(void)
+{
+	if (number_of_children >= max_number_of_children)
+	{
+		errno = EAGAIN;
+		return -1;
+	}
+
+	pid_t pid = fork();
+	if (pid > 0)
+		++number_of_children;
+	return pid;
+}
+
+void
+process_handle_child_termination(int signal)
+{
+	waitpid(-1, NULL, WNOHANG);
+	--number_of_children;
+}
+
 int
-daemonize(void)
+process_daemonize(void)
 {
 	int pid;
 #ifndef USE_DAEMON
 	int i;
 
-	switch(fork())
+	switch(process_fork())
 	{
-	/* fork error */
-	case -1:
-		perror("fork()");
-		exit(1);
-	
-	/* child process */
-	case 0:
+		/* fork error */
+		case -1:
+			perror("fork()");
+			exit(1);
+
+		/* child process */
+		case 0:
 		/* obtain a new process group */
-		if( (pid = setsid()) < 0)
-		{
-			perror("setsid()");
-			exit(1);
-		}
+			if( (pid = setsid()) < 0)
+			{
+				perror("setsid()");
+				exit(1);
+			}
 
-		/* close all descriptors */
-		for (i=getdtablesize();i>=0;--i) close(i);		
+			/* close all descriptors */
+			for (i=getdtablesize();i>=0;--i) close(i);		
 
-		i = open("/dev/null",O_RDWR); /* open stdin */
-		dup(i); /* stdout */
-		dup(i); /* stderr */
+			i = open("/dev/null",O_RDWR); /* open stdin */
+			dup(i); /* stdout */
+			dup(i); /* stderr */
 
-		umask(027);
-		chdir("/");
+			umask(027);
+			chdir("/");
 
-		break;
-	/* parent process */
-	default:
-		exit(0);
+			break;
+		/* parent process */
+		default:
+			exit(0);
 	}
 #else
 	if( daemon(0, 0) < 0 )
@@ -87,7 +114,7 @@
 }
 
 int
-checkforrunning(const char * fname)
+process_check_if_running(const char *fname)
 {
 	char buffer[64];
 	int pidfile;
@@ -98,9 +125,9 @@
 
 	if( (pidfile = open(fname, O_RDONLY)) < 0)
 		return 0;
-	
+
 	memset(buffer, 0, 64);
-	
+
 	if(read(pidfile, buffer, 63))
 	{
 		if( (pid = atol(buffer)) > 0)
@@ -112,9 +139,8 @@
 			}
 		}
 	}
-	
+
 	close(pidfile);
-	
+
 	return 0;
 }
-
daemonize.h to process.h
--- a/daemonize.h
+++ b/process.h
@@ -1,7 +1,7 @@
-/* MiniUPnP project
- * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+/* Process handling
  *
- * Copyright (c) 2006, Thomas Bernard
+ * Copyright © 2013, Benoît Knecht <benoit.knecht@fsfe.org>
+ *
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,24 +26,41 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-#ifndef __DAEMONIZE_H__
-#define __DAEMONIZE_H__
+#ifndef __PROCESS_H__
+#define __PROCESS_H__
 
-#include "config.h"
+#include <unistd.h>
 
-/* daemonize()
- * "fork" to background, detach from terminal, etc... 
- * returns: pid of the daemon, exits upon failure */
-int
-daemonize(void);
+/**
+ * Fork a new child (just like fork()) but keep track of how many childs are
+ * already running, and refuse fo fork if there are too many.
+ * @return -1 if it couldn't fork, 0 in the child process, the pid of the
+ *         child process in the parent process.
+ */
+pid_t process_fork(void);
 
-/* checkforrunning()
- * check for another instance running
- * returns: 0 only instance
- *          -1 invalid filename
- *          -2 another instance running  */
-int
-checkforrunning(const char * fname);
+/**
+ * Handler to be called upon receiving SIGCHLD. This signal is received by the
+ * parent process when a child terminates, and this handler updates the number
+ * of running childs accordingly.
+ * @param signal The signal number.
+ */
+void process_handle_child_termination(int signal);
 
-#endif
+/**
+ * Daemonize the current process by forking itself and redirecting standard
+ * input, standard output and standard error to /dev/null.
+ * @return The pid of the process.
+ */ 
+int process_daemonize(void);
 
+/**
+ * Check if the process corresponding to the pid found in the pid file is
+ * running.
+ * @param fname The path to the pid file.
+ * @return 0 if no other instance is running, -1 if the file name is invalid,
+ *         -2 if another instance is running.
+ */
+int process_check_if_running(const char *fname);
+
+#endif // __PROCESS_H__