Пользователь
0,0
рейтинг
7 апреля 2013 в 23:38

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

Вступление


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


Disclaimer

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

Список статей

Здесь собраны ссылки на мои статьи из этой темы:
  1. Основы безопасности операционной системы Android. Уровень ядра
  2. Основы безопасности операционной системы Android. Native user space, ч.1
  3. Основы безопасности операционной системы Android. Native user space, ч.2
  4. Основы безопасности операционной системы Android. Безопасность на уровне Application Framework. Binder IPC




Стек 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 устройство. Существует несколько способов установить приложение на устройство (в общем случае):
  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() или Context.getDir() У этой папки права доступа определены как drwxr-x--x, т.е. только владелец и пользователи входящие в группу владельцев имеют полный доступ к этой папке. А так как каждое приложение определено как уникальный пользователь, то это означает, что приложения, по умолчанию, не имеют доступа к информации друг друга. Хотя при создании файла во внутреннем хранилище можно явно задать, что этот файл будет MODE_WORLD_READABLE и/или MODE_WORLD_WRITABLE

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

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

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

<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 в массиве структур 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. Если нет, то приложению запрещается доступ. Код этой проверки очень тривиальный:

...
#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» by Karim Yaghmour
  2. «Android Security Underpinnings» by Marko Gargenta
  3. «Understanding Android Security» by William Enck et al.
  4. Android Security Overview
Юрий @zyrik
карма
40,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (19)

  • НЛО прилетело и опубликовало эту надпись здесь
  • +3
    Радует тенденция появления постов про низкоуровневое программирование под Андроид. Пишите еще, интересно.
    • 0
      Ну, это скорее программирование не под Андроид, а программирование Андроида :)
  • +9
    Если приложения имеют

    У вас, кажется, кусок текста потерялся
    • 0
      Да, точно! Вроде и перечитывал перед опубликованием, но глаз замылился видно! Спасибо! А так же тем, кто написал про это в личку!
  • 0
    Написано очень легким и доступным языком.
    Я никогда не сталкивался с разработкой под андроид, но я понял всё! Продолжайте :)
  • +1
    Обязательно продолжайте, очень интересно и доступно для понимания.
  • 0
    Хорошая статья. Спасибо. Продолжения приветствуются.
  • +2
    У этой папки права доступа определены как drwxrwx--x, т.е. только владелец и пользователи входящие в группу владельцев имеют полный доступ к этой папке.

    Полный то да — имеет только владелец и группа, да вот только --x позволяет получать доступ к файлам на чтение и запись (если права файла позволяют, конечно), если известно имя файла. Т.е. другое приложение прочесть содержимое папки не сможет (нет r), но прочесть пароли из файла с известным именем внутри этой папки, если на нем стоят права rw-rw-r--) — легко.
    • 0
      После Вашего комментария решил проверить на своем эмуляторе. У папки /data/data права доступа drwxrwx--r, у папки конкретного приложения /data/data/<package_name> права доступа drwxr-x--x (подправил в статье), а вот у конкретных файлов, например, у файла базы данных или файла shared preferences права доступа -rw-rw---, т.е. к конкретному файла другие приложения доступа не имеют.
      Насколько я знаю Linux DAC для файлов должен выставлять разрешения такие же как и для родительского файла. Поэтому надо проверить, где они меняются на более жесткие.
      Спасибо!
      • +1
        Насколько я знаю Linux DAC для файлов должен выставлять разрешения такие же как и для родительского файла.

        Не совсем так, есть такая штука как umask, скорее всего для андроида по умолчанию стоит 027 (что-то не вижу в инете информации по этому вопросу, а эмулятора у меня нет) — поэтому для всех новых файлов и папок права для other будут нулевые (если действительно в umask последняя восьмеричная цифра — 7).

        Вообще, идея с уникальными uid-ами для каждого приложения — самая здравая для телефонного применения, можно очень тонко все настраивать. Даже спокойнее немного стало за свои данные в мобилке, все-таки в кармане куча личной информации носится, и хочется знать что никто без твоего спросу её не получит…

        Хотелось бы услышать Ваше мнение (а точнее — прочитать статью) — что надо дополнительно сделать на стоковом андроиде чтобы обезопасить свой телефон и свои данные. В частности — где найти более подробную информацию о системных пермишнах (типа GET ACCOUNTS) и как их попроще ограничивать (permission manager сейчас может управлять пермишнами только через переустановку приложения, что не очень удобно).
        • +1
          У меня есть небольшая проблема, с Linux я больше на Вы, хотя у меня на лэптопе стоит эта система ) Поэтому некоторые вещи, вполне возможно, что могу не знать. Если будет время, то я посмотрю исходники и постараюсь найти, где и как выставляются пермишенны на файлы. Спасибо за наводку!

          В частности — где найти более подробную информацию о системных пермишнах (типа GET ACCOUNTS) и как их попроще ограничивать (permission manager сейчас может управлять пермишнами только через переустановку приложения, что не очень удобно).

          Я планирую в следующей статье написать про системные разрешения, где и как их найти. Проблема в том, что в голове крутиться очень много не структурированной информации, которую надо как-то структурировать и написать так, чтобы было понятно обычному читателю. Когда я начинал с этим всем разбираться не было никакой информации о том, как это всё работает, приходилось её собирать по-крупицам, плюс, конечно, исходный код.
          Даже спокойнее немного стало за свои данные в мобилке, все-таки в кармане куча личной информации носится, и хочется знать что никто без твоего спросу её не получит…

          А вот здесь — не всё так просто :) Честно говоря, я очень сильно беспокоюсь за свои данные, ведь мобильник — это просто кладезь информации о пользователе и очень лакомный кусочек для разных нехороших личностей. Могу попробовать эти мысли тоже оформить в статью, если интересно )
  • 0
    Очень интересно. Пожалуйста, продолжайте писать.
  • –3
    Статья очень интересная.
    Но вот режет глаз прямо
    >Linux kernel
    >kernel
    А есть еще Linux что-то !?
    • 0
      Я не совсем понимаю Ваш вопрос.
      • 0
        Ну как бы Linux — опенсорсное монолитное ядро с поддержкой подгружаемых модулей. Linux kernel — ядро ядро? Тавтология из разряда SEO оптимизация/ сервисное обслуживание и т.п
  • –1
    Мой пост о том, как выкачать исходники Android под виндой тут — habrahabr.ru/post/130892/

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.