[PATCH] Add Selftest to test fork() syscall

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This test verifies the correct behavior of the fork() system call,
which creates a child process by duplicating the parent process.

The test checks the following:
- The child PID returned by fork() is present in /proc.
- The child PID is different from the parent PID.
- The memory allocated to a variable in the child process is independent
  of the parent process.

Test logs :

- Run without root
 TAP version 13
 1..1
 ok 1 # SKIP This test needs root to run!

- Run with root
TAP version 13
1..1
 # Inside the parent process.
 # Child PID got from fork() return : 56038
 # Parent PID from getpid(): 56037
 # Inside the child process.
 1..2
 ok 1 Child Pid from /proc and fork() matching
 ok 2 Child Pid != Parent pid
 1..3
 ok 3 After modification in child No effect on the value of 'var' in parent
 # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0

Signed-off-by: Shivam Chaudhary <cvam0000@xxxxxxxxx>
---

Here is my proposal for a new directory, /syscalls, to add syscall selftests,
as there is currently no dedicated space for these tests. I encountered this
issue while writing the test case for the delete_module syscall and was unsure
where to place it. As a heads-up, the delete_module test is currently under
review, and I would like to add it to this directory.

 tools/testing/selftests/Makefile              |   1 +
 tools/testing/selftests/syscalls/.gitignore   |   1 +
 .../syscalls/fork_syscall/.gitignore          |   1 +
 .../selftests/syscalls/fork_syscall/Makefile  |   5 +
 .../syscalls/fork_syscall/fork_syscall.c      | 151 ++++++++++++++++++
 5 files changed, 159 insertions(+)
 create mode 100644 tools/testing/selftests/syscalls/.gitignore
 create mode 100644 tools/testing/selftests/syscalls/fork_syscall/.gitignore
 create mode 100644 tools/testing/selftests/syscalls/fork_syscall/Makefile
 create mode 100644 tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 363d031a16f7..9265c17c5de3 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -97,6 +97,7 @@ TARGETS += sparc64
 TARGETS += splice
 TARGETS += static_keys
 TARGETS += sync
+TARGETS += syscalls/fork_syscall
 TARGETS += syscall_user_dispatch
 TARGETS += sysctl
 TARGETS += tc-testing
diff --git a/tools/testing/selftests/syscalls/.gitignore b/tools/testing/selftests/syscalls/.gitignore
new file mode 100644
index 000000000000..c7ae138d3f0c
--- /dev/null
+++ b/tools/testing/selftests/syscalls/.gitignore
@@ -0,0 +1 @@
+// SPDX-License-Identifier: GPL-2.0
\ No newline at end of file
diff --git a/tools/testing/selftests/syscalls/fork_syscall/.gitignore b/tools/testing/selftests/syscalls/fork_syscall/.gitignore
new file mode 100644
index 000000000000..788cc1ff70bd
--- /dev/null
+++ b/tools/testing/selftests/syscalls/fork_syscall/.gitignore
@@ -0,0 +1 @@
+# SPDX-License-Identifier: GPL-2.0-only
\ No newline at end of file
diff --git a/tools/testing/selftests/syscalls/fork_syscall/Makefile b/tools/testing/selftests/syscalls/fork_syscall/Makefile
new file mode 100644
index 000000000000..56033a3d5a87
--- /dev/null
+++ b/tools/testing/selftests/syscalls/fork_syscall/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_GEN_PROGS := fork_syscall
+CFLAGS += -Wall
+
+include ../lib.mk
\ No newline at end of file
diff --git a/tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c b/tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c
new file mode 100644
index 000000000000..eab22831f7e1
--- /dev/null
+++ b/tools/testing/selftests/syscalls/fork_syscall/fork_syscall.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* kselftest for fork() system call
+ *
+ * Summery : fork() system call is used to create a new process
+ * by duplicating an existing one. The new process, known as the
+ * child process, is a copy of the parent process.
+ * 
+ * Child process is dublicate process but has different PID and 
+ * memory allocation.
+ * 
+ * About the test : With this test we are testing the following:
+ * - Child PID which fork() returns to Parent is present in /proc
+ * - Child PID is not same as Parent PID.
+ * - Memory allocation to a variable in child and parent process
+ *   is different.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "../../kselftest.h"
+
+// Function to check if a string is numeric (PID check)
+int is_numeric(const char *str) {
+    while (*str) {
+        if (!isdigit(*str)) return 0;
+        str++;
+    }
+    return 1;
+}
+
+// Function to find the child PID in /proc
+pid_t find_child_pid(pid_t parent_pid) {
+    DIR *proc_dir = opendir("/proc");
+    struct dirent *entry;
+
+    if (proc_dir == NULL) {
+        perror("Failed to open /proc directory");
+        ksft_exit_fail();
+        return 1;
+    }
+
+    // Iterate through the /proc directory to find PIDs
+    while ((entry = readdir(proc_dir)) != NULL) {
+        // Check if the entry is a PID
+        if (is_numeric(entry->d_name)) {  
+            pid_t pid = atoi(entry->d_name);
+
+            // Construct the path to /proc/<pid>/
+            //stat to check the parent PID
+
+            char path[40], buffer[100];
+            snprintf(path, 40, "/proc/%d/stat", pid);
+
+            FILE *stat_file = fopen(path, "r");
+            if (stat_file != NULL) {
+                fgets(buffer, 100, stat_file);
+                fclose(stat_file);
+
+                // The fourth field in /proc/<pid>/stat is the parent PID
+                pid_t ppid;
+                sscanf(buffer, "%*d %*s %*c %d", &ppid);
+
+                if (ppid == parent_pid) {
+                    closedir(proc_dir);
+                    // Return the child PID if the parent PID matches
+                    return pid;  
+                }
+            }
+        }
+    }
+
+    closedir(proc_dir);
+
+    // Return -1 if no child PID was found
+    return -1;  
+}
+
+int main(void) {
+
+    // Setting up kselftest framework
+	ksft_print_header();
+	ksft_set_plan(1);
+
+    // Check if test is run a root
+	if (geteuid()) {
+		ksft_test_result_skip("This test needs root to run!\n");
+		return 1;
+	}
+
+    // forking
+    pid_t pid = fork();
+
+    // Declare a variable in both parent and child processes
+    int var = 17;  
+
+    if (pid == -1) {
+		ksft_test_result_error("%s.\n", strerror(errno));
+		ksft_finished();
+		return 1;
+
+    } else if (pid == 0) {
+        // This is the child process
+        ksft_print_msg("Inside the child process.\n");
+        var = 1998;
+
+    } else {
+        // This is the parent process
+        pid_t ppid=getpid();
+        ksft_print_msg("Inside the parent process.\n");
+        ksft_print_msg("Child PID got from fork() return : %d\n", pid);
+        ksft_print_msg("Parent PID from getpid(): %d\n",ppid);
+
+        // Find the child PID in /proc
+        pid_t child_pid = find_child_pid(getpid());
+        if (child_pid != -1) {
+            ksft_set_plan(2);
+            if(child_pid == pid && pid != ppid && var != 1998) {
+                ksft_test_result_pass("Child Pid from /proc and fork() matching\n");
+                ksft_test_result_pass("Child Pid != Parent pid\n");
+                ksft_set_plan(3);
+                ksft_test_result_pass(
+                    "After modification in child No effect on the value of 'var' in parent\n");
+                ksft_exit_pass();
+		        return 0;
+            }
+            else {
+                ksft_exit_fail();
+			    return 1;
+            }
+        }
+        else {
+            ksft_test_result_fail("Child Pid from /proc and fork() does not match");
+            ksft_exit_fail();
+			return 1;
+        }
+
+        // Wait for the child process to finish
+        wait(NULL);
+    }
+
+    return 0;
+}
+
-- 
2.34.1





[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux