Материал проверен 2 ноября 2026?
БК

ГЛАВНАЯ / ИНСТРУКЦИИ / CROSS-FUNCTION REENTRANCY: КАК ПОВТОРНЫЙ ВХОД ЗАТРАГИВАЕТ ОБЩИЕ ИНВАРИАНТЫ

Cross-function reentrancy: как повторный вход затрагивает общие инварианты

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

Передача управления

Внешний вызов может вернуть управление до завершения функции

Когда контракт вызывает другой контракт или отправляет ему Ether, выполнение внешнего адресата может начаться до того, как исходная функция закончит свою работу. Если адресат способен выполнить callback, он может повторно обратиться к публичной функции исходного контракта в том же общем сценарии транзакции.

При обычной reentrancy повторно вызывается исходный entrypoint. При cross-function варианте callback обращается к другой функции, которая использует те же balances, shares, collateral, limits или статус операции. Условие риска – не само наличие callback, а возможность воспользоваться промежуточным состоянием, пока инвариант ещё не восстановлен.

  • callback запускается до завершения внешней функции
  • повторный вход может выбрать другой entrypoint
  • возможность callback подтверждена поведением вызываемого адреса
Общее состояние

Связанные функции могут нарушить единое условие учёта

Представьте контракт, где функция вывода сначала отправляет актив внешнему получателю, а потом уменьшает внутренний баланс. Если callback вызывает функцию займа, расчёта лимита или выдачи награды, та может прочитать старый баланс и принять решение, которое уже не должно быть доступно. Вызов повторно использует не обязательно одну и ту же строку кода – он использует несогласованное состояние.

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

  • общие переменные перечислены
  • инвариант проверяется в промежуточной точке
  • повторный метод не может использовать прежнее право на баланс или залог
ВопросЧто искать
Где передаётся управление?CALL, transfer активов, callback или интеграционный hook
Какие функции доступны?Все public/external entrypoint вызывающего контракта
Что у них общее?Storage, лимиты, балансы, состояние залога
Когда восстанавливается условие?До внешнего вызова, после callback или не восстанавливается
Как анализировать

Рисуйте граф вызовов и отмечайте состояние до callback

Для каждой внешней операции выпишите вызывающий метод, целевой адрес и параметры передачи управления. Затем перечислите функции, доступные этому адресу при callback, и отмечайте чтение или запись общих переменных. Отдельно рассмотрите вложенную цепочку: вызываемый контракт может сам обратиться к третьему протоколу, который прочитает состояние исходного контракта.

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

Границы риска

Внешний вызов сам по себе не означает успешную атаку

Для эксплуатации должны совпасть доступный путь callback, промежуточное состояние, полезный эффект и условия допуска функции. Модификатор доступа, проверка статуса или уже обновлённое состояние могут закрыть путь. И наоборот, защита только одной функции может не закрыть повторный вход в соседний метод.

Не считайте view-функцию автоматически безвредной: её чтение может быть использовано другим контрактом в той же составной операции, если возвращаемое значение отражает промежуточное состояние. При этом конкретный путь и возможность получить выгоду нужно доказать trace и моделью протокола, а не одним названием класса уязвимости.

FAQ

Частые вопросы

Cross-function reentrancy повторно вызывает ту же функцию?

Не обязательно. Callback может обратиться к другой функции, использующей связанное состояние.

Для reentrancy нужен перевод ETH?

Нет. Риск может возникнуть при других внешних вызовах и интеграционных callback, если управление возвращается к уязвимому состоянию.

Достаточно проверить одну функцию withdraw?

Нет. Нужно перечислить связанные entrypoint и общий инвариант.

Если функция помечена view, риска нет?

Её чтение может иметь значение для другой функции или контракта, если состояние временно несогласовано.

Внешний вызов всегда означает уязвимость?

Нет. Нужно показать достижимый callback и конкретное нарушение инварианта.

Итоговая проверка

Чек-лист: cross-function reentrancy: как повторный вход затрагивает общие инварианты

  • внешние вызовы перечислены;
  • доступные callback entrypoint найдены;
  • общие переменные и инварианты записаны;
  • порядок чтения и записи проверен;
  • вложенные контракты учтены;
  • тесты проверяют разные entrypoint и состояние после callback;
  • защита распространяется на связанную операцию.

Материал подготовлен редакцией сайта и проверен 2 ноября 2026 года. Условия бирж, кошельков и блокчейн-сетей могут меняться. Перед операцией сверяйте данные в интерфейсе выбранного сервиса.