Spec-Zone.ru › Perl 5.32

Safe

СОДЕРЖАНИЕ

  • ИМЯ
  • СИНТАКСИС
  • ОПИСАНИЕ
  • ПРЕДУПРЕЖДЕНИЕ
  • МЕТОДЫ
    • permit (OP, ...)
    • permit_only (OP, ...)
    • deny (OP, ...)
    • deny_only (OP, ...)
    • trap (OP, ...), untrap (OP, ...)
    • share (NAME, ...)
    • share_from (PACKAGE, ARRAYREF)
    • varglob (VARNAME)
    • reval (STRING, STRICT)
    • rdo (FILENAME)
    • root (NAMESPACE)
    • mask (MASK)
    • wrap_code_ref (CODEREF)
    • wrap_code_refs_within (...)
  • РИСКИ
  • АВТОР

ИМЯ

Safe — Компиляция и выполнение кода в ограниченных отсеках

СИНТАКСИС

use Safe;

$compartment = new Safe;

$compartment->permit(qw(time sort :browse));

$result = $compartment->reval($unsafe_code);

ОПИСАНИЕ

Модуль расширения Safe позволяет создавать отсеки, в которых можно оценивать перл-код. Каждый отсек имеет

новый пространство имен

«Корень» пространства имен (т. е. «main::») изменяется на другой пакет, и код, выполняемый в отсеке, не может ссылаться на переменные вне этого пространства имен, даже с помощью поиска по шаблонам в runtime и других ухищрений.

Код, который компилируется вне отсека, может помещать переменные в (или делиться переменными с) пространством имен отсека, и только эти данные будут видны коду, выполняемому в отсеке.

По умолчанию, переменные, которые разделяются с отсеками, — это только переменные «подчеркивания» $_ и @_. (и, технически, реже используемые %_, _ файловый дескриптор и так далее). Это потому, что в противном случае операторы Perl, которые по умолчанию используют $_, не будут работать, а также не будет работать присвоение аргументов в @_. при входе в подпрограмму.

маску операторов

Каждый отсек имеет связанную «маску операторов». Вспомните, что код Perl компилируется в внутренний формат перед выполнением. Выполнение перл-кода (например, с помощью «eval» или «do 'file'») приводит к компиляции кода в внутренний формат, а затем, при отсутствии ошибок в компиляции, к его выполнению. Код, выполняемый в отсеке, компилируется с учетом маски операторов отсека. Попытка выполнить код в отсеке, который содержит замаскированный оператор, приведет к ошибке компиляции с ошибкой. Код не будет выполнен.

По умолчанию маска операторов для вновь созданного отсека — это тег ':default'.

Важно прочитать документацию модуля Opcode для получения дополнительной информации, особенно для подробных определений opnames, optags и opsets.

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

$cpt = new Safe;
sub wrapper {
  # vet arguments and perform potentially unsafe operations
}
$cpt->share('&wrapper');

ПРЕДУПРЕЖДЕНИЕ

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

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

Результаты могут отличаться. В случае сомнений не используйте его.

МЕТОДЫ

Для создания нового отсека используйте

$cpt = new Safe;

Необязательный аргумент (NAMESPACE), где NAMESPACE — это корневое пространство имен для использования в отсеке (по умолчанию «Safe::Root0», увеличивается для каждого нового отсека).

Обратите внимание, что версия 1.00 модуля Safe поддерживала второй необязательный параметр MASK. Эта функциональность была удалена до окончательного рассмотрения. Используйте методы permit и deny, описанные ниже.

Затем можно использовать следующие методы для объекта отсека, возвращаемого конструктором. Объект-аргумент подразумевается в каждом случае.

permit (OP, ...)

Разрешить указанные операторы для использования при компиляции кода в отсеке (в дополнение к уже разрешенным операторам).

Вы можете перечислять коды операций по именам или использовать имя тега; см. "Predefined Opcode Tags" в Opcode.

permit_only (OP, ...)

Разрешить только указанные операторы для использования при компиляции кода в отсеке (ни другие операторы не разрешены).

deny (OP, ...)

Запретить указанные операторы для использования при компиляции кода в отсеке (другие операторы могут быть разрешены).

deny_only (OP, ...)

Запретить только указанные операторы для использования при компиляции кода в отсеке (все остальные операторы будут разрешены, поэтому вы, вероятно, не захотите использовать этот метод).

trap (OP, ...), untrap (OP, ...)

Методы trap и untrap являются синонимами deny и permit соответственно.

share (NAME, ...)

Это разделяет переменную(ые) в списке аргументов с отсеком. Это почти идентично экспорту переменных с помощью модуля Exporter.

Каждое NAME должно быть именем нелексической переменной, как правило, с включенным идентификатором типа. Слово без префикса интерпретируется как имя функции.

Примеры допустимых имён: «$foo» для скаляра, «@foo» для массива, «%foo» для хэша, «&foo» или «foo» для подпрограммы и «*foo» для шаблона (т.е. все записи таблицы символов, связанные с «foo», включая скаляр, массив, хэш, подпрограмму и дескриптор файла).

Предполагается, что каждое имя NAME находится в вызывающем пакете. См. share_from для альтернативного метода (который share использует).

share_from (PACKAGE, ARRAYREF)

Этот метод похож на share(), но позволяет явно указать пакет, символы которого должны быть разделены. Имена символов (включая символы типа) предоставляются как ссылка на массив.

$safe->share_from('main', [ '$foo', '%bar', 'func' ]);

Имена могут включать имена пакетов, которые являются относительными к указанному PACKAGE. Следовательно, эти два вызова имеют одинаковый эффект:

$safe->share_from('Scalar::Util', [ 'reftype' ]);
$safe->share_from('main', [ 'Scalar::Util::reftype' ]);

varglob (VARNAME)

Это возвращает ссылку на шаблон для записи в таблице символов VARNAME в пакете отсека. VARNAME должно быть именем переменной без маркера ведущего типа. Например:

${$cpt->varglob('foo')} = "Hello world";

имеет тот же эффект, что и:

$cpt = new Safe 'Root';
$Root::foo = "Hello world";

но избавляет от необходимости знать имя пакета $cpt.

reval (STRING, STRICT)

Это вычисляет STRING как перл-код внутри отсека.

Код может видеть только пространство имен отсека (как возвращается методом root). Корневой пакет отсека отображается как main:: пакет для кода внутри отсека.

Любая попытка кода в STRING использовать оператор, который не разрешен в отсеке, вызовет ошибку (во время выполнения основной программы, но во время компиляции кода в STRING). Ошибка имеет вид «'%s' заблокирован маской операций…».

Если операция заблокирована таким образом, код в STRING не будет выполнен. Если такая заблокированная операция произойдёт или любая другая ошибка времени компиляции или возврата, то $@ устанавливается на сообщение об ошибке, точно так же, как при eval().

Если ошибок нет, то метод возвращает значение последнего вычисленного выражения или используется оператор return, аналогично подпрограммам и eval(). Контекст (список или скаляр) определяется вызывающим элементом как обычно.

Если возвращаемое значение reval() является (или содержит) ссылкой на код, эти ссылки на код упаковываются для выполнения всегда в отсеке. См. "wrap_code_refs_within".

Прежде не документированный аргумент STRICT задаёт строгость: если он равен true, используется 'use strict;', в противном случае используется 'no strict;'. Обратите внимание: если STRICT опущен, по умолчанию используется 'no strict;'.

Некоторые моменты, которые следует учитывать:

Если оператор entereval разрешен, то код может использовать eval "..." для «скрытия» кода, который может использовать запрещенные операторы. Это не является большой проблемой, поскольку при попытке выполнить код eval он потерпит неудачу, так как маска операторов всё ещё активна. Однако эта техника позволила бы умному и, возможно, вредному коду «исследовать» границы того, что возможно.

Любой строковый eval, который выполняется кодом, выполняющимся в отсеке, или кодом, вызванным из кода, выполняющегося в отсеке, будет оценён в пространстве имен отсека. Это потенциально серьёзная проблема.

Рассмотрим функцию foo() в пакете pkg, скомпилированную вне отсека, но общую с ним. Предположим, что отсек имеет корневой пакет под названием «Root». Если foo() содержит оператор eval, такой как eval '$foo = 1', то обычно $pkg::foo будет установлен в 1. Если foo() вызывается из отсека (каким-либо способом), то вместо установки $pkg::foo eval фактически установит $Root::pkg::foo.

Это легко продемонстрировать, используя модуль, такой как Socket, который использует eval "..." в качестве части функции AUTOLOAD. Вы можете «использовать» модуль вне отсека и поделиться (автозагружаемой) функцией с отсеком. Если автозагрузка инициируется кодом в отсеке или любым кодом где-либо, который вызывается каким-либо способом из отсека, то eval в функции AUTOLOAD модуля Socket происходит в пространстве имен отсека. Любые переменные, созданные или используемые выполняемым кодом, теперь находятся под управлением кода в отсеке.

Аналогичный эффект действует для всех поисков символов в runtime в коде, вызываемом из отсека, но не скомпилированном в нём.

rdo (FILENAME)

Это вычисляет содержимое файла FILENAME внутри отсека. Он использует те же правила, что и встроенный в Perl do для поиска файла, возможно, используя @INC.

См. документацию метода reval для получения дополнительной информации.

root (NAMESPACE)

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

Обратите внимание, что это поведение отличается от версии 1.00 модуля Safe, где корневой модуль мог использоваться для изменения пространства имен. Эта функциональность была удалена до окончательного рассмотрения.

mask (MASK)

Это метод get-or-set для маски оператора компартмента.

Без аргумента MASK он возвращает текущую маску оператора компартмента.

С аргументом MASK он устанавливает маску оператора для компартмента (эквивалентно вызову метода deny_only).

wrap_code_ref (CODEREF)

Возвращает ссылку на анонимную подпрограмму, которая при выполнении вызовет CODEREF с компартментом Safe «в действии». Другими словами, с изменённым пространством имён пакета и включённой маской оператора.

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

Это особенно полезно, когда применяется к ссылкам на код, возвращённым из reval().

(Это также предоставляет своего рода обходной путь для RT#60374: «Ошибка сортировки Safe.pm {} с -Dusethreads». См. https://rt.perl.org/rt3//Public/Bug/Display.html?id=60374 для более подробной информации.)

wrap_code_refs_within (...)

Обертывает все ссылки CODE, найденные в аргументах, заменяя каждую результатом вызова "wrap_code_ref" для ссылки CODE. Любые ссылки ARRAY или HASH в аргументах проверяются рекурсивно.

Ничего не возвращает.

РИСКИ

Этот раздел представляет собой лишь обзор некоторых действий, которые код в компартменте может выполнить (намеренно или непреднамеренно), что может повлиять на область за пределами компартмента.

Память

Потребление всей (или почти всей) доступной памяти.

Процессор

Вызов бесконечных циклов и т. п.

Шпионаж

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

Сигналы

Вызывание сигналов (особенно SIGFPE и SIGALARM) для воздействия на ваш процесс.

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

Изменения состояния

Операции, такие как chdir, очевидно, влияют на весь процесс, а не только на код в компартменте. Операции, такие как rand и srand, оказывают подобное, но более тонкое влияние.

АВТОР

Первоначально разработан и реализован Malcolm Beattie.

Переработан для использования модуля Opcode и других изменений, добавленных Tim Bunce.

В настоящее время поддерживается Perl 5 Porters, <perl5-porters@perl.org>.

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.32.0/Safe

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API