>From the mainline commit 5fdee8c4a5e1800489ce61963208f8cc55e42ea1:

A program that repeatedly forks and waits is susceptible to having the
same pid repeated, especially when it competes with another instance of
the same program.  This is really bad for bash implementation.
Furthermore, many shell scripts assume that pid numbers will not be used
for some length of time.

Race Description:

A                                B

// pid == offset == n            // pid == offset == n + 1
test_and_set_bit(offset, map->page)
                                 test_and_set_bit(offset, map->page);
                                 pid_ns->last_pid = pid;
pid_ns->last_pid = pid;
                                 // pid == n + 1 is freed (wait())

                                 // Next fork()...
                                 last = pid_ns->last_pid; // == n
                                 pid = last + 1;

Signed-off-by: CAI Qian <[email protected]>
---
 runtest/syscalls                        |    1 +
 testcases/kernel/syscalls/fork/fork13.c |  166 +++++++++++++++++++++++++++++++
 2 files changed, 167 insertions(+), 0 deletions(-)
 create mode 100644 testcases/kernel/syscalls/fork/fork13.c

diff --git a/runtest/syscalls b/runtest/syscalls
index b2bf144..d8f9b20 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -274,6 +274,7 @@ fork08 fork08
 fork09 fork09
 fork10 fork10
 fork11 fork11
+fork13 fork13 -c 2 -i 10000000
 
 fpathconf01 fpathconf01
 
diff --git a/testcases/kernel/syscalls/fork/fork13.c 
b/testcases/kernel/syscalls/fork/fork13.c
new file mode 100644
index 0000000..9c36310
--- /dev/null
+++ b/testcases/kernel/syscalls/fork/fork13.c
@@ -0,0 +1,166 @@
+/*
+ * a race in pid generation that causes pids to be reused immediatelly
+ *
+ * From the mainline commit 5fdee8c4a5e1800489ce61963208f8cc55e42ea1:
+ * 
+ * A program that repeatedly forks and waits is susceptible to having
+ * the same pid repeated, especially when it competes with another
+ * instance of the same program.  This is really bad for bash
+ * implementation.  Furthermore, many shell scripts assume that pid
+ * numbers will not be used for some length of time.
+ * 
+ * Race Description:
+ *
+ * A                                B
+ *
+ * // pid == offset == n            // pid == offset == n + 1
+ * test_and_set_bit(offset, map->page)
+ *                                  test_and_set_bit(offset, map->page);
+ *                                  pid_ns->last_pid = pid;
+ * pid_ns->last_pid = pid;
+ *                                  // pid == n + 1 is freed (wait())
+ *
+ *                                  // Next fork()...
+ *                                  last = pid_ns->last_pid; // == n
+ *                                  pid = last + 1;
+ *
+ * Copyright (C) 2010  Red Hat, Inc.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it
+ * is free of the rightful claim of any third person regarding
+ * infringement or the like.  Any license provided herein, whether
+ * implied or otherwise, applies only to this software file.  Patent
+ * licenses, if any, provided herein do not apply to combinations of
+ * this program with other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "test.h"
+#include "usctest.h"
+
+char *TCID = "fork13";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+static void setup(void);
+static int PidDistance(pid_t first, pid_t second);
+static void cleanup(void) LTP_ATTRIBUTE_NORETURN;
+static int check(void);
+
+int main(int argc, char* argv[])
+{
+       /* message returned from parse_opts */
+       char *msg;
+
+       msg = parse_opts(argc, argv, NULL, NULL);
+       if (msg != NULL) {
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s",
+                       msg);
+               tst_exit();
+       }
+       setup();
+       TEST(check());
+       cleanup();
+}
+
+int check(void)
+{
+       /* loop counter */
+       int lc;
+
+       pid_t last_pid = 0;
+       pid_t pid;
+       int child_exit_code, distance, reaped, status;
+
+       /* Check looping state if -i option given */
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               if (lc % 32786 == 0)
+                       tst_resm(TINFO, "Iter: %d", lc/32768);
+               child_exit_code = lc % 256;
+               switch (pid = fork()) {
+               case -1:
+                       tst_brkm(TBROK|TERRNO, cleanup, "fork");
+                       tst_exit();
+               case 0:
+                       // Child
+                       exit(child_exit_code);
+               default:
+                       // Parent
+                       if (lc > 0) {
+                               printf("last_pid = %d\npid = %d\n", last_pid, 
pid);
+                               distance = PidDistance(last_pid, pid);
+                               if (distance == 0 || distance > 30000) {
+                                       tst_resm(TFAIL,
+                                               "Unexpected pid "
+                                               "sequence: previous "
+                                               "fork: pid=%d, current "
+                                               "fork: pid=%d for "
+                                               "iteration=%d.",
+                                               last_pid, pid, lc);
+                               }
+                       }
+                       last_pid = pid;
+
+                       reaped = wait(&status);
+                       if (reaped != pid) {
+                               tst_resm(TFAIL,
+                                       "Wait return value: expected "
+                                       "pid=%d, got %d, iteration %d.",
+                                       pid, reaped, lc);
+                       } else if (WEXITSTATUS(status != child_exit_code)
+                               != child_exit_code) {
+                               tst_resm(TFAIL,
+                                       "Unexpected exit status %x, "
+                                       "iteration %d.",
+                                       WEXITSTATUS(status), lc);
+                       }
+               }
+       }
+       return 0;
+}
+
+void setup(void)
+{
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       tst_tmpdir();
+}
+
+void cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_rmdir();
+       tst_exit();
+}
+
+/* The distance mod 32768 between two pids, where the first pid is
+   expected to be smaller than the second. */
+int PidDistance(pid_t first, pid_t second) {
+       return (second + 32768 - first) % 32768;
+}
-- 
1.7.1
From: CAI Qian <[email protected]>
Date: Tue, 30 Nov 2010 17:59:46 +0800
Subject: [PATCH] a race in pid generation that causes pids to be reused immediatelly

>From the mainline commit 5fdee8c4a5e1800489ce61963208f8cc55e42ea1:

A program that repeatedly forks and waits is susceptible to having the
same pid repeated, especially when it competes with another instance of
the same program.  This is really bad for bash implementation.
Furthermore, many shell scripts assume that pid numbers will not be used
for some length of time.

Race Description:

A                                B

// pid == offset == n            // pid == offset == n + 1
test_and_set_bit(offset, map->page)
                                 test_and_set_bit(offset, map->page);
                                 pid_ns->last_pid = pid;
pid_ns->last_pid = pid;
                                 // pid == n + 1 is freed (wait())

                                 // Next fork()...
                                 last = pid_ns->last_pid; // == n
                                 pid = last + 1;

Signed-off-by: CAI Qian <[email protected]>
---
 runtest/syscalls                        |    1 +
 testcases/kernel/syscalls/fork/fork13.c |  166 +++++++++++++++++++++++++++++++
 2 files changed, 167 insertions(+), 0 deletions(-)
 create mode 100644 testcases/kernel/syscalls/fork/fork13.c

diff --git a/runtest/syscalls b/runtest/syscalls
index b2bf144..d8f9b20 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -274,6 +274,7 @@ fork08 fork08
 fork09 fork09
 fork10 fork10
 fork11 fork11
+fork13 fork13 -c 2 -i 10000000
 
 fpathconf01 fpathconf01
 
diff --git a/testcases/kernel/syscalls/fork/fork13.c b/testcases/kernel/syscalls/fork/fork13.c
new file mode 100644
index 0000000..9c36310
--- /dev/null
+++ b/testcases/kernel/syscalls/fork/fork13.c
@@ -0,0 +1,166 @@
+/*
+ * a race in pid generation that causes pids to be reused immediatelly
+ *
+ * From the mainline commit 5fdee8c4a5e1800489ce61963208f8cc55e42ea1:
+ * 
+ * A program that repeatedly forks and waits is susceptible to having
+ * the same pid repeated, especially when it competes with another
+ * instance of the same program.  This is really bad for bash
+ * implementation.  Furthermore, many shell scripts assume that pid
+ * numbers will not be used for some length of time.
+ * 
+ * Race Description:
+ *
+ * A                                B
+ *
+ * // pid == offset == n            // pid == offset == n + 1
+ * test_and_set_bit(offset, map->page)
+ *                                  test_and_set_bit(offset, map->page);
+ *                                  pid_ns->last_pid = pid;
+ * pid_ns->last_pid = pid;
+ *                                  // pid == n + 1 is freed (wait())
+ *
+ *                                  // Next fork()...
+ *                                  last = pid_ns->last_pid; // == n
+ *                                  pid = last + 1;
+ *
+ * Copyright (C) 2010  Red Hat, Inc.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it
+ * is free of the rightful claim of any third person regarding
+ * infringement or the like.  Any license provided herein, whether
+ * implied or otherwise, applies only to this software file.  Patent
+ * licenses, if any, provided herein do not apply to combinations of
+ * this program with other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "test.h"
+#include "usctest.h"
+
+char *TCID = "fork13";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+static void setup(void);
+static int PidDistance(pid_t first, pid_t second);
+static void cleanup(void) LTP_ATTRIBUTE_NORETURN;
+static int check(void);
+
+int main(int argc, char* argv[])
+{
+	/* message returned from parse_opts */
+	char *msg;
+
+	msg = parse_opts(argc, argv, NULL, NULL);
+	if (msg != NULL) {
+		tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s",
+			msg);
+		tst_exit();
+	}
+	setup();
+	TEST(check());
+	cleanup();
+}
+
+int check(void)
+{
+	/* loop counter */
+	int lc;
+
+	pid_t last_pid = 0;
+	pid_t pid;
+	int child_exit_code, distance, reaped, status;
+
+	/* Check looping state if -i option given */
+	for (lc = 0; TEST_LOOPING(lc); lc++) {
+		if (lc % 32786 == 0)
+			tst_resm(TINFO, "Iter: %d", lc/32768);
+		child_exit_code = lc % 256;
+		switch (pid = fork()) {
+		case -1:
+			tst_brkm(TBROK|TERRNO, cleanup, "fork");
+			tst_exit();
+		case 0:
+			// Child
+			exit(child_exit_code);
+		default:
+			// Parent
+			if (lc > 0) {
+				printf("last_pid = %d\npid = %d\n", last_pid, pid);
+				distance = PidDistance(last_pid, pid);
+				if (distance == 0 || distance > 30000) {
+					tst_resm(TFAIL,
+						"Unexpected pid "
+						"sequence: previous "
+						"fork: pid=%d, current "
+						"fork: pid=%d for "
+						"iteration=%d.",
+						last_pid, pid, lc);
+				}
+			}
+			last_pid = pid;
+
+			reaped = wait(&status);
+			if (reaped != pid) {
+				tst_resm(TFAIL,
+					"Wait return value: expected "
+					"pid=%d, got %d, iteration %d.",
+					pid, reaped, lc);
+			} else if (WEXITSTATUS(status != child_exit_code)
+				!= child_exit_code) {
+				tst_resm(TFAIL,
+					"Unexpected exit status %x, "
+					"iteration %d.",
+					WEXITSTATUS(status), lc);
+			}
+		}
+	}
+	return 0;
+}
+
+void setup(void)
+{
+	/* capture signals */
+	tst_sig(FORK, DEF_HANDLER, cleanup);
+
+	/* Pause if that option was specified */
+	TEST_PAUSE;
+
+	tst_tmpdir();
+}
+
+void cleanup(void)
+{
+	/*
+	 * print timing stats if that option was specified.
+	 * print errno log if that option was specified.
+	 */
+	TEST_CLEANUP;
+
+	/* exit with return code appropriate for results */
+	tst_rmdir();
+	tst_exit();
+}
+
+/* The distance mod 32768 between two pids, where the first pid is
+   expected to be smaller than the second. */
+int PidDistance(pid_t first, pid_t second) {
+	return (second + 32768 - first) % 32768;
+}
-- 
1.7.1

------------------------------------------------------------------------------
Increase Visibility of Your 3D Game App & Earn a Chance To Win $500!
Tap into the largest installed PC base & get more eyes on your game by
optimizing for Intel(R) Graphics Technology. Get started today with the
Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs.
http://p.sf.net/sfu/intelisp-dev2dev
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to