ЯЗЫК ПРОГРАММИРОВАНИЯ RUST УПРОЩАЕТ РАЗРАБОТКУ БОЛЕЕ БЕЗОПАСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ. ЧТО ЕЩЕ ПРЕДСТОИТ СДЕЛАТЬ?
Допустим, вы пишете почтовый клиент на С++. Ваше новое приложение будет применяться на рабочей станции, ежедневно используемой несколькими разными людьми. Но где-то по ходу дела вами была допущена ошибка. Работники, посылая друг другу специально изготовленное сообщение, могут вызвать переполнение буфера в памяти приложения и отправлять команды, позволяющие извлекать письма из почтовых ящиков других пользователей.
Такой баг с переполнением буфера – классический образец проблемы с памятью, а проблемы с памятью – одни из наиболее типичных при разработке программного обеспечения. Около 70% всех проблем с безопасностью, устраненных в продуктах Microsoft в период с 2004 по 2018 год, были связаны именно с памятью, как следует из презентации Мэтта Миллера из Центра реагирования на вопросы безопасности компании Microsoft, который рассматривает все проблемы безопасности, передаваемые в компанию.
Безопасность памяти – гигантская проблема. Операционные системы должны гарантировать, что в веб-приложениях не будет происходить взаимных утечек данных. Веб-браузер должен обеспечить, что веб-приложение, открытое в одной вкладке, не сможет заграбастать данные из другой вкладки. На облачных платформах необходимо сделать так, чтобы ни один пользователь не мог считывать данные другого пользователя.
“Безопасность памяти – проблема не только техническая, но и социальная,” – считает Джошуа Аас, исполнительный директор «Internet Security Research Group». - “из-за проблем с памятью получается не просто сбоящее программное обеспечение. Из-за них могут обрушиваться сервисы, которыми люди зарабатывают себе на жизнь или при помощи которых находят работу. Бреши в безопасности могут лишать нас приватности. Программы можно и следует писать более качественно.
В октябре 2020 года компания Internet Security Research Group запустила программу Prossimo, цель которой – продвигать безопасность памяти в Интернете. До сих пор одна из их ключевых инициатив связана с использованием языка программирования Rust, исходный код которого был открыт компанией Mozilla в 2010 году. На языке Rust гораздо легче писать код, безопасный с точки зрения памяти.
C, C++ и другие языки программирования, не требующие от разработчиков специально писать код для управления памятью программы, считаются «небезопасными для памяти», поскольку даже мелкие баги могут приводить к проблемам с безопасностью памяти. «Как бы ни были талантливы ваши разработчики, они все равно будут допускать ошибки», - говорит Аас, – «лучшие команды в мире, где работают самые компетентные системные программисты, то и дело допускают ошибки в области безопасности памяти. Просто посмотрите планируемые патчи безопасности практически для любого крупного проекта – и примеров найдется сколько угодно».
По словам Лоры Томпсон, вице-президента по инженерии в компании Fastly, занимающейся пограничными облачными вычислениями, «писать на С – все равно, что делать хирургию на мозге без помощи ассистента».
Давно было показано, что, когда пишешь программы на языках, безопасных с точки зрения памяти, устраняется целый класс уязвимостей из области безопасности. Тем не менее, код на C и C++ все еще повсюду. Операционные системы, сетевое программное обеспечение, веб-браузеры и аппаратные драйверы традиционно пишут на C или его объектно-ориентированном наследнике C++. С чем бы вы ни работали, Android, iOS, Windows, Linux или Mac, под капотом у них будет масса C/C++, несмотря на то, что во многих приложениях для них используются языки, обеспечивающие безопасность памяти – например, C#, Java и Swift.
На то есть причины. C и C++ быстрые. Надежные. Программисты уже умеют ими пользоваться, на них написаны тысячи свободно распространяемых библиотек, а также для них есть компиляторы, работающие практически с любым мыслимым чипсетом.
Prossimo фокусируется на безопасности памяти в целом, а не только на Rust. Но именно Rust, как никакой другой язык, наиболее в силах изменить статус-кво, сложившийся в системном программировании.
"Rust – это первый из множества новых языков, вошедших в практику примерно за 20 последних лет, действительно хорошо справляющийся с теми вещами, с которыми нам ранее многое не удавалось на C или ассемблере," – говорит генеральный технический директор Fastly Тайлер Мак-Маллен. – «Он очень производителен по части памяти, и у него убедительная система типов, позволяющая выражать высокоуровневые концепции на низкоуровневом языке». Плюс он хорошо взаимодействует с другими языками, способными работать на множестве платформ, от встраиваемых систем до серверов.
Причем, Rust усваивается. Он был признан “самым любимым” языком программирования в рамках опроса разработчиков, проведенного на Stack Overflow в 2021 году – пятый год подряд с тех пор, как вышел на первое место. Тем временем, он становится все популярнее в самых разных областях, от научных вычислений до проектов с открытым исходным кодом, например, Deno, это новая серверная JavaScript-платформа, созданная Райаном Далем, создателем Node.js.
В этом году Mozilla передала курирование Rust фонду Rust – это коалиция, основанная Amazon Web Services, Facebook, Google, Huawei, Microsoft и Mozilla. Это признак, что главные тяжеловесы нашей индустрии всерьез прочат Rust большое будущее.
Например, в Facebook более 100 разработчиков занимаются языком Rust, есть среди них и контрибьюторы, внесшие вклад в ядро языка. Facebook не отказывается и от других языков, но Rust используется в проектах по всей компании, в том числе, в блокчейне Diem, при разработке языка программирования Move и новой версии инструмента Buck. “Одна из основных целей, с которыми мы вступили в этот фонд – работать с другими его замечательными участниками, а также с сообществом Rust. Так мы поможем поддержке Rust еще эффективнее справляться с их отличной работой, чтобы Rust превратился в мейнстримовый язык системного программирования и не только,” – говорит Джоэл Марси, отстаивающий интересы свободной разработки в Facebook и входящий в совет директоров фонда Rust.
В настоящее время многие компании пользуются Rust, чтобы повысить безопасность своих облачных платформ; среди них - Amazon Web Services, Cloudflare, Fastly и Microsoft Azure.
"Еще пару лет назад меня эта идея не цепляла," - говорит Мак-Маллен. Но команда Fastly, работающая с WebAssembly, попросила выполнить пару проектов с использованием Rust, и Мак-Маллен был впечатлен как производительностью, так и безопасностью этого языка. Теперь Rust – ключевой элемент стека компании. "В принципе, все новое, что у нас сейчас делается на бекенде, написано на Rust," – говорит Томсон, - "Все вычислительные сервисы, при помощи которых наши клиенты запускают код, построены на основе Rust."
Цель, по словам Мак-Маллена – обеспечить безопасность памяти в масштабах всей плоскости данных. «Это среда такого рода, где нельзя доверять всем подряд», - говорит он, - «нельзя доверять входящему трафику, нельзя доверять коду, работающему на серверах. Если писать на таком языке как Rust, то проще обходиться без такого доверия».
AWS использует Rust в сетевых стеках многих своих сервисов, в том числе, EC2, S3 и CloudFront, сообщает Шейн Миллер, глава команды Rust Platform в Amazon Web Services. Облачная платформа построена в основном на базе свободно распространяемой контейнерно-ориентированной системы виртуализации Firecracker, написанной на Rust, а также на базе контейнерной операционной системы Bottlerocket, сделанной на основе Linux. "Rust быстро приобрел принципиальное значение для предоставления инфраструктуры в тех масштабах, с которыми работает AWS," – говорит Миллер.
Разрабатывать с нуля языки, обеспечивающие безопасность памяти – уже неплохо для начала. Но, чтобы привить безопасность памяти в масштабах всего Интернета, также потребуется рефакторинг старого программного обеспечения. Одна из самых амбициозных инициатив, связанных с Rust – добавление поддержки Rust под Linux, причем, это начинание пока не одобрил Линус Торвальдс, сообщивший ZDnet, что, когда речь идет о Rust, он предпочитает «посидеть и подождать».
Тем временем команда по адаптации Rust под Linux работает над тем, чтобы подружить Rust с ядром. Например, в стандартной библиотеке Rust предполагается, что при выделениях памяти никогда не возвращаются ошибки – данная концепция известна под названием «безупречное выделение». Если выделить память не удается, то процессы сразу завершаются. Загвоздка в том, что из-за этого могут возникать паники ядра – иными словами, операционная система полностью застопоривается в ответ на фатальную (с ее точки зрения) ошибку. Это плохая новость, если вы параллельно гоняете несколько рабочих нагрузок. Команда Rust под Linux, спонсируемая Google, недавно смогла обойти эту проблему при помощи собственноручно созданной Rust-библиотеки, но руководитель этого проекта Мигель Охеда надеется, что эта проблема будет устранена на более высоком уровне, в рамках самого языка Rust. «Мы уже начали этот процесс, и некоторые изменения уже приняты на уровне ядра», - написал он в почтовой рассылке по разработке ядра.
Если (и когда) Rust под Linux будет добавлен в ядро, это будет первый прецедент, когда в ядре Linux будет официально поддерживаться какой-либо язык кроме C или ассемблера, говорит разработчик ядра Грег Кроа-Хартман.
Linux – не единственная операционная система, в которой используется Rust. В 2019 году Адам Бёрч из команды разработчиков, развивающих в Microsoft систему Hyper-V, анонсировал у себя в блоге, что переписывает на Rust низкоуровневый системный компонент из базы кода Windows, но не сказал, какой именно. «Хотя проект пока не завершен, могу сказать, что опыт работы с Rust в целом положительный. Это хороший выбор для тех, кто хочет избежать распространенных ошибок, таких, что часто приводят к уязвимостям в базах кода на C++».
Все на Rust
Если вы решили сами попрактиковаться с Rust, то в сообществе предлагаются разнообразные ресурсы для изучения языка. Но предупреждаю: притом, насколько фанаты Rust любят этот язык, кривая обучения на этом языке очень крутая по сравнению с такими кривыми в других современных языках. «Разработчики сравнивают изучение Rust с вегетарианской диетой», - говорит Миллер, - «когда поймешь язык, он начинает нравиться, но обучение может получиться изнурительным. Поэтому я всегда стараюсь превратить брокколи в брауни. Чтобы учиться было классно».
Чтобы справиться с этой проблемой, Amazon Web Services приглашает на работу экспертов-преподавателей компьютерных наук, которые могли бы рассказать, как устроен этот язык. Некоторые приемы вполне тривиальны – например, добавить примеров кода в документацию. Есть и более сложные, которые, как рассчитывает компания, можно будет привнести в Rust – например, переосмыслить его компиляторы.
Но даже самым большим фанатам Rust до сих пор сложно представить, что на этом языке когда-нибудь будет переписан весь код, небезопасный с точки зрения памяти. Пройдет много времени, прежде, чем старый код выйдет из употребления, особенно, если он уже хорошо работает. Так, по оценке Томсона Рейтерса, в мире до сих пор в реальных сценариях используется около 220 миллиардов строк на COBOL, древнем языке, истоки которого восходят к концу 1950-х. Они обеспечивают работу около 43% банковских систем и 95% операций в банкоматах. Кроме того, в бизнес-приложениях во всем мире по-прежнему обычен Fortran.
Несмотря на это, не весь старый код на C/C++ требуется переписывать. «Мы не пытаемся взяться за тысячи проектов», - говорит Аас. – «Мы сосредоточились на критически важных компонентах, которыми пользуется практически каждый. Я говорю о веб-серверах, ядрах, TLS, DNS, NTP — базовом волокне, из которого сплетен Интернет».
«Бывает, что программу можно заменять компонент за компонентом», - объясняет Аас, - «можно заменить небезопасную с точки зрения памяти библиотеку на безопасную и постепенно повысить безопасность памяти в рамках всего приложения».
Отличный пример этого – работа Prossimo с программой Curl. Curl написана в основном на C, но Prossimo поддержала инициативу по добавлению в нее поддержки Rust-библиотек для поддержки сетевых технологий TLS и HTTP. Таким образом, можно использовать Rust для тех частей приложения, которые краешком затрагивают сеть, но не переписывать Curl целиком. Библиотеки на основе Rust не используются в Curl по умолчанию, но все, кому они кажутся предпочтительными, могут их включить. «Надеемся, что модули, безопасные для памяти, будут тестироваться, совершенствоваться, пока, наконец, не станут использоваться по умолчанию во всех крупных дистрибутивах Linux," – говорит Аас.
При этом есть способы изолировать в песочнице код, небезопасный для памяти, чтобы минимизировать связанные с ним риски. Например, в Fastly большая часть компонентов, основанных на C/C++, используется в среде исполнения WebAssembly, основанной на Rust. «Такой аккуратный способ перевести весь этот софт на Rust», - говорит Мак-Маллен.
Конечно же, нельзя устранить всех багов, в том числе, уязвимостей безопасности. Но совершенно реально избавиться от огромного класса проблем, связанных с небезопасностью памяти, просто подобрав подходящий язык. Rust становится все популярнее, поскольку этот язык не просто производительный, но и мощный, и открытый, и благодаря нему Интернет становится безопаснее для каждого.