The Kernel

Although Android’s foundation, the Linux kernel, is fairly well documented and understood, there are some notable differences between the vanilla Linux kernel and that which is used by Android. This section explains some of those changes, especially those which are pertinent to Android security.

The Android Fork 

Early on, Google created an Android-centric fork of the Linux kernel, as many modifi cations and additions weren’t compatible with the Linux kernel mainline tree. Overall, this includes approximately 250 patches, ranging from fi le system support and networking tweaks to process and memory management facilities. According to one kernel engineer, most of these patches “represent[ed] a limitation that the Android developers found in the Linux kernel.” In March 2012, the Linux kernel maintainers merged the Android-specifi c kernel modifi cations into the mainline tree. Table 2-3 highlights some of the additions/ changes to the mainline kernel. We discuss several of these in more detail later in this section.


Table 2-3: Android’s major changes to Linux kernel

 KERNEL CHANGE DESCRIPTION

 Binder (IPC mechanism with additional features such as security validation of callers/callees; used by numerous system and framework services)

ashmem (Anonymous Shared Memory; fi le-based shared memory allocator; uses Binder IPC to allow processes to identify memory region fi le descriptors)

pmem (Process Memory Allocator; used for managing large, contiguous regions of shared memory)

logger (System-wide logging facility)

RAM_CONSOLE (Stores kernel log messages in RAM for viewing after a kernel panic)

“oom” modifi cations (“Out of memory”-killer kills processes as memory runs low; in Android fork, OOM kills processes sooner than vanilla kernel, as memory is being depleted) 

wakelocks (Power management feature to keep a device from entering low-power state, and staying responsive)

Alarm Timers (Kernel interface for AlarmManager, to instruct kernel to schedule “waking up”)

Paranoid Networking (Restricts certain networking operations and features to specifi c group IDs)

timed output / gpio (Allows user-space programs to change and restore GPIO registers after a period of time) 

yaff (s2 Support for the yaff s2 fl ash fi le system)

Binder

Perhaps one of the most important additions to Android’s Linux kernel was a driver known as Binder. Binder is an IPC mechanism based on a modifi ed version of OpenBinder, originally developed by Be, Inc., and later Palm, Inc. Android’s Binder is relatively small (approximately 4,000 lines of source code across two fi les), but is pivotal to much of Android’s functionality. In a nutshell, the Binder kernel driver facilitates the overall Binder architecture. The Binder—as an architecture—operates in a client-server model. It allows a process to invoke methods in “remote” processes synchronously. The Binder architecture abstracts away underlying details, making such method calls seem as though they were local function calls. Figure 2-3 shows Binder’s communication fl ow.

Process A Proxy

Binder Driver

Process B with Threads

Figure 2-3:  Binder communication

Binder also uses process ID (PID) and UID information as a means of identifying the calling process, allowing the callee to make decisions about access control. This typically occurs through calls to methods like Binder .getCallingUid and Binder.getCallingPid, or through higher-level checks such as checkCallingPermission. An example of this in practice would be the ACCESS_SURFACE_FLINGER permission. This permission is typically granted only to the graphics system user, and allows access to the Binder IPC interface of the Surface Flinger graphics service. Furthermore, the caller’s group membership—and subsequent bearing of the required permission—is checked through a series of calls to the aforementioned functions, as illustrated by the following code snippet:

                 const int pid = ipc->getCallingPid();  

                 const int uid = ipc->getCallingUid(); 

                       if ((uid != AID_GRAPHICS) && 

                           !PermissionCache::checkPermission(sReadFramebuffer,                 

                               pid, uid)) { 

                      ALOGE("Permission Denial: "

                                "can't read framebuffer pid=%d, uid=%d", pid, uid); 

                      return PERMISSION_DENIED;

}

At a higher level, exposed IPC methods, such as those provided by bound Services, are typically distilled into an abstract interface via Android Interface Defi nition Language (AIDL). AIDL allows for two applications to use “agreed-upon” or standard interfaces for sending and receiving data, keeping the interface separate from the implementation. AIDL is akin to other Interface Defi nition Language fi les or, in a way, C/C++ header fi les. Consider the following sample AIDL snippet:

// IRemoteService.aidl 

package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */ 

interface IRemoteService {

 /** Request the process ID of this service,    

 to do evil things with it. */    

int getPid();

  /** Demonstrates some basic types that you can use as parameters     

* and return values in AIDL.    

 */ 

 void basicTypes(int anInt, long aLong, boolean aBoolean, 

                float aFloat,

               double aDouble, String aString); 

}

This AIDL example defi nes a simple interface, IRemoteService, along with two methods: getPid and basicTypes. An application that binds to the service exposing this interface would subsequently be able to call the aforementioned methods—facilitated by Binder.

ashmem

Anonymous Shared Memory, or ashmem for short, was another addition to the Android Linux kernel fork. The ashmem driver basically provides a fi le-based, reference-counted shared memory interface. Its use is prevalent across much of Android’s core components, such as Surface Flinger, Audio Flinger, System Server, and the DalvikVM. Because ashmem is designed to automatically shrink memory caches and reclaim memory regions when available system-wide memory is low, it is well suited for low-memory environments. At a low level, using ashmem is as simple as calling ashmem_create_region, and using mmap on the returned fi le descriptor:

      int fd = ashmem_create_region("SomeAshmem", size); 

      if(fd == 0) { 

      data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

      ...

At a higher level, the Android Framework provides the MemoryFile class, which serves as a wrapper around the ashmem driver. Furthermore, processes can use the Binder facility to later share these memory objects, leveraging the security features of Binder to restrict access. Incidentally, ashmem proved to be the source of a pretty serious fl aw in early 2011, allowing for a privilege escalation via Android properties. This is covered in greater detail in Chapter 3.

pmem

Another Android-specifi c custom driver is pmem, which manages large, physically contiguous memory ranging between 1 megabyte (MB) and 16MB (or more, depending on the implementation). These regions are special, in that they are shared between user-space processes and other kernel drivers (such as GPU drivers). Unlike ashmem, the pmem driver requires the allocating process to hold a fi le descriptor to the pmem memory heap until all other references are closed.

Logger

Though Android’s kernel still maintains its own Linux-based kernel-logging mechanism, it also uses another logging subsystem, colloquially referred to as the logger. This driver acts as the support for the logcat command, used to view log buffers. It provides four separate log buffers, depending on the type of information: main, radio, event, and system. Figure 2-4 shows the fl ow of log events and components that assist logger. The main buffer is often the most voluminous, and is the source for applicationrelated events. Applications typically call a method from the android.util.Log class, where the invoked method corresponds to the log entry priority level—for example, the Log.i method for “informational,” Log.d for “debug,” or Log.e for “error” level logs (much like syslog).


Native program

Java program

android.util.Log

liblogstdout /stderr

User Kernel

Host

ADT in Eclipse

adb logcat

main radio

systemevent

/dev/log/main /dev/log/radio /dev/log/event /dev/log/system

/dev/log/main /dev/log/radio /dev/log/event /dev/log/system

64KB

256KB

64KB

com.android.internal.os AndroidPrintstream

64KB

logger

Target

System.out /System.err

logcat

adbd

stdout

adbserver

Overview of Android Logging System

Figure 2-4:  Android logging system architecture

The system buffer is also a source of much information, namely for system-wide events generated by system processes. These processes utilize the println_native method in the android.util.Slog class. This method in turn calls native code specifi c to logging to this particular buffer. Log messages can be retrieved using the logcat command, with both the main and system buffers being the default sources. In the following code, we run adb -d logcat to see what is happening on the attached device:

$ adb -d logcat 

--------- beginning of /dev/log/system

D/MobileDataStateTracker( 1600): null: Broadcast received:

 ACTION_ANY_DATA_CONNECTION_STATE_CHANGEDmApnType=null != received

apnType=internet 

D/MobileDataStateTracker( 1600): null: Broadcast received: 

ACTION_ANY_DATA_CONNECTION_STATE_CHANGEDmApnType=null != received

apnType=internet 

D/MobileDataStateTracker( 1600): httpproxy: Broadcast received: 

ACTION_ANY_DATA_CONNECTION_STATE_CHANGEDmApnType=httpproxy != received 

apnType=internet 

D/MobileDataStateTracker( 1600): null: Broadcast received: 

ACTION_ANY_DATA_CONNECTION_STATE_CHANGEDmApnType=null != received 

apnType=internet 

...

--------- beginning of /dev/log/main 

...

D/memalloc( 1743): /dev/pmem: Unmapping buffer base:0x5396a000 

size:12820480 offset:11284480

D/memalloc( 1743): /dev/pmem: Unmapping buffer base:0x532f8000 

size:1536000 offset:0 

D/memalloc( 1743): /dev/pmem: Unmapping buffer base:0x546e7000

size:3072000 offset:1536000 

D/libEGL  ( 4887): loaded /system/lib/egl/libGLESv1_CM_adreno200.so 

D/libEGL  ( 4887): loaded /system/lib/egl/libGLESv2_adreno200.so

I/Adreno200-EGLSUB( 4887): <ConfigWindowMatch:2078>: Format RGBA_8888. 

D/OpenGLRenderer( 4887): Enabling debug mode 0

V/chromium( 4887): external/chromium/net/host_resolver_helper/host_resolver_helper.cc:66: [0204/172737:INFO:host_resolver_helper.cc(66)] 

DNSPreResolver::Init got hostprovider:0x5281d220 

V/chromium( 4887): external/chromium/net/base/host_resolver_impl.cc:1515: 

[0204/172737:INFO:host_resolver_impl.cc(1515)] 

HostResolverImpl::SetPreresolver preresolver:0x013974d8

V/WebRequest( 4887): WebRequest::WebRequest, setPriority = 0

I/InputManagerService( 1600): [unbindCurrentClientLocked] Disable input method client. 

I/InputManagerService( 1600): [startInputLocked] Enable input method client. 

V/chromium( 4887): external/chromium/net/disk_cache/

hostres_plugin_bridge.cc:52: [0204/172737:INFO:hostres_

plugin_bridge.cc(52)] StatHubCreateHostResPlugin initializing...

The logcat command is so commonly executed that ADB actually provides a shortcut for running it on a target device. Throughout the course of the book, we make extensive use of the logcat command to monitor processes and overall system state.

Paranoid Networking 

The Android kernel restricts network operations based on supplementary group membership of the calling process—a kernel modifi cation known as Paranoid Networking. At a high level, this involves mapping an AID, and subsequently a GID, to an application-level permission declaration or request. For example, the manifest permission android.permission.INTERNET effectively maps to the AID_INET AID—or GID 3003. These groups, IDs, and their respective capabilities are defi ned in include/linux/android_aid.h in the kernel source tree, and are described in Table 2-4.

Table 2-4: Networking capabilities by group 

 AID DEFINITION GROUP ID / NAME CAPABILITY

AID_NET_BT_ADMIN 3001 / net_bt_admin

Allows for creation of any Bluetooth socket, as well as diagnoses and manages Bluetooth connections AID_NET_BT 3002 / net_bt Allows for creation of SCO, RFCOMM, or L2CAP (Bluetooth) sockets AID_INET 3003 / inet Allows for creation of AF_INET and AF_INET6 sockets AID_NET_RAW 3004 / net_raw Allows the use of RAW and PACKET sockets AID_NET_ADMIN 3005 / net_admin Grants the CAP_NET_ADMIN capability, allowing for network interface, routing table, and socket manipulation

You can fi nd additional Android-specifi c group IDs in the AOSP source repository in system/core/include/private/android_filesystem_config.h.

Complex Security, Complex Exploits

After taking a closer look at the design and architecture of Android, it is clear that the Android operating system developers created a very complex system. Their design allows them to adhere to the principle of least privilege, which states that any particular component should have access only to things that it absolutely requires. Throughout this book, you will see substantial evidence of the use of this principle. Although it serves to improve security, it also increases complexity.

Process isolation and privilege reduction are techniques that are often a cornerstone in secure system design. The complexities of these techniques complicate the system for both developers and attackers, which increase the cost of development for both parties. When an attacker is crafting his attack, he must take the time to fully understand the complexities involved. With a system like Android, exploiting a single vulnerability may not be enough to get full access to the system. Instead, the attacker may have to exploit several vulnerabilities to achieve the objective. To summarize, successfully attacking a complex system requires a complex exploit. A great real-world example of this concept is the “diaggetroot” exploit used to root the HTC J Butterfl y. To achieve root access, that exploit leveraged multiple, complementary issues. That particular exploit is discussed in further detail in Chapter 3.

Summary

 This chapter gave an overview of the security design and architecture of Android. We introduced the Android sandbox and the permissions models used by Android. This included Android’s special implementation of Unix UID/GID mappings (AIDs), as well as the restrictions and capabilities enforced throughout the system. We also covered the logical layers of Android, including applications, the Android Framework, the DalvikVM, user-space native code, and the Linux kernel. For each of these layers, we discussed key components, especially those that are security related. We highlighted important additions and modifi cations that the Android developers made to the Linux kernel. This fairly high-level coverage of Android’s overall design helps frame the remaining chapters, which dive even further into the components and layers introduced in this chapter. The next chapter explains the how and why of taking full control of your Android device. It discusses several generic methods for doing so as well as some past techniques that rely on specifi c vulnerabilities. 

androidhack
4
0 GOLOS
0
В избранное
mestn1k
На Golos с 2018 M05
4
0

Зарегистрируйтесь, чтобы проголосовать за пост или написать комментарий

Авторы получают вознаграждение, когда пользователи голосуют за их посты. Голосующие читатели также получают вознаграждение за свои голоса.

Зарегистрироваться
Комментарии (0)
Сортировать по:
Сначала старые