LINUX.ORG.RU

Атака на пакет arrayref Rust

 , , ,


0

5

Атака на цепочку поставок: вредоносный код в crates.io через пакет arrayref

20 августа 2026 года Команда безопасности Rust (Rust Security Response Team) сообщила об обнаружении вредоносных пакетов в реестре crates.io, связанных с популярной библиотекой arrayref.

Что произошло

20 августа 2026 года в 7:15 UTC команда получила сообщение о том, что пакет proc-macro1 является вредоносным. После проверки выяснилось, что его build-скрипт загружал вредоносное ПО.

Пакет proc-macro1, а также связанные с ним proc-macro-en, aovine, arone, aronenao и tinymember были удалены из реестра.

Дальнейшее расследование показало, что широко используемый пакет arrayref был недавно перевыпущен с добавленной зависимостью от вредоносного proc-macro1, при этом последние версии были помечены как yanked. Команда удалила вредоносную версию и восстановила ранее ошибочно отозванные версии.

Аналогичным образом пострадали другие пакеты того же автора — internment и append-only-vec. По ним были приняты те же меры. Аккаунт автора заблокирован в качестве меры предосторожности. По имеющимся данным, сам автор arrayref не действовал злонамеренно — вероятнее всего, были скомпрометированы его компьютер или учётные данные. Команда пытается связаться с ним.

Что нужно сделать пользователям

Рекомендуется проверить локальные зависимости на предмет использования следующих вредоносных версий, удалённых с crates.io:

  • append-only-vec@0.1.9
  • arrayref@0.3.10
  • internment@0.8.7
  • proc-macro1, proc-macro-en, aovine, arone, aronenao, tinymember (любые версии)

Проверить наличие этих пакетов в локальном кэше можно следующей командой:

find ~/.cargo/registry/cache -type f \( \
  -name 'append-only-vec-0.1.9.crate' -o \
  -name 'arrayref-0.3.10.crate' -o \
  -name 'internment-0.8.7.crate' -o \
  -name 'proc-macro1-*.crate' -o \
  -name 'proc-macro-en-*.crate' -o \
  -name 'aovine-*.crate' -o \
  -name 'arone-*.crate' -o \
  -name 'aronenao-*.crate' -o \
  -name 'tinymember-*.crate' \
\) -print

Благодарности

Команда Rust поблагодарила исследователей Nextron Systems GmbH за первоначальное обнаружение проблемы и сообщение о ней, а также сотрудников, участвовавших в устранении инцидента.

>>> Источник



Проверено: cetjs2 ()
Последнее исправление: cetjs2 (всего исправлений: 3)
Ответ на: комментарий от unC0Rr

Да? А как просмотреть код для его проверки на закладки?

Открыть в песочнице.

То, что VSCode, непример, предлагает в качестве ограничений - это не песочница. Это издевательство. Если взять тот же rust-analyzer, то без него не будут работать автодополнение, поиск по типам и определениям и многое другое. В таком режиме пытаться что-то анализировать, равносильно запуску grep и обычному просмотру кода в vim. Просто нет смысла использовать IDE.

Впрочем, это не проблема именно rust, схожая ситуация для golang и python. Но для последних хотя бы можно привинтить ctags и использовать его в vim. Для rust оно не работает и надо ставить сторонние утилиты через тот же cargo(а мы ведь ему не доверяем). Хотя, может, сейчас и стало лучше, хз. Но когда мне последний раз приходилось с этим сталкиваться, было именно так.

Это то же самое, что открыть код зависимостей с нуля.

Но, нет. В VSCode если ты добавил проект в Trusted Workspace, то всё, что там обновляется уже по умолчанию доверено.

С другими IDE не работал и не собираюсь. Как и очень большое количество разработчиков. Тут или где-то в соседнем треде как раз сегодня кто-то приводил ссылку на наиболее используемые IDE для rust и VSCode там был в тройке лидеров.

shell-script ★★★★★
()
Последнее исправление: shell-script (всего исправлений: 1)
Ответ на: комментарий от firkax

Если фичи не связанные то никаких проблем от сливания не будет.

Кто такое сказал? В коде бывают очень неочевидные связи, тем более что код для новых фич может требовать изменений в старом.

при ребейзе своих наработок надо проверять результат

Т.е. начинать все проверки с нуля.

Ребейз - это буквальный отказ от всех ранее проведённых проверок, потому что каждый коммит приводится в состояние, в котором никто его никогда ранее не видел. В сочетании с языком, в котором о коде невозможно рассуждать локально - бомба.

unC0Rr ★★★★★
()
Ответ на: комментарий от sena

для этих 0.001% индустрии

Это далеко не 0.001% индустрии. Это любой гигант в IT, у которого внезапно больше всего вакансий и сотрудников.

peregrine ★★★★★
()
Ответ на: комментарий от unC0Rr

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

firkax ★★★★★
()
Ответ на: комментарий от peregrine

Это далеко не 0.001% индустрии. Это любой гигант в IT, у которого внезапно больше всего вакансий и сотрудников.

Даже у любого гиганта отнюдь не весь код настолько высококритичен. А из высококритичного кода отнюдь не весь должен быть высокопроизводительным и высоконагруженным. Во многих остальных случаях те же практические задачи дешевле и проще решаются средствами Java, Go, Python, PHP, C# и проч., а инженерный ригоризм Rust превращается из преимущества в издержку. Так что да, есть какая-то область где нужно извращаться, где все звёзды сошлись, но она весьма ограничена.

sena ★★★
()
Последнее исправление: sena (всего исправлений: 1)
Ответ на: комментарий от F457

Статистика хрома 70% багов в Chrome из-за неверной работы с памятью Где еще современнее и безопаснее то искать?)

Они использовали кучу готовых библиотек, например не так давно отказались от libxml.

sena ★★★
()
Ответ на: комментарий от sena

Так что да, есть какая-то область где нужно извращаться, где все звёзды сошлись, но она весьма ограничена.

Ты про переписывание cp с ошибками в логике обработки аргументов командной строки?

shell-script ★★★★★
()
Ответ на: комментарий от sena

И?

А и да. Где этот сказочный «Современный код на с++, написанный с учётом вопросов безопасности»? А то в реальной жизни почемуто софт на крестах лажает с памятью.

F457 ★★★★
()
Ответ на: комментарий от F457

Где этот сказочный «Современный код на с++, написанный с учётом вопросов безопасности»?

libxml это старая сишная библиотека, но я говорю не только о возрасте и языке.

Взять например, Qt. Хотя это вроде бы современная библиотека, она использует подходы ещё с++98. Там нет ни unique_ptr, ни shared_ptr, std::span и многое другое.

И таких зрелых с++ библиотек большинство. Новых, написанных с современным подходом пока исчезающе мало, а старые типа Qt никто не спешит переписывать.

Современный с++ существенно отличается от этого старого подхода. Но известных популярных библиотек на нём не сильно больше (а то и меньше), чем на расте. Это же, уверен, относится и к гугловскому коду и другим исследованиям.

sena ★★★
()
Последнее исправление: sena (всего исправлений: 6)
Ответ на: комментарий от sena

Новых, написанных с современным подходом пока исчезающе мало, а старые типа Qt никто не спешит переписывать

И будет мало, и старое переписывать будут только такие же фанатики как у раста. Потому что все эти горы обёрток над указателями большинству программистов нафиг не сдались.

firkax ★★★★★
()
Ответ на: комментарий от F457

Нашёл на кого равняться... Хром (и вообще большинство гугловской деятельности) это пример того как делать не надо.

firkax ★★★★★
()
Ответ на: комментарий от firkax

И будет мало, и старое переписывать будут только такие же фанатики как у раста. Потому что все эти горы обёрток над указателями большинству программистов нафиг не сдались.

Здесь я с тобой не соглашусь. Например умные указатели в с++ позволяют сильно экономить код (в отличие от фишек раста, которые код раздувают и усложняют) и действительно позволяют существенно снизить количество ошибок при работе с памятью. При этом в отличие от раста, они не являются обязательными к использованию и всегда можно отказаться от них в пользу старых добрых указателей, если вдруг понадобится выжать максимум из железа. Многие фирмы вообще запрещают использовать голые указатели, хотя это и перебор по-моему. Но как минимум, запрет передавать через них владение вполне разумен.

Это же можно сказать и про многие другие современные возможности с++. Они есть и позволяют действительно снизить количество ошибок с памятью, но в силу инерции переход на них сильно затянулся.

sena ★★★
()
Последнее исправление: sena (всего исправлений: 2)
Ответ на: комментарий от sena

Там нет ни unique_ptr, ни shared_ptr, std::span и многое другое.

У вас устаревшая на несколько лет информация. Сам unique_ptr не используется в публичном интерфейсе, насколько я помню, но его использование поощряется, а соответствующие умные указатели Qt частично объявлены устаревшими. Всякие string_view и span как минимум принимаются в конструкторах.

unC0Rr ★★★★★
()
Ответ на: комментарий от bbc69

Ещё раз: ты утверждаешь, что разработка на расте – это быстро. Положим быстрее, чем на цепепе. Откуда мы это знаем? Из того, что, интуитивно, относится к теме можем припомнить, что конпелятор раста медленный (крестовый код же бывает разный) и компилятор требует от программиста некоторых приседаний при написании кода. Кажется, что и первое и второе должно сокращать скорость итерирования?

BruteForce ★★★★
()
Ответ на: комментарий от BruteForce

требует от программиста некоторых приседаний при написании кода

Когда код начнёшь не только писать и компилировать, но и запускать, тогда и почувствуешь разницу.

unC0Rr ★★★★★
()
Ответ на: комментарий от vvb333007

Это дословно именно то, что я и так сейчас имею, но на Си.

Ты большой молодец, но не совсем понятно, что именно это должно опровергать.

Ну штош теперт. Для таких , как вы, __prefetch() придумали в GCC, подсасывать в кэш то, что нужно.

Вот твой префетч из гцц, void __builtin_prefetch (const void *addr, ...), видишь там адрес в аргументах? В обычном связном списке адрес следующего элемента ты узнаёшь только после того, как загрузил текущий элемент и прочитал из него следующий. Сам pointer chasing на месте, префетч не поможет. А если у тебя адреса будущих элементов известны сильно заранее, то у тебя уже есть какой-то дополнительный механизм их хранения/индексации, и это уже не просто обычный обход списка по next. Да и куда красота твоей сишки денется, если ты будешь компиляторозависимыми костылями его обмазывать?

В реальном мире списки кругом: ваша сетевая карта, допустим Ethernet

Вот тут уже просто мимо. У Ethernet типичная схема RX/TX descriptor rings. Специально глянул в доку. В памяти это может быть обычный массив дескрипторов [desc0][desc1][desc2][desc3], а следующий элемент выбирается по индексу. Это не связный список. Покажи конкретный драйвер, где на списках построено, потыкаю.

PS: Мне было бы реально интересно посмотреть на реализацию какого-нибудь более-менее живого TCP/IP стека на Rust. Есть такое? Интересно поглазеть, как у них будет выглядеть работа с памятью.

Да, сетевой стек фучии полностью написан на расте, вот тут сырцы: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/connectivity/network/netstack3

Gordon
()
Ответ на: комментарий от AlexM

Вопросики, вопросики.

Резонные вопросики, в питонячьем мире этого конечно сильно больше и там они сильно взрослее. Но для чебуречной не нужны особо сложные опенапи фичи, чтобы куцая по меркам питона растовая тулза на них спасовала, в любом случае условный кодекс нагенерит тебе это на ать-два. Зато тулинг питона более замороченный, пока там все эти uv/poetry настроишь, mypy+ruff (хз нужно ли для чебуречной), а потом еще в CI это все запихнешь… В расте все в одном месте, и билдится в статичный бинарь. Короче, что я хочу сказать, для вебдева использовать раст - не бредовая мысль, это не то же самое что и на сях.

Gordon
()
Ответ на: комментарий от unC0Rr

У вас устаревшая на несколько лет информация.

В смысле устаревшая?

Вот тебе официальный пример из Qt6

https://code.qt.io/cgit/qt/qtbase.git/tree/examples/opengl/2dpainting/window.cpp?h=6.11

Cтарые добрые голые (или сырые? как лучше rawptr перевести?) указатели

C++98 во всей своей красе…

sena ★★★
()
Ответ на: комментарий от sena

Что плохого в unsafe? Это часть языка, и это не полная свобода. Вот единственное с чего снимает ошейник unsafe:

  • Разыменовывать сырой указатель
  • Вызывать unsafe-функцию или метод
  • Получать доступ к изменяемой статической переменной или изменять её
  • Реализовывать unsafe-трейт
  • Получать доступ к полям union

по-прежнему работают:

  • Проверка типов
  • Бороу чекер для обычных &T/&mut T
  • Правила move/ownership
  • Проверки lifetime там, где они выражены обычными ссылками
  • Trait checking
  • Visibility/privacy
  • Pattern matching/exhaustiveness
  • Обычные правила мутабельности

Как видишь даже unsafe rust остается более безопасным чем сишка.

Gordon
()
Ответ на: комментарий от Gordon

Что плохого в unsafe?

Сама идея (не)безопасного режима очень хороша, в том или ином виде это непременно попадёт в с++, надеюсь раньше чем его похоронят. :) За первую реализацию этой идеи следует сказать спасибо расту и его авторам.

sena ★★★
()
Ответ на: комментарий от vvb333007

Там как раз все обмазано списками, односвязными.

Односвязный список в расте реализуется вообще без unsafe.

Gordon
()
Ответ на: комментарий от sena

Ну так тут владение и не предусматривается. Какой же ещё указатель использовать? В рамках Qt только QPointer будет подходящей заменой.

unC0Rr ★★★★★
()
Ответ на: комментарий от sena

непременно попадёт в с++

Не попадёт. Или же он потеряет обратную совместимость, а значит автоматом станет не нужным.

unC0Rr ★★★★★
()
Ответ на: комментарий от BruteForce

Речь шла о сборщиках мусора, так что пусть будет Джава, например.

Раст находится где-то посередине. Очевидно, что на нём нужно возни больше, чем на джаве. И скорее всего меньше, чем на плюсах. Последнее измерить сложнее, т.к. если мы возьмем человека с 20+ лет опыта на плюсах и одним годом опыта на расте, ему быстрее будет писать на первом. Если же мы возьмем людей с одинаковым опытом то сравнение уже может быть не в пользу плюсов.

УПД. А пердолинг связан с непониманием концепции языка как такового. Имхо.

bbc69
()
Последнее исправление: bbc69 (всего исправлений: 1)
Ответ на: комментарий от unC0Rr

Основная идея QPointer для qobject и графических виджетов вполне подходит: вполне логично, что у виджета есть виджет-родитель-владелец, который им владеет. Но всё что происходит вокруг этого, и в кютном api и внутри Qt - всё это написано на старом c++98. И полностью переделать это без частичного отказа от совместимости не получится.

С современном с++ владение виджетом(или другим объектом) логично выражать либо через unique_ptr, либо непосредственно через «член класса». Гарантированный не владеющий доступ - через ссылку&. Если возможен нуль, то нужен отдельный тип. Там где действительно совместное владение, то shared_ptr, weak_ptr, вот это вот всё. Конкретный пример: сейчас можно написать

QPushButton quit("Quit");
QWidget window;
quit.setParent(&window);

Это ошибочный код. window попытается удалить quit в деструкторе и мы получим UB. Но с помощью современного с++ можно сделать api который не позволит сделать ошибку:

QWidget window;
auto& quit = window.makeChild<QPushButton>("Quit");

Либо с помощью unique_ptr:

QWidget window;
auto quit = std::make_unique<QPushButton>("Quit");
window.addChild(std::move(quit));

И таких примеров в Qt очень много. Он остаётся с++98 и внутри и в api, хотя пользователь его может использовать с современными лямбдами, концептами и range for…

Но сам он преимущества современного с++ для управления временем жизни/владением объектом не использует. Современный же с++ уже позволяет создавать безопасный api, который делает многие классы ошибок невозможными или существенно менее вероятными. 100% гарантий как раст на все случаи жизни он не даст, но все практически значимые ситуации покрыть можно.

А ведь это современная библиотека, причём одна из лучших на сегодня, с помощью которой создаются современные без кавычек программы. Такая ситуация очень распространена в мире с++ и это понятно.

Новые библиотеки и новый код, написанный с учётом требований безопасности на современном с++ значительно снижает риски. И развитие в этом направлении продолжается, с каждым новым стандартом ситуация улучшается и будет улучшаться.

sena ★★★
()
Последнее исправление: sena (всего исправлений: 1)
Ответ на: комментарий от Gordon

Но сначала нужно придумать реальный кейс для такого контейнера, нужен ли он вообще.

Да ну тебя, наводишь тень на плетень… Это стандартная структура, преимущества недостатки расписаны в любом букваре, типа когда нужна гарантия что указатель на ноду не протухнет.

sena ★★★
()
Последнее исправление: sena (всего исправлений: 3)
Ответ на: комментарий от Gordon

Там по ощущениям меньше сотни строк кода. Это много? Покажи аналогичную реализацию на крестах.

Наглядность, простота, понятность - вот что главное. Объём кода это тоже существенно. Лишний код дольше читать, дольше писать, труднее понять.

Для языка важен принцип, когда простые задачи решаются просто и только более сложные требует усложнения кода.

Попросил жптшку этот растокод переписать на с++, хотя по-моему и так всё очевидно, но может тебе так будет наглядней

#include <cstddef>

template <typename T>
class LinkedList
{
    struct Node {
        T value;
        Node* prev = nullptr;
        Node* next = nullptr;
    };

public:
    LinkedList() = default;

    ~LinkedList() {
        clear();
    }

    void push_front(const T& value) {
        Node* node = new Node{
            .value = value,
            .prev = nullptr,
            .next = head_
        };

        if (head_) {
            head_->prev = node;
        } else {
            tail_ = node;
        }

        head_ = node;
        ++len_;
    }

    void push_back(const T& value) {
        Node* node = new Node{
            .value = value,
            .prev = tail_,
            .next = nullptr
        };

        if (tail_) {
            tail_->next = node;
        } else {
            head_ = node;
        }

        tail_ = node;
        ++len_;
    }

    void remove(Node* node) {
        if (node->prev) {
            node->prev->next = node->next;
        } else {
            head_ = node->next;
        }

        if (node->next) {
            node->next->prev = node->prev;
        } else {
            tail_ = node->prev;
        }

        delete node;
        --len_;
    }

    std::size_t size() const {
        return len_;
    }

    void clear() {
        Node* p = head_;

        while (p) {
            Node* next = p->next;
            delete p;
            p = next;
        }

        head_ = nullptr;
        tail_ = nullptr;
        len_ = 0;
    }

private:
    Node* head_ = nullptr;
    Node* tail_ = nullptr;
    std::size_t len_ = 0;
};
sena ★★★
()
Последнее исправление: sena (всего исправлений: 1)
Ответ на: комментарий от sena

Это ни фига не аналог, и не читабельнее и, самое главное, не надёжней. Аналог должен быть с каким-нибудь std::shared_ptr вместо указателей. Так то в расте тоже сырые указатели есть (которые тоже лучше обставлены и реализованы чем в сишках/плюсишках), и идиоматичнее реализовывать именно на них, это если, конечно, прям всралась интрузивно-указательная реализация списка. Как это и сделано в стандартно библиотечном LinkedList https://doc.rust-lang.org/src/alloc/collections/linked_list.rs.html#50-53

zurg ★★
()
Последнее исправление: zurg (всего исправлений: 2)
Ответ на: комментарий от Gordon

А с сями-то что не так? У меня сайт чебуречной на сях. Есть не просит.

BruteForce ★★★★
()
Ответ на: комментарий от bbc69

Я сказал, где могут быть проблемы, влияющие на скорость разработки.

может быть не в пользу плюсов.

Вот я о том же. Откуда знаем-то? Может быть, а может быть и наоборот.

BruteForce ★★★★
()
Ответ на: комментарий от sena

С современном с++ владение виджетом(или другим объектом) логично выражать либо через unique_ptr, либо непосредственно через «член класса».

Либо через индекс на элемент пула, либо через указатель на память где-то, либо…

Да куча вариантов в зависимости от задачи.

BruteForce ★★★★
()
Ответ на: комментарий от Gordon

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

zurg ★★
()
Ответ на: комментарий от zurg

Вопрос перформанса похоже. Я в целом не вижу особых проблем с unsafe, отличная штука для локализации опасных участков. Проблемы возникают только у си-фанатов, честно не могу понять почему.

Gordon
()
Ответ на: комментарий от zurg

Это ни фига не аналог, и не читабельнее и, самое главное, не надёжней.

По-моему полный аналог, а что с++ надёжней в смысле гарантий от дурака, я не говорил. Но зато читабельнее и проще

sena ★★★
()
Последнее исправление: sena (всего исправлений: 2)
Ответ на: комментарий от Gordon

дело не в объёме, хотя с++ версия явно более краткая

sena ★★★
()
Последнее исправление: sena (всего исправлений: 1)
Ответ на: комментарий от sena

Это стандартная структура для учебников по программированию, в реальном мире почти не встречается за ненадобностью.

Gordon
()
Ответ на: комментарий от Gordon

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

sena ★★★
()
Ответ на: комментарий от Gordon

а в принципе он используется, например для организации LRU-кэш, intrusive list (это у меня было, но есть и в ядре), потом для кольца я его использовал, да всё уже и не вспомню.

Кстати, точно! С кольцом особенно интересно, особенно в контексте Раст, там же получается цикл в графе, хотелось бы посмотреть на имплементацию в Расте! Гы-гы

sena ★★★
()
Последнее исправление: sena (всего исправлений: 2)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.