fork and fork bomb moved in from cpp-cheat

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-11-12 00:00:00 +00:00
parent 762cd8d601
commit ca47a77676
4 changed files with 191 additions and 6 deletions

View File

@@ -13783,6 +13783,8 @@ This first allows memory overcommit so to that the program can mmap 1GiB, 4x mor
It then walks over every page and writes a value in it to ensure that it is used. It then walks over every page and writes a value in it to ensure that it is used.
A <<fork-bomb>> is another example that can trigger the OOM killer.
Algorithm used by the OOM: https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first Algorithm used by the OOM: https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first
==== C multithreading ==== C multithreading
@@ -13875,9 +13877,47 @@ These links provide a clear overview of what POSIX is:
* link:userland/posix/count.c[] illustrates `sleep()` * link:userland/posix/count.c[] illustrates `sleep()`
* link:userland/posix/count_to.c[] minor variation of link:userland/posix/count.c[] * link:userland/posix/count_to.c[] minor variation of link:userland/posix/count.c[]
==== fork
POSIX' multiprocess API. Contrast with <<pthreads>> which are for threads.
Example: link:userland/posix/fork.c[]
Sample <<userland-setup-getting-started-natively,native userland output>> on Ubuntu 19.04 at 762cd8d601b7db06aa289c0fca7b40696299a868 + 1:
....
before fork before fork pid=13038 ppid=4805
after fork after fork pid=13038 ppid=4805
after (pid == 0) after (pid == 0) pid=13038 ppid=4805
after fork after fork pid=13039 ppid=13038
inside (pid == 0) inside (pid == 0) pid=13039 ppid=13038
after wait after wait pid=13038 ppid=4805
fork() return = 13039
....
Read the source comments and understand everything that is going on!
===== Fork bomb
https://en.wikipedia.org/wiki/Fork_bomb
DANGER! Only run this on your host if you have saved all data you care about! Better run it inside an emulator! QEMU v4.0.0 <<user-mode-simulation,user mode>> is not safe enough either because it is very native does not limit guest memory, so it will still blow up the host!
So without further ado, let's rock:
....
./run --eval-after './posix/fork_bomb.out danger'
....
Source: link:userland/posix/fork_bomb.c[]
Outcome on LKMC 762cd8d601b7db06aa289c0fca7b40696299a868 + 1: after a few seconds of an unresponsive shell, we get a visit form the <<linux-out-of-memory-killer>>, and the system is restored!
==== pthreads ==== pthreads
POSIX' multithreading API. This was for a looong time the only "portable" multithreading alternative, until <<cpp-multithreading,C++11 finally added threads>>, thus also extending the portability to Windows. POSIX' multithreading API. Contrast with <<fork>> which is for processes.
This was for a looong time the only "portable" multithreading alternative, until <<cpp-multithreading,C++11 finally added threads>>, thus also extending the portability to Windows.
* link:userland/posix/pthread_count.c[] * link:userland/posix/pthread_count.c[]
* link:userland/posix/pthread_deadlock.c[] * link:userland/posix/pthread_deadlock.c[]

View File

@@ -127,6 +127,27 @@ class PathProperties:
}, },
} }
# TODO wire up.
unimplemented_userland_syscalls = {
'gem5': {
'all': {
'wait',
},
'arm': {
},
'x86_64': {
},
},
'qemu': {
'all': {
},
'arm': {
},
'x86_64': {
},
},
}
''' '''
Encodes properties of userland and baremetal paths. Encodes properties of userland and baremetal paths.
For directories, it applies to all files under the directory. For directories, it applies to all files under the directory.
@@ -620,6 +641,14 @@ path_properties_tuples = (
'baremetal': True, 'baremetal': True,
'signal_received': signal.Signals.SIGHUP, 'signal_received': signal.Signals.SIGHUP,
}, },
'fork.c': {
# wait
'gem5_unimplemented_syscall': True
},
'mmap_file.c': {
# https://github.com/cirosantilli/linux-kernel-module-cheat/issues/102
'gem5_unimplemented_syscall': True
},
'pthread_count.c': { 'pthread_count.c': {
'more_than_1s': True, 'more_than_1s': True,
'test_run_args': {'cpus': 2}, 'test_run_args': {'cpus': 2},
@@ -627,12 +656,8 @@ path_properties_tuples = (
'pthread_self.c': { 'pthread_self.c': {
'test_run_args': {'cpus': 2}, 'test_run_args': {'cpus': 2},
}, },
'mmap_file.c': {
# https://github.com/cirosantilli/linux-kernel-module-cheat/issues/102
'gem5_unimplemented_syscall': True
},
'wget.c': {'requires_internet': True},
'sleep_forever.c': {'more_than_1s': True}, 'sleep_forever.c': {'more_than_1s': True},
'wget.c': {'requires_internet': True},
'virt_to_phys_test.c': {'more_than_1s': True}, 'virt_to_phys_test.c': {'more_than_1s': True},
} }
), ),

107
userland/posix/fork.c Normal file
View File

@@ -0,0 +1,107 @@
/* https://cirosantilli.com/linux-kernel-module-cheat#fork */
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h> /* fork */
void print_pid(char *msg) {
printf("%s ", msg);
printf(
"%s pid=%jd ppid=%jd\n",
msg,
(intmax_t)getpid(),
(intmax_t)getppid()
);
}
int main(void) {
int status;
/* This variable will be duplicated on the parent and on the child. */
int i;
pid_t pid;
/* Parent PID */
pid_t ppid;
i = 0;
ppid = getpid();
if (ppid == -1) {
perror("getpid");
exit(EXIT_FAILURE);
}
/* Happens on parent only: child does not exist yet! */
print_pid("before fork");
/* Flush before fork so that existing output won't be duplicated. */
fflush(stdout);
fflush(stderr);
/* In case of success, PID is set differently on parent and child
* so you can distinguish between them. For the child, `pid = 0`. */
pid = fork();
if (pid == -1) {
perror("fork");
assert(false);
}
/* Happens both on parent and child. */
print_pid("after fork");
if (pid == 0) {
/* Happens on child only.
*
* This print is asynchronous with the process stdout.
* So it might not be in the line program order.
* But they both go to the same terminal. */
print_pid("inside (pid == 0)");
/* Child has a different PID than its parent */
pid = getpid();
if (pid == -1) {
perror("getpid");
exit(EXIT_FAILURE);
}
assert(pid != ppid);
/* This only change the child's `i` because memory was cloned (unlike threads). */
i++;
/* The child exits here. */
exit(EXIT_SUCCESS);
}
/* Only the parent reaches this point because of the exit call
* done on the child.
*
* Could happen before or after the child executes. */
print_pid("after (pid == 0)");
/* Wait for any child to terminate, then wake up.
* Since we only have on child here, wait for that one child to terminate. */
wait(&status);
if (WIFEXITED(status)) {
assert(status == WEXITSTATUS(EXIT_SUCCESS));
} else {
perror("execl abnormal exit");
assert(false);
}
/* fork returns the child pid to the parent.
*
* This could be asserted with the getpid in the child,
* but would require the child to communicate that back to the parent,
* which would need a `mmap` + `semaphore`,
* and we don't want to complicate the example too much. */
print_pid("after wait");
printf("fork() return = %jd\n", (intmax_t)pid);
/* Memory was cloned, parent `i` was only modified in child memory. */
assert(i == 0);
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,13 @@
/* https://cirosantilli.com/linux-kernel-module-cheat#fork-bomb */
#define _XOPEN_SOURCE 700
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
if (argc > 1 && strcmp(argv[1], "danger") == 0) {
while (1) {
fork();
}
}
}