Security basics of the Android operating system. Native user space, part 1
Introduction
In this article I will try to consider security a little higher than the kernel, namely: how security works in Native user space. We will cover the theme of the operating system boot process and consider the structure of the Android file system. As I said, I'm not very strong on Linux, so if you notice inaccuracies, then fix it - teach me and improve the article. Since this topic is quite extensive, I decided to break it into two parts. In the first part we will consider the process of loading the operating system and the features of the file system. Everyone who is interested, welcome!
List of Articles
Here are links to my articles from this topic:- Security basics of the Android operating system. Core level
- Security basics of the Android operating system. Native user space, part 1
- Security basics of the Android operating system. Native user space, part 2
- Security basics of the Android operating system. Security at the Application Framework level. Binder IPC
What is meant by native user space
Native user space refers to all user space components that run outside the Dalvik Virtual Machine and which are not part of the Linux kernel.Android file system
First, let's look at the structure of the Android file system. Although Android is based on the Linux kernel, we will not see the file system structure familiar to our eyes here. Let's run the emulator and see what we have. To do this, run the command:
adb shell ls -al
In my terminal for an emulator on Android 4.2, I see the following result:
drwxr-xr-x root root 2013-04-10 08:13 acct
drwxrwx--- system cache 2013-04-10 08:13 cache
dr-x------ root root 2013-04-10 08:13 config
lrwxrwxrwx root root 2013-04-10 08:13 d -> /sys/kernel/debug
drwxrwx--x system system 2013-04-10 08:14 data
-rw-r--r-- root root 116 1970-01-01 00:00 default.prop
drwxr-xr-x root root 2013-04-10 08:13 dev
lrwxrwxrwx root root 2013-04-10 08:13 etc -> /system/etc
-rwxr-x--- root root 244536 1970-01-01 00:00 init
-rwxr-x--- root root 2487 1970-01-01 00:00 init.goldfish.rc
-rwxr-x--- root root 18247 1970-01-01 00:00 init.rc
-rwxr-x--- root root 1795 1970-01-01 00:00 init.trace.rc
-rwxr-x--- root root 3915 1970-01-01 00:00 init.usb.rc
drwxrwxr-x root system 2013-04-10 08:13 mnt
dr-xr-xr-x root root 2013-04-10 08:13 proc
drwx------ root root 2012-11-15 05:31 root
drwxr-x--- root root 1970-01-01 00:00 sbin
lrwxrwxrwx root root 2013-04-10 08:13 sdcard -> /mnt/sdcard
d---r-x--- root sdcard_r 2013-04-10 08:13 storage
drwxr-xr-x root root 2013-04-10 08:13 sys
drwxr-xr-x root root 2012-12-31 03:20 system
-rw-r--r-- root root 272 1970-01-01 00:00 ueventd.goldfish.rc
-rw-r--r-- root root 4024 1970-01-01 00:00 ueventd.rc
lrwxrwxrwx root root 2013-04-10 08:13 vendor -> /system/vendor
I will mark here only the main directories and those that will be useful to us in the future. On the Internet you can find a description and the purpose of other directories. You may notice that some directories are the same as on Linux, for example, / dev , / proc , / sys , / mnt , / etc, and their purpose is basically the same as on Linux. By the way, note that we do not see the / bin and / lib directories. Where they hid, I will tell a little later.
On the other hand, you will notice directories that Linux does not have at all. Among them, we are interested in / data , / system , / cache , / init ,/init.rc Let's look at their purpose in more detail.
/ system This is the main directory where the immutable components of the Android system are stored. If we draw an analogy, then this folder is similar to the read-only C: \ windows \ folder . Those. we cannot change the data in this directory. This is where you can find the / bin and / lib directories where various executables and shared libraries are stored. In addition, there are also system applications that are built into the operating system and which, by default, cannot be deleted. The contents of this directory are generated during compilation of the operating system.
/ data Because / systemIf we have read-only access, then there should be a directory where mutable data is stored. / data is just that. For example, apk files of installed applications are stored in this directory in / data / app , and their data is stored in / data / data (we examined this directory in detail in the previous article).
/ cache This is just temporary storage. Also, this directory is saved, and then system updates are launched from it.
To understand what an / init file is and why we need obscure files with the * .rc extension, consider the system boot process.
Android boot process

Let's look at a few steps in the process of loading the Android operating system. This picture is taken from the book "Embedded Android", there you can find a more detailed description. Although in general I understand the process, but for me it is more magic :)
CPU. When you press the power button, voltage starts to be applied to the processor of your device. Since until this moment the processor was turned off, and since it is not able to maintain its state without applying voltage, then immediately after the start it is in some uninitialized state. In this case, the processor reads some hard-wired address from its special register and starts to execute instructions starting from it. Most often, this address points to the chip in which the bootloader (bootloader) is wired.
Bootloader.Bootloader initializes the RAM and loads the Linux kernel into it. In addition, Bootloader creates a RAMdisk.
Linux kernel. The kernel initializes various subsystems, built-in drivers and mounts root filesystem (root file system). After that, the kernel can run the first program.
This ends the magic and then everything becomes more or less clear.
Init
The first program in the case of Android is init . The executable file is located in the root directory ( / init ). It is this program that the kernel starts after it boots. Its sources are located in the system / core / init / folder . Let's dig into them a little. We are interested in system / core / init / init.c :
...
int main(int argc, char **argv)
{
...
/* clear the umask */
umask(0);
/* Get the basic filesystem setup we need put
* together in the initramdisk on / and then we will
* let the rc file figure out the rest.
*/
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
...
init_parse_config_file("/init.rc");
...
}
At first, we create and install some necessary for the directory, and then parse the file /init.rc and do what parsed. The format of the /init.rc file is very well described in readme , where you can also find an example. In short, this file is a set of actions (sections - a named sequence of commands). Each sequence of commands is triggered by a specific trigger (trigger). For example, the following in sequence is action, in which trigger is fs, and the sequence of commands is a set of mount commands:
on fs
# mount mtd partitions
# Mount /system rw first to give the filesystem a chance to save a checkpoint
mount yaffs2 mtd@system /system
mount yaffs2 mtd@system /system ro remount
mount yaffs2 mtd@userdata /data nosuid nodev
mount yaffs2 mtd@cache /cache nosuid nodev
The source file /init.rc is located in system / core / rootdir / init.rc. Let's look at some of its main parts, although I highly recommend that you look at its fullness. After that, many things should become clear to you. So, our file begins with the following lines:
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.trace.rc
They mean that in addition to the init.rc file, you also need to import the settings from the init.usb.rc , init.trace.rc files and from the file with the strange name init. $ {Ro.hardware} .rc However, $ {ro.hardware} Is just a variable whose value determines the type of iron. In the case of an emulator, its value, for example, is goldfish . Next, environment variables are defined:
...
on init
...
# setup the global environment
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /vendor/lib:/system/lib
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
export ANDROID_STORAGE /storage
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH /system/framework/core.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
...
After this, the variables necessary for the operation of the device are initialized. If you are interested in this topic, then you can easily find information about a particular command. Let's take a closer look at the following block (which I already cited in this article):
on fs
# mount mtd partitions
# Mount /system rw first to give the filesystem a chance to save a checkpoint
mount yaffs2 mtd@system /system
mount yaffs2 mtd@system /system ro remount
mount yaffs2 mtd@userdata /data nosuid nodev
mount yaffs2 mtd@cache /cache nosuid nodev
MTD - Memory Technology Devices. In general terms, MTD is a special chip with non-volatile (i.e., data on this chip is saved after a reboot or shutdown) with flash memory (such as NOR or NAND), on which disk images are saved. In thisThe article talks in more detail about this type of device, as well as limitations. Specifically for these varieties of flash-memory special file systems were developed, for example, YAFFS. One of the most important limitations of these types of memory is that in order to write data to a sector where some data has already been written, you must completely erase the entire sector first. Therefore, manufacturers began to switch to a new type of block flash memory (eMMC), on which you can put a regular ext4 file system and get rid of this limitation. Because I am showing an init.rc examplefile for the emulator, where all the work is emulated, then it uses the YAFFS2 file system by default (I think that these are relics of the past, because YAFFS2 was used for all devices up to Android 2.2). In a real device (this is just one example when you need to use the init.rc file for a specific hardware), these commands will be overwritten. For example, in the case of a herring device (Google Nexus S), in the init.herring.rc file , this section looks like this:
on fs
mkdir /efs 0775 radio radio
mount yaffs2 mtd@efs /efs noatime nosuid nodev
chmod 770 /efs/bluetooth
chmod 770 /efs/imei
mount_all /fstab.herring
...
Where fstab.herring is a file whose contents are as follows:
...
/dev/block/platform/s3c-sdhci.0/by-name/system /system ext4 ro wait
/dev/block/platform/s3c-sdhci.0/by-name/userdata /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,encryptable=/efs/userdata_footer
As you may have noticed, / system , / data , / cache are simply mounting points (mount points of the file system) that indicate either MTD devices (in the case of an emulator) or block devices (in the case of a real device) where corresponding disk images (system.img, userdata.img and cache.img). I'm not sure, but I think that inside the smartphone there is one single chip with flash-memory, divided into partitions (volumes), each of which contains the corresponding image. This flash memory chip is what we know by the name Internal storage , the volume of which is one of the main parameters of a smartphone.
It should be noted that / systemmounted read-only (read-only). This means that the contents of this section does not change during the operation of the device, but only when you, for example, update the system on your device (using system updates).
We continue to look at our init.rc . The post-fs-data trigger generates the basic structure of the / data partition file system . There, in general, everything is clear - a set of mkdir , chown , chmod commands.
Next init.rclaunches several demons. If you return to the figure at the beginning of the article, they are listed in the Native daemons block. We will stop here for now. As you can see from the figure, I did not fully consider the process of loading the operating system. Some uncovered steps I will consider in the following article.
Conclusion
In the next part I will tell you where the images system.img, userdata.img and cache.img come from and consider security at the Native user space level. As always, corrections, additions, as well as suggestions about what to write are welcome. And although I already have some plan about what to write in the next article, I am ready to correct it.
References
- Working with MTD Devices
- "Embedded Android" by Karim Yaghmour
- Android Security Underpinnings by Marko Gargenta
Update