clone.c (4046B)
1 #define _GNU_SOURCE 2 #include <sched.h> 3 #include <stdarg.h> 4 #include <stdlib.h> 5 #include <sys/wait.h> 6 #include <stdio.h> 7 #include <errno.h> 8 #include <stdint.h> 9 #include <unistd.h> 10 #include <sys/types.h> 11 #include <string.h> 12 #include <syscall.h> 13 #include <sys/syscall.h> 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 #include <fcntl.h> 17 #include <stdio.h> 18 #include <errno.h> 19 #include <unistd.h> 20 21 /* For our clone experiments, we working on a very low level and 22 * fiddle around with threading. However, this leads to a problem with 23 * the libc, which must perform some user-space operations to setup a 24 * new thread. For example, in a clone()ed thread, we cannot simply 25 * use printf(). Therefore, we provide you with a simple function to 26 * output a string and a number. The writing to stdout (fd=1) is done 27 * with plain system calls. 28 * 29 * Example: syscall_write("foobar = ", 23); 30 */ 31 int syscall_write(char *msg, int number) { 32 write(1, msg, strlen(msg)); 33 if (number != 0) { 34 char buffer[sizeof(number) * 3]; 35 char *p = &buffer[sizeof(number) * 3]; 36 int len = 1; 37 *(--p) = '\n'; 38 if (number < 0) { 39 write(1, "-", 1); 40 number *= -1; 41 } 42 while (number > 0) { 43 *(--p) = (number % 10) + '0'; 44 number /= 10; 45 len ++; 46 } 47 write(1, p, len); 48 } else { 49 write(1, "0\n", 2); 50 } 51 52 53 return 0; 54 } 55 56 // For the new task, we always require an stack area. To make our life 57 // easier, we just statically allocate an global variable of PAGE_SIZE. 58 char stack[4096]; 59 60 // To demonstrate whether child and parent are within the same 61 // namespace, we count up a global variable. If they are within the 62 // same address space, we will see modification to this counter in 63 // both namespaces 64 volatile int counter = 0; 65 66 int child_entry(void* arg) { 67 // We just give a little bit of information to the user. 68 syscall_write(": Hello from child_entry", 0); 69 syscall_write(": getppid() = ", getppid()); // What is our parent PID 70 syscall_write(": getpid() = ", getpid()); // What is our thread group/process id 71 syscall_write(": gettid() = ", gettid()); // The ID of this thread! 72 syscall_write(": getuid() = ", getuid()); // What is the user id of this thread. 73 74 75 // We increment the global counter in one second intervals. If we 76 // are in our own address space, this will have no influence on 77 // the parent! 78 while (counter < 4) { 79 // syscall_write("child counter = ", counter); 80 counter++; 81 sleep(1); 82 } 83 84 return 0; 85 } 86 87 88 int main(int argc, char *argv[]) { 89 if (argc != 2) { 90 printf("usage: %s MODE\n", argv[0]); 91 printf("MODE:\n"); 92 printf(" - fork -- emulate fork with clone\n"); 93 printf(" - chimera -- create process/thread chimera\n"); 94 printf(" - thread -- create a new thread in a process\n"); 95 printf(" - user -- create a new process and alter its UID namespace\n"); 96 return -1; 97 } 98 99 syscall_write("> Hello from main!", 0); 100 syscall_write("> getppid() = ", getppid()); 101 syscall_write("> getpid() = ", getpid()); 102 syscall_write("> gettid() = ", gettid()); 103 syscall_write("> getuid() = ", getuid()); 104 105 int flags = 0; 106 void *arg = NULL; 107 if (!strcmp(argv[1], "fork")) { 108 // Receive a SIGCHLD if the child terminates. 109 flags = SIGCHLD; 110 } else if (!strcmp(argv[1], "chimera")) { 111 // Process-thread chimera. 112 // Child process shares virtual memory with the parent. 113 flags = SIGCHLD | CLONE_VM; 114 } else if (!strcmp(argv[1], "thread")) { 115 // Thread 116 // Child shares virtual memory with parent. 117 // Child is in the same thread group as parent. 118 // Child shares the signal handler table with the parent. 119 flags = CLONE_VM | CLONE_THREAD | CLONE_SIGHAND; 120 } else if (!strcmp(argv[1], "user")) { 121 // TODO 122 flags = SIGCHLD; 123 } else { 124 printf("Invalid clone() mode: %s\n", argv[1]); 125 return -1; 126 } 127 128 pid_t pid = clone(child_entry, &stack[sizeof(stack)-1], flags, arg); 129 if (pid == -1) { 130 perror("clone"); 131 return -1; 132 } 133 syscall_write("> clone() returned ", pid); 134 135 syscall_write("\n!!!!! Press C-c to terminate. !!!!!", 0); 136 while(counter < 4) { 137 syscall_write("counter = ", counter); 138 sleep(1); 139 } 140 141 return 0; 142 }