1) "fork-and-wait.c" int Data = 0x017; int main(int argc, char **argv) { pid_t pid; char buf[80]; open("/dev/tty0", O_RDONLY, 0); open("/dev/tty0", O_WRONLY, 0); sprintf(buf, "(Before fork(), Data should be 0x17) Data = 0x%08x\n", Data); write(1, buf, strlen(buf)); write(1, "Ready to fork()...\n", 19); pid = fork(); if (pid == 0) { sprintf(buf, "(Child, Data should first be 0x17) Data = 0x%08x\n", Data); write(1, buf, strlen(buf)); Data = 0x0129e; sprintf(buf, "(Child, Data should now be 0x129e) Data = 0x%08x\n", Data); write(1, buf, strlen(buf)); write(1, "(Child) Hello, world!\n", 22); exit(0); } else if (pid == (pid_t)(-1)) { write(1, "fork() failed.\n", 15); } else { sprintf(buf, "(Parent, Data should first be 0x17) Data = 0x%08x\n", Data); write(1, buf, strlen(buf)); Data = 0x0b38e; sprintf(buf, "(Parent, Data should now be 0xb38e) Data = 0x%08x\n", Data); write(1, buf, strlen(buf)); write(1, "(Parent) Calling waitpid()...\n", 30); waitpid(pid, 0, NULL); write(1, "(Parent) waitpid() returned successfully.\n", 42); } return 0; } objdump --disassemble --section=".text" user/usr/bin/fork-and-wait.exec > w objdump --disassemble --section=".text" -S user/usr/bin/fork-and-wait.exec > x objdump --headers user/usr/bin/fork-and-wait.exec > y xxd -g 1 user/usr/bin/fork-and-wait.exec > z int fork(void) { return trap(SYS_fork, 0); } 08048481 : 8048481: 55 push %ebp 8048482: 89 e5 mov %esp,%ebp 8048484: 83 ec 10 sub $0x10,%esp 8048487: e8 18 0c 00 00 call 80490a4 <__x86.get_pc_thunk.cx> 804848c: 81 c1 74 6b 00 00 add $0x6b74,%ecx 8048492: c7 45 fc 02 00 00 00 movl $0x2,-0x4(%ebp) 8048499: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%ebp) 80484a0: 8b 45 fc mov -0x4(%ebp),%eax 80484a3: 8b 55 f8 mov -0x8(%ebp),%edx 80484a6: cd 2e int $0x2e 80484a8: 89 45 f4 mov %eax,-0xc(%ebp) 80484ab: b8 27 00 00 00 mov $0x27,%eax 80484b0: cd 2e int $0x2e 80484b2: 89 c2 mov %eax,%edx 80484b4: 8d 05 84 f2 04 08 lea 0x804f284,%eax 80484ba: 89 10 mov %edx,(%eax) 80484bc: 8b 45 f4 mov -0xc(%ebp),%eax 80484bf: 90 nop 80484c0: c9 leave 80484c1: c3 ret 2) "/sbin/init.c" char *empty[] = { NULL }; const char *hi = "init: starting shell on "; const char *sh = "/bin/sh"; const char *home = "/"; static void spawn_shell_on(char *tty) { if (!fork()) { close(0); close(1); close(2); if (-1 == open_tty(tty)) { exit(1); } chdir(home); printf(hi,NULL); printf(tty,NULL); printf("\n"); execve(sh, empty, empty); fprintf(stderr, "exec failed!\n"); } } Here comes trouble! execve() calls malloc(). a) malloc() depends on properly initialized global variables b) the first time you call malloc(), it will call malloc_init() c) malloc_init() calls INIT_MMAP(), which depends on the correct implementation of the /dev/zero device in kernel 2 d) malloc_init() then calls mmap(): #define MMAP(size) mmap(0, (size), PROT_READ|PROT_WRITE, MAP_PRIVATE, MMAP_FD, 0); page_dir = (struct pginfo **) MMAP(malloc_pagesize); mmap() returns the first virtual address of a newly created memory segment this memory segment is 4KB in size since malloc_pagesize = 4096 this is not the heap! the heap is created and managed by the brk/sbrk() system call Can it be a kernel virtual address? Of course not! How can maloc() uses a kernel virtual address? 3) Kernel 3 FAQ - do_fork() http://merlot.usc.edu/cs402-f20/projects/kernel/faq.html#q_sbininit 4) Kernel 3 FAQ - /sbin/init http://merlot.usc.edu/cs402-f20/projects/kernel/faq.html#q_sbininit 5) Kernel 3 FAQ - dynamic region and do_brk() http://merlot.usc.edu/cs402-f20/projects/kernel/faq.html#q_heap 6) Other user space tests memtest.c eatmem.c forkbomb.c 7) Kernel 3 FAQ - make "forkbomb" run forever http://merlot.usc.edu/cs402-f20/projects/kernel/faq.html#q_forkbomb