mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
fork and fork bomb moved in from cpp-cheat
This commit is contained in:
42
README.adoc
42
README.adoc
@@ -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[]
|
||||||
|
|||||||
@@ -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
107
userland/posix/fork.c
Normal 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;
|
||||||
|
}
|
||||||
13
userland/posix/fork_bomb.c
Normal file
13
userland/posix/fork_bomb.c
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user