📜 ⬆️ ⬇️

Basics of security of the Android operating system. Security at the Application Framework level. Binder ipc

Introduction


After a short break, I continue to explain the basic principles of how security is provided in the Android operating system. Today I will begin to describe security at the Application Framework level. But in order to understand this topic, you first need to consider how the Inter-Process Communication (IPC) mechanism is implemented in Android. This mechanism is called Binder IPC, and today we will consider its features. All who are interested, welcome!



List of articles

Below are links to my articles in this series:
  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



Why binder ipc?


As I wrote in the first article of the cycle, each Android application runs in its own “sandbox” (Application Sandbox). The sandbox mechanism in Android is based on assigning each application a unique user ID (UID) and group ID (GID) , thus each application (application or app) in this operating system has its own unique non-privileged user. We considered this topic in the first article of the cycle . At the same time, the owners of all critical system resources are more privileged users whose names and identifiers are hardcoded into the system (see system / core / include / private / android_filesystem_config.h ). System services that run on behalf of these users have access to the relevant critical system resources (for example, GPS data), while normal application processes cannot access these resources.
')
However, applications should be able to “ask” system services to provide them with such information, and the latter, in turn, should be able to provide such information to applications. Since applications and system services run in different processes, to organize such an exchange, the operating system must provide a mechanism for exchanging information between processes. Moreover, even regular applications sometimes have to interact with each other. For example, an email client may “ask” the image viewer to display a graphic application to the letter.

In Android, the exchange of signals and data between processes is organized using the Inter-Process Communication framework ( Binder ). The standard System V IPC framework is not supported by this operating system; in particular, the Bionic libc lacks the header files <sys / ipc.h>, <sys / sem.h>, <sys / shm.h>, <sys / msg.h >. In some specific cases (for example, to interact with the Zygote daemon), Unix domain sockets are used . All other methods of interaction between processes, including Intents, are implemented using Binder IPC. This framework allows you to call remote object methods synchronously and asynchronously as if they were local, exchange file descriptors between processes, link to death (automatically notify if the Binder of a specific process was interrupted), etc.


How does binder ipc work?


The interaction between processes is organized according to a synchronous client-server model. The client initiates the connection and waits for a response from the server. Thus, the interaction between the client and the server occurs sequentially. This design allows the developer to call remote methods as if they were in the same process. It should be noted that this does not disagree with what I wrote above about the asynchronous method call: in the case of an asynchronous call, the server immediately returns an empty response to the client. The diagram of the interaction of processes through Binder is presented in the following figure: an application (client) that runs in Process A gains access to the functionality implemented in the service that runs in Process B.



All interactions between the client and the server within Binder occur through the special Linux device driver (device driver) / dev / binder . In the article "Fundamentals of security of the Android operating system. Native user space, part 1 ” we looked at the system boot process. One of the first daemons launched by the init process is ueventd, an external device manager on Android. This service reads the ueventd.rc configuration file during start and plays back events of adding external devices. These events expose permissions for devices (permissions), as well as the owner (owner) and group (owning group). In the following example, you can see which permissions are set for / dev / binder .

... /dev/ashmem 0666 root root /dev/binder 0666 root root ... 


As you can see, the permissions for this device are set to 0666. This means that any user of the system (and we remember that different applications on Android are unique users) has the right to write to and read from this device. To interact with this driver library libbinder was created. This library allows you to make the process of interaction with the driver transparent to the application developer. In particular, the interaction between the client and the server occurs through a proxy (proxy) on the client side and a stub on the server side (see figure above). Proxies and Stubs are responsible for marshaling data and commands transmitted through the driver. Those. Proxy builds (marshalling) the data and commands received from the client in such a way that they can be correctly read (unmarshalling) and clearly understood by Stub. In general, application developers do not even write Stubs and Proxy for their applications. Instead, they use the interface described by the AIDL language. During the compilation of the application, based on this interface, the code for the Stubs and Proxy is generated (you can search in your projects to see how they look).

On the server side, a separate binder stream is created for each client request (see figure above). Typically, these threads are called Binder Thread #n. By the way, if memory serves me, then the maximum number of Binder threads is 255, and the maximum amount of data that can be transferred through Binder in a single transaction is 1Mb. This should be borne in mind when developing applications that transmit or receive data from other processes.


Service Manager


Attentive readers should have noted for themselves the fact that before that I had not written anything about how Android understands which process you need to send data. Technically, each Binder service assigns a 32-bit token, which is unique in all processes of the system (what the driver is monitoring). This token is used as a pointer to the service. If the client has this pointer, then it can interact with the service. But first, the client needs to get this unique value.

To do this, the client refers to the Binder context manager , which in the case of Android is called Service Manager (servicemanager). Service Manager is a special service whose Binder token is known to everyone in advance. It is not surprising that the value of the token for this service is 0. The binder driver allows registration of only one service with such a token, therefore the servicemanager is one of the first services launched in the system. Service Manager can be presented in the form of a directory. You say that you want to find a service with such a name, and you are returned in response to its unique token number, which you can use later to interact with the desired service. Naturally, the service must first register in this "directory".


Security


By itself, the Binder framework is not responsible for security in the system, but it provides mechanisms for its maintenance. First, the binder driver writes the PID and UID of the process that initiates the transaction to each transaction. The called service can use this information to decide whether to fulfill the request or not. You can get this information using the methods android.os.Binder.getCallingUid () , android.os.Binder.getCallingPid () . Secondly, since the Binder token is unique within the system and its value is not known a priori, it can itself be used as a security token (see, for example, this article ).



Conclusion


In the next part I plan to write about permissions (permissions). The material is already there, but you need to translate it and earn some money. As always I will be grateful for interesting questions and explanations in the comments, maybe I misunderstood some moments for myself.


Links


  1. Deep Dive Into Binder Framework by Aleksandar Gargenta
  2. "Embedded Android" by Karim Yaghmour
  3. “Android Binder. Android Interprocess Communication » by Thorsten Schreiber

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


All Articles