1 /* 2 * a race in pid generation that causes pids to be reused immediately 3 * 4 * From the mainline commit 5fdee8c4a5e1800489ce61963208f8cc55e42ea1: 5 * 6 * A program that repeatedly forks and waits is susceptible to having 7 * the same pid repeated, especially when it competes with another 8 * instance of the same program. This is really bad for bash 9 * implementation. Furthermore, many shell scripts assume that pid 10 * numbers will not be used for some length of time. 11 * 12 * Race Description: 13 * 14 * A B 15 * 16 * // pid == offset == n // pid == offset == n + 1 17 * test_and_set_bit(offset, map->page) 18 * test_and_set_bit(offset, map->page); 19 * pid_ns->last_pid = pid; 20 * pid_ns->last_pid = pid; 21 * // pid == n + 1 is freed (wait()) 22 * 23 * // Next fork()... 24 * last = pid_ns->last_pid; // == n 25 * pid = last + 1; 26 * 27 * Copyright (C) 2010 Red Hat, Inc. 28 * This program is free software; you can redistribute it and/or 29 * modify it under the terms of version 2 of the GNU General Public 30 * License as published by the Free Software Foundation. 31 * 32 * This program is distributed in the hope that it would be useful, 33 * but WITHOUT ANY WARRANTY; without even the implied warranty of 34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 35 * 36 * Further, this software is distributed without any warranty that it 37 * is free of the rightful claim of any third person regarding 38 * infringement or the like. Any license provided herein, whether 39 * implied or otherwise, applies only to this software file. Patent 40 * licenses, if any, provided herein do not apply to combinations of 41 * this program with other software, or any other product whatsoever. 42 * 43 * You should have received a copy of the GNU General Public License 44 * along with this program; if not, write the Free Software 45 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 46 * 02110-1301, USA. 47 */ 48 49 #include <sys/types.h> 50 #include <sys/stat.h> 51 #include <sys/wait.h> 52 #include <fcntl.h> 53 #include <errno.h> 54 #include <unistd.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include "test.h" 58 59 char *TCID = "fork13"; 60 int TST_TOTAL = 1; 61 62 static unsigned long pid_max; 63 64 #define PID_MAX_PATH "/proc/sys/kernel/pid_max" 65 #define PID_MAX 32768 66 #define RETURN 256 67 68 static void setup(void); 69 static int pid_distance(pid_t first, pid_t second); 70 static void cleanup(void); 71 static void check(void); 72 73 int main(int argc, char *argv[]) 74 { 75 tst_parse_opts(argc, argv, NULL, NULL); 76 setup(); 77 check(); 78 cleanup(); 79 tst_exit(); 80 } 81 82 static void check(void) 83 { 84 long lc; 85 pid_t last_pid = 0; 86 pid_t pid; 87 int child_exit_code, distance, reaped, status; 88 89 for (lc = 0; TEST_LOOPING(lc); lc++) { 90 tst_count = 0; 91 child_exit_code = lc % RETURN; 92 switch (pid = fork()) { 93 case -1: 94 tst_brkm(TBROK | TERRNO, cleanup, "fork"); 95 case 0: 96 exit(child_exit_code); 97 default: 98 if (lc > 0) { 99 distance = pid_distance(last_pid, pid); 100 if (distance == 0) { 101 tst_resm(TFAIL, 102 "Unexpected pid sequence: " 103 "previous fork: pid=%d, " 104 "current fork: pid=%d for " 105 "iteration=%ld.", last_pid, 106 pid, lc); 107 return; 108 } 109 } 110 last_pid = pid; 111 112 reaped = waitpid(pid, &status, 0); 113 if (reaped != pid) { 114 tst_resm(TFAIL, 115 "Wait return value: expected pid=%d, " 116 "got %d, iteration %ld.", pid, reaped, 117 lc); 118 return; 119 } else if (WEXITSTATUS(status) != child_exit_code) { 120 tst_resm(TFAIL, "Unexpected exit status %x, " 121 "iteration %ld.", WEXITSTATUS(status), 122 lc); 123 return; 124 } 125 } 126 } 127 tst_resm(TPASS, "%ld pids forked, all passed", lc); 128 } 129 130 static void setup(void) 131 { 132 tst_require_root(); 133 134 tst_sig(FORK, DEF_HANDLER, cleanup); 135 TEST_PAUSE; 136 137 /* Backup pid_max value. */ 138 SAFE_FILE_SCANF(NULL, PID_MAX_PATH, "%lu", &pid_max); 139 140 SAFE_FILE_PRINTF(NULL, PID_MAX_PATH, "%d", PID_MAX); 141 } 142 143 static void cleanup(void) 144 { 145 /* Restore pid_max value. */ 146 FILE_PRINTF(PID_MAX_PATH, "%lu", pid_max); 147 } 148 149 /* The distance mod PIDMAX between two pids, where the first pid is 150 expected to be smaller than the second. */ 151 static int pid_distance(pid_t first, pid_t second) 152 { 153 return (second + PID_MAX - first) % PID_MAX; 154 } 155