- PVSM.RU - https://www.pvsm.ru -

Основы безопасности операционной системы Android. Уровень ядра

Вступление

Самой распространенной операционной системой для смартфонов на сегодняшний день является Android. Но не только этот факт подогревает интерес к ней. Открытость, возможность что-то настроить, подкрутить, и, естественно, сломать тоже в немалой степени способствуют увеличению популярности этой платформы. Я попробую поделиться опытом, как устроена эта операционная система, а так же рассмотреть систему безопасности. Всем, кому интересно, добро пожаловать! В этой статье я рассмотрю безопасность на уровне ядра.

Disclaimer

Термины я буду стараться писать на английком языке, так как боюсь ошибиться в их переводе. Если кто-то знает, как их красиво перевести на русский язык, напишите мне, и я дам перевод этих терминов. Желательно, чтобы у вас под рукой находились исходный код Android (хотя я и буду стараться давать ссылки на файлы в Интернете), потому что я иногда буду давать ссылки на файлы, где находится та или иная функциональность. Как загрузить исходный код, можно почитать здесь [1] или вот в этой [2] статье на Хабре.

Стек Android

Основы безопасности операционной системы Android. Уровень ядра
Ну никуда не деться от этой картинки. Я нашел её на просторах Интернета и нужна она для того, чтобы понять из чего состоит Android. Итак, в стеке Android выделяют четыре уровня (снизу-вверх):

  1. Linux kernel (Ядро Linux)
  2. Native Libraries
  3. Application Framework
  4. Applications (Приложения)

Linux kernel. Как неудивительно это звучит, но изначально, Android Inc. — это стартап. Как и во всех стартапах, в этой компании стояла задача максимально использовать уже существующие решения. Поэтому в качестве ядра этой платформы был выбран Linux из-за его открытости и наличия необходимой функциональности. В Android ядро Linux управляет памятью, процессами, а так же используется в качестве hardware abstraction layer (HAL). Насколько мне известно, в Linux драйвера либо встроены в ядро, либо разработаны в виде загружаемых модулей ядра. Так как в Android загрузка модулей ядра по умолчанию отключена, а если встраивать все драйвера, то ядро очень сильно разрастется, то было принято решение создать промежуточный слой (proxy) между ядром и драйверами, который и назвали HAL. Таким образом, HAL — это просто набор интерфейсов, имплементация которых реализована в драйверах. С другой стороны в ядро были добавлены некоторые системы, которые характерны только для Android систем. На данный момент, они пока не включены в основную ветку ядра Linux, поэтому просто скачать ядро Linux и заменить им ядро Android не получится. Среди них следует выделить, Binder (обеспечивает межпроцессное взаимодействие IPC/RPC), Asynchronous SHared MEMory — Ashmem (драйвер разделяемой памяти), Wakelocks (механизм, который позволяет предотвращать затемнение экрана и/или отключение процессора), Low Memory Killer, Alarm, Logger и т.д.

Native Libraries. К этому слою относятся различные нативные библиотеки, которые необходимы для работы Android. Они так же позаимствованы у open-source сообщества. Среди них мы можем найти SQLite, WebKit и т.д.

Android Framework. К этому слою относится то, с чем мы обычно взаимодействуем, когда пишем наши приложения для Android (PowerManager, ActivityManager, NotificationManager и т.д.).

Applications. Приложения бывают двух типов: те, что поставляются вместе с образом системы (системные) и приложения, которые мы загружаем из маркета или других источников. В первом случае, в устройстве приложения находятся в "/system/app" директории, во втором случае в "/data/app".

Безопасность на уровне ядра

Давайте рассмотрим процесс установки приложения на Android устройство.
Основы безопасности операционной системы Android. Уровень ядра
Существует несколько способов установить приложение на устройство (в общем случае):

  1. Используя приложение PackageInstaller
  2. Используя приложение Android Market
  3. Используя комманду adb install

На рисунке, например, приложение ex1.apk устанавливается с помощью PackageInstaller (используется в случае, если вам, например, по почте прислали приложение и вы хотите его установить с устройства), ex2.apk устанавливается с помощью Android Market (Google Play), и приложение ex3.apk устанавливается с помощью комманды adb install ex3.apk (обычно эта комманда используется разработчиками приложений для установки приложения с компьютера).

Во время установки, Android каждому приложению по умолчанию присваивает уникальные user ID (UID) и group ID (GID), таким образом каждому приложению в этой операционной системе соответсвует свой пользователь. Имя пользователя обычно имеет формат app_x, а идентификаторы пользователя вычисляется по формуле (Process.FIRST_APPLICATION_UID + x), Process.FIRST_APPLICATION_UID равен 10000. Эти идентификаторы приложения не изменяются. Список установленных приложений хранится в файле "/data/system/packages.list" и если у вас рутованый телефон, или вы работаете с эмулятором, то вы можете просмотреть этот файл, используя следующую комманду:

adb shell cat /data/system/packages.list

У каждого приложения есть своя домашняя директория, например /data/data/<package_name>, где <package_name> — имя Android пакета, например com.ex.ex1 Имя Android пакета задается в свойстве package в файле AndroidManifest.xml Эта папка — Internal storage (внутреннее хранилище), директория, где приложение хранит все свои приватные данные, и к которому разработчики приложений получают доступ используя функции Context.getFilesDir() [3] или Context.getDir() [4] У этой папки права доступа определены как drwxrwx--x, т.е. только владелец и пользователи входящие в группу владельцев имеют полный доступ к этой папке. А так как каждое приложение определено как уникальный пользователь, то это означает, что приложения, по умолчанию, не имеют доступа к информации друг друга. Хотя при создании файла во внутреннем хранилище можно явно задать, что этот файл будет MODE_WORLD_READABLE [5] и/или MODE_WORLD_WRITABLE [6]

Кроме того, на уровне ядра уникальные UID и GID каждого приложения используются для разделения доступа к ресурсам системы (память и процессорное время). Таким образом, на уровне ядра для каждого приложения создается своя собственная песочница (Application Sandbox).

С другой стороны, разработчик приложения может указать некоторые ЕГО приложения должны иметь один и тот же UID. В AndroidManifest.xml файле для этого есть специальное свойство sharedUserId [7] В этом случае, эти приложения будут иметь доступ к ресурсам друг-друга, но только если они подписаны одним и тем же ключом разработчика. Если приложения имеют

Некоторые permission (разрешения) так же работают на уровне ядра. Давайте, например, рассмотрим наиболее используемое разрешение android.permission.INTERNET [8] Если приложение запрашивает это разрешение, то Android во время установки дополнительно включает это приложение в специальную группу «inet». Так же работают и некоторые другие разрешения. Список соответствия между этими разрешениями и соответствующими группами можно найти в файле frameworks/base/data/etc/platform.xml [9]:

<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>

Список соответствия между именами этих групп и значениями (GID) задан в явном виде в файле system/core/include/private/android_filesystem_config.h [10] в массиве структур 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, },
    ...
}
...

Таким образом, если приложение пытается подключиться к Интернету, ядро проверяет, находится ли это приложение в группе с идентификатором AID_INET. Если нет, то приложению запрещается доступ. Код этой проверки очень тривиальный [11]:

...
#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;
    ...
}

Заключение

Это моя первая статья на Хабре, так что не судите строго. Если сообществу интересно, то я продолжу в следующих статьях описывать внутренности Android. Я понимаю, что много не знаю, да и времени всегда не хватает, но я постараюсь поделиться тем, что уже пропустил через себя. Надеюсь, что узнаю что-то новое из комментариев! Если кому-то интересна какая-то определенная тема, то пишите в комментариях, постараюсь в будущих статьях учесть ваши пожелания.

Ссылки

  1. «Embedded Android» [12] by Karim Yaghmour
  2. «Android Security Underpinnings» [13] by Marko Gargenta
  3. «Understanding Android Security» [14] by William Enck et al.
  4. Android Security Overview [15]

Автор: zyrik

Источник [16]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/android/31442

Ссылки в тексте:

[1] здесь: http://source.android.com/source/index.html

[2] этой: http://habrahabr.ru/company/intel/blog/153521/

[3] Context.getFilesDir(): http://developer.android.com/reference/android/content/Context.html#getFilesDir()

[4] Context.getDir(): http://developer.android.com/reference/android/content/Context.html#getDir(java.lang.String, int)

[5] MODE_WORLD_READABLE: http://developer.android.com/reference/android/content/Context.html#MODE_WORLD_READABLE

[6] MODE_WORLD_WRITABLE: http://developer.android.com/reference/android/content/Context.html#MODE_WORLD_WRITEABLE

[7] sharedUserId: http://developer.android.com/guide/topics/manifest/manifest-element.html#uid

[8] android.permission.INTERNET: http://developer.android.com/reference/android/Manifest.permission.html#INTERNET

[9] frameworks/base/data/etc/platform.xml: https://android.googlesource.com/platform/frameworks/base//+/master/data/etc/platform.xml

[10] system/core/include/private/android_filesystem_config.h: https://android.googlesource.com/platform/system/core//+/master/include/private/android_filesystem_config.h

[11] тривиальный: https://android.googlesource.com/kernel/common.git//+/android-3.4/net/ipv4/af_inet.c

[12] «Embedded Android»: http://shop.oreilly.com/product/0636920021094.do

[13] «Android Security Underpinnings»: https://marakana.com/s/post/1393/slides.htm

[14] «Understanding Android Security»: http://css.csail.mit.edu/6.858/2012/readings/android.pdf

[15] Android Security Overview: http://source.android.com/tech/security/index.html

[16] Источник: http://habrahabr.ru/post/175517/