![](https://habrastorage.org/getpro/habr/post_images/12d/598/079/12d59807902a43d32a954bdcba45d25e.jpg)
На днях компания Google сделала важный шаг, объявив о включении языка программирования Rust в число языков, которые допускаются для разработки платформы Android. Да, еще в 2019 году компилятор Rust включили в дерево исходных текстов Android, но это была экспериментальная поддержка.
Сейчас в Android планируется добавить первые компоненты на Rust, это будут новые реализации механизма межпроцессного взаимодействия Binder и Bluetooth-стека. Все это хорошо, но зачем весь этот сыр-бор с включением Rust?
По словам представителей Google, Rust добавили в список языков разработки Android для усиления защищенности последнего, плюс для продвижения приемов безопасного программирования и повышения выявления проблем при работе с памятью в Android. Около 70% из всех опасных уязвимостей, которые выявлены в Android, вызваны ошибками при работе с памятью. Использование Rust дает возможность снизить риск появления уязвимостей, которые вызваны ошибками при работе с памятью, включая обращение к области памяти после ее освобождения и выход за границы буфера.
Безопасная работа с памятью обеспечивается в Rust во время компиляции посредством проверки ссылок, отслеживания владения объектами и учета времени жизни объектов (области видимости). Дополнительно — через оценку корректности доступа к памяти во время выполнения кода. Кроме того, Rust предоставляет средства защиты от целочисленных переполнений и требует обязательной инициализации значений переменных перед использованием. А еще он лучше обрабатывает ошибки в стандартной библиотеке и применяет концепцию неизменяемости (immutable) ссылок и переменных по умолчанию, предлагает сильную статическую типизацию для минимизации логических ошибок.
Что касается Android, то здесь безопасная работа с памятью обеспечивается в поддерживаемых языках Kotlin и Java. Правда, они не подходят для разработки системных компонентов из-за больших накладных расходов. Rust позволяет добиться увеличения производительности до близкой к языкам C и С++. А это значит, что язык можно использовать для разработки низкоуровневых частей платформы и компонентов для взаимодействия с оборудованием.
Безопасность кода на С и С++ в Android обеспечивается благодаря sandbox-изоляции, статическому анализу и fuzzing-тестированию. Возможности изоляции, правда, ограничены — они достигли предела возможностей. Эта ограниченность вызывает рост накладных расходов и увеличение объемов потребляемой памятью, что вызвано необходимостью порождения новых процессов. Плюс есть издержки, которые связаны с использованием IPC.
Sandbox не устраняет уязвимости в коде, все это работает иначе — снижаются риски и усложняется проведение атаки. К сожалению, для того чтобы бороться с проблемами максимально эффективно, нужно знать их все или подавляющую часть. А в ходе тестирования для выявления ошибок нужно создавать условия для их появления. Соответственно, абсолютно все условия предусмотреть невозможно, так что многие ошибки проходят мимо внимания разработчиков.
![](https://habrastorage.org/getpro/habr/post_images/66d/b34/d88/66db34d8872cc2aae7ab11688ba84b3c.png)
Компания Google использует так называемое «правило двух», в соответствии с которым для системных процессов любой добавляемый код должен подпадать не больше, чем под два условия из трех:
Работа с непроверенными входными данными.
Использование небезопасного языка программирования.
Выполнение процесса без жесткой sandbox-изоляции.
Соответственно, код для обработки внешних данных должен быть либо урезан до минимальных привилегий, либо написан на безопасном языке программирования.
![](https://habrastorage.org/getpro/habr/post_images/9c5/71f/3b0/9c571f3b079a669ba6d543767ab88da0.png)
Можно было бы подумать, что Google планирует переписать на Rust уже имеющийся C\C++ код, но нет — его будут использовать для разработки нового кода. В этом есть смысл, поскольку, согласно статистике разработки, большая часть ошибок появляется либо в новом, либо недавно модифицированном коде. Так, около 50% ошибок работы с памятью в Android OS выявляются как раз в коде, который написан менее года назад.
![](https://habrastorage.org/webt/pe/ay/zf/peayzfh745-twugmjk-r2zg-plc.png)
amarao
Ядро Linux:
DOOM?
lain8dono
Да. Согласно этой терминологии так и есть.
amarao
… При том, что в том же Rust'е вызов naked function является unsafe на 100%, а вещи, которые в naked function творят, к безопасности отношения не имеют, я не уверен, что замена в этом месте C/C++ на Rust что-то фундаментально поменяет. А как писать ядро без naked functions — я очень хочу посмотреть.
mkpankov
В отличие от Си, в Расте аудит UB требуется только в unsafe коде. Которого очень мало — в т.ч. учитывая текущую практику разработки системных компонентов или операционных систем.
Например, в сетевом стеке Fuchsia:
К сожалению, именно число строк посчитать уже сложно. Но порядок и так видно, если на 300 тысяч строк кода 300 мест, где могут быть проблемы.
lain8dono
Легко. Вызываем обычные функции из асма. Я так делал, загляните в мои статеечки.
С другой стороны не очень понятна мысль про
unsafe
. Разница как раз в этом месте и будет фундаментальной. Блокunsafe
предполагает, что внутри вы вручную налагаете ограничения для соответствия всем правилам safe-абстракций. Ну и традиционное:unsafe
не отключает никакие проверки, которые Rust делает.amarao
Э… Простите, а как вы будете уговаривать процессор вызывать "обычные функции" в обработчике прерываний? Там задача — ничего не поломать у прерванного процесса, и без naked functions — никуда. см rust-rfcs/1201.
lain8dono
Легко и непринуждённо поговорю с процессором на его ассемблере. Читайте про такую штуку, как ABI. Я при помощи
extern
говорю функции из Rust следовать стабильному ABI (а не своему внутреннему) и в ассемблере просто выполняю требования ABI. При этомextern
сам по себе не требуетunsafe
. Вообще говоря можно полностью написать ядро без единогоunsafe
. Всё останется корректным. Просто это не столь удобно.А неудобно это именно по той причине, что я теряю мощную фундаментальную абстракцию под названием
unsafe
.gxcreator
А разве extern это не unsafe?
Morgan_iv
extern бывает как из Rust наружу, так и снаружи в Rust. Первое не требует unsafe, второе требует
mkpankov
Вообще да, если посмотреть на статистику нахождения там багов и уязвимостей, в т.ч. вызванных проблемами небезопасной работы с памятью.
Например, вот относительно недавнее исследование. Оно не блещет полнотой, но достаточно репрезентативно.