📜 ⬆️ ⬇️

Basics of security of the Android operating system. Core level

Introduction


The most common operating system for smartphones today is Android. But not only this fact stirs interest in her. Openness, the ability to adjust something, tweak, and, of course, also break down to a large extent contribute to the increasing popularity of this platform. I will try to share the experience of how this operating system is arranged, as well as consider the security system. Anyone interested is welcome! In this article, I will look at kernel-level security.


Disclaimer

I will try to write the terms in English, as I am afraid to make a mistake in their translation. If someone knows how beautifully to translate them into Russian, write to me, and I will give a translation of these terms. It is advisable that you have the Android source code at hand (although I will try to give links to files on the Internet), because sometimes I will 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. Basics of security of the Android operating system. Core level
  2. Basics of security of the Android operating system. Native user space, part 1
  3. Basics of security of the Android operating system. Native user space, part 2
  4. Basics of security of the Android operating system. Security at the Application Framework level. Binder ipc

')


Android stack




Well, nowhere not to get away from this picture. I found it on the Internet and need it in order to understand what Android consists of. So, in 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 surprising it sounds, but initially, Android Inc. - this is a startup. As in all startups, this company had a task to make the most of existing solutions. Therefore, Linux was chosen as the core of this platform because of its openness and availability of the necessary functionality. In Android, the Linux kernel manages memory, processes, and is also used as the hardware abstraction layer (HAL). As far as I know, Linux drivers are either built into the kernel or developed as loadable kernel modules. Since the loading of kernel modules is disabled by default in Android, and if all the drivers are embedded, 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. Thus, the HAL is simply a set of interfaces, the implementation of which is implemented in the drivers. On the other hand, some systems were added to the core, which are typical only for Android systems. At the moment, they are not yet included in the main branch of the Linux kernel, so just download the Linux kernel and replace it with the Android kernel will not work. Among them, Binder (provides IPC / RPC interprocess communication), Asynchronous SHared MEMory — Ashmem (shared memory driver), Wakelocks (a mechanism that helps prevent screen darkening and / or processor shutdown), Low Memory Killer, Alarm, Logger and etc.

Native Libraries. This layer includes various native libraries that are needed for Android. 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. Applications are of two types: 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 in the "/ system / app" directory, in the second case in the "/ data / app".



Kernel Security





Let's look at the process of installing the application on your Android device. There are several ways to install an application on a 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 the PackageInstaller (used if, for example, an 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 an application from a computer).

During installation, Android assigns each application a unique user ID (UID) and group ID (GID) by default, so each application in this operating system has its own user. The username is usually app_x , and user IDs are calculated using the formula (Process.FIRST_APPLICATION_UID + x) , Process.FIRST_APPLICATION_UID is 10000. These application identifiers do not change. 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 an 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 / <package_name> , where <package_name> is the name of the Android package, for example com.ex.ex1 The Android package name is specified in the package property in the AndroidManifest.xml file This folder is Internal storage (internal storage), the directory where the application stores all its private data, and to which application developers get access using the Context.getFilesDir () or Context.getDir () functions. This folder has access permissions defined as drwxr-x - x , t . Only the owner and users in the group of owners 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 be MODE_WORLD_READABLE and / or MODE_WORLD_WRITABLE

In addition, at the kernel level, the unique UID and GID of each application are used to separate access to system resources (memory and processor time). Thus, at the kernel level, each application creates its own sandbox (Application Sandbox).

On the other hand, an application developer may indicate that some of its applications must have the same UID. In the AndroidManifest.xml file there is a special property sharedUserId for this . 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 permission also work at the kernel level. Let's, for example, consider the most commonly used permission android.permission.INTERNET If an application requests this permission, Android additionally includes this application in the special “inet” group during installation. Some other permissions also work. A list of correspondences between these permissions and the corresponding groups can be found in the frameworks / base / data / etc / platform.xml file:

 <permissions> ... <permission name="android.permission.INTERNET" > <group gid="inet" /> </permission> <permission name="android.permission.CAMERA" > <group gid="camera" /> </permission> <permission name="android.permission.READ_LOGS" > <group gid="log" /> </permission> ... </permissions> 

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

 ... #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 the application is in a group with the identifier AID_INET . If not, the application is denied access. The code for this check is very trivial :

 ... #ifdef CONFIG_ANDROID_PARANOID_NETWORK #include <linux/android_aid.h> static inline int current_has_network(void) { return in_egroup_p(AID_INET) || capable(CAP_NET_RAW); } #else static inline int current_has_network(void) { return 1; } #endif ... /* * Create an inet socket. */ static int inet_create(struct net *net, struct socket *sock, int protocol, int kern) { ... if (!current_has_network()) return -EACCES; ... } 




Conclusion


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


Links


  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

Source: https://habr.com/ru/post/175517/


All Articles