Security basics of the Android operating system. Core level


    The most common operating system for smartphones today is Android. But not only this fact fuels interest in her. Openness, the ability to tweak, tweak something, and, of course, break it, also contribute to a large extent to the popularity of this platform. I will try to share my experience on how this operating system works, as well as consider the security system. Everyone who is interested, welcome! In this article, I will discuss kernel-level security.


    I will try to write the terms in English, as I am afraid to make a mistake in translating them. If someone knows how to translate them beautifully into Russian, write to me and I will give a translation of these terms. It is advisable that you have the source code of Android at hand (although I will try to give links to files on the Internet), because I will sometimes give links to files where this or that functionality is located. How to download the source code, you can read here or here in this article on Habr.

    List of Articles

    Here are links to my articles from this topic:
    1. Security basics of the Android operating system. Core level
    2. Security basics of the Android operating system. Native user space, part 1
    3. Security basics of the Android operating system. Native user space, part 2
    4. Security basics of the Android operating system. Security at the Application Framework level. Binder IPC

    Android stack

    Well, there’s no getting around this picture. I found it on the Internet and I need it in order to understand what Android consists of. So, on the Android stack, there are four levels (bottom-up):
    1. Linux kernel (Linux kernel)
    2. Native libraries
    3. Application framework
    4. Applications

    Linux kernel.How unsurprisingly this sounds, but initially, Android Inc. - this is a startup. As in all startups, this company had the task of maximizing the use of existing solutions. Therefore, Linux was chosen as the kernel of this platform because of its openness and the availability of the necessary functionality. On Android, the Linux kernel manages memory, processes, and is also used as a hardware abstraction layer (HAL). As far as I know, in Linux, drivers are either built into the kernel or designed as loadable kernel modules. Since loading of kernel modules in Android is disabled by default, and if you embed all the drivers, the kernel will grow very much, it was decided to create an intermediate layer (proxy) between the kernel and the drivers, which was called HAL. So a HAL is just a set of interfaces, implementation of which is implemented in drivers. On the other hand, some systems that are specific only to Android systems have been added to the kernel. At the moment, they are not yet included in the main branch of the Linux kernel, so just downloading the Linux kernel and replacing it with the Android kernel will fail. Among them, Binder (provides IPC / RPC interprocess communication), Asynchronous SHared MEMory - Ashmem (shared memory driver), Wakelocks (a mechanism that helps prevent screen dimming and / or processor shutdown), Low Memory Killer, Alarm, Logger and etc.

    Native Libraries. This layer includes various native libraries that are necessary for Android to work. They are also borrowed from the open-source community. Among them we can find SQLite, WebKit, etc.

    Android Framework This layer refers to what we usually interact with when we write our Android applications (PowerManager, ActivityManager, NotificationManager, etc.).

    Applications. There are two types of applications: those that come with the system image (system) and applications that we download from the market or other sources. In the first case, the applications in the device are located in the "/ system / app" directory, in the second case in the "/ system / app".

    Kernel Security

    Let's look at the process of installing an application on an Android device. There are several ways to install the application on the device (in general):
    1. Using the PackageInstaller Application
    2. Using the Android Market App
    3. Using the adb install command

    In the figure, for example, the ex1.apk application is installed using PackageInstaller (used if, for example, the application was sent by mail and you want to install it from the device), ex2.apk is installed using the Android Market (Google Play), and The ex3.apk application is installed using the adb install ex3.apk command (usually this command is used by application developers to install the application from a computer).

    During installation, Android assigns a unique user ID (UID) and group ID (GID) to each application by default , so each application in this operating system has its own user. Username is usually app_x , and user identifiers are calculated using the formula(Process.FIRST_APPLICATION_UID + x) , Process.FIRST_APPLICATION_UID is 10000. These application identifiers are not changed. The list of installed applications is stored in the file "/data/system/packages.list" and if you have a rooted phone, or you work with the emulator, then you can view this file using the following command:

    adb shell cat /data/system/packages.list

    Each application has its own home directory, for example / data / data /where - the name of the Android package, for example com.ex.ex1 The name of the Android package is set in the package property in the AndroidManifest.xml file. This folder is Internal storage, the directory where the application stores all its private data, and which application developers access using the functions Context.getFilesDir () or Context.getDir () For this folder, access rights are defined as drwxr-x - x , i.e. only the owner and users in the owner group have full access to this folder. And since each application is defined as a unique user, this means that applications, by default, do not have access to each other's information. Although when creating a file in the internal storage, you can explicitly specify that this file will beMODE_WORLD_READABLE and / or MODE_WORLD_WRITABLE

    In addition, at the kernel level, the unique UIDs and GIDs of each application are used to share access to system resources (memory and processor time). Thus, at the kernel level, each application has its own sandbox (Application Sandbox).

    On the other hand, the application developer may indicate that some HIS applications must have the same UID. There is a special property sharedUserId for this in the AndroidManifest.xml file . In this case, these applications will have access to each other’s resources, but only if they are signed by the same developer key.

    Some permissions also work at the kernel level. Let's, for example, consider the most used permission android.permission.INTERNET. If an application requests this permission, then Android during installation additionally includes this application in a special “inet” group. Some other permissions also work. A list of the correspondence between these permissions and the corresponding groups can be found in the frameworks / base / data / etc / platform.xml file :


    The list of correspondence between the names of these groups and the values ​​(GID) is specified explicitly in the file system / core / include / private / android_filesystem_config.h in the array of structures android_ids []:

    #define AID_ROOT             0  /* traditional unix root user */
    #define AID_SYSTEM        1000  /* system server */
    #define AID_CAMERA        1006  /* camera devices */
    #define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */
    static const struct android_id_info android_ids[] = {
        { "root",      AID_ROOT, },
        { "camera",    AID_CAMERA, },
        { "log",       AID_LOG, },
        { "inet",      AID_INET, },

    Thus, if an application tries to connect to the Internet, the kernel checks if this application is in the group with the identifier AID_INET . If not, the application is denied access. The code for this check is very trivial :

    static inline int current_has_network(void)
            return in_egroup_p(AID_INET) || capable(CAP_NET_RAW);
    static inline int current_has_network(void)
            return 1;
     *      Create an inet socket.
    static int inet_create(struct net *net, struct socket *sock, int protocol,
                           int kern)
        if (!current_has_network())
                    return -EACCES;


    This is my first article on Habré, so do not judge strictly. If the community is interested, then I will continue to describe Android internals in future articles. I understand that I don’t know much, and there’s always not enough time, but I will try to share what I have already passed through myself. Hope to learn something new from the comments! If someone is interested in a specific topic, then write in the comments, I will try to take into account your wishes in future articles.


    1. "Embedded Android" by Karim Yaghmour
    2. Android Security Underpinnings by Marko Gargenta
    3. "Understanding Android Security" by William Enck et al.
    4. Android Security Overview

    Also popular now: