内容

名称

Opcode - 在编译 Perl 代码时禁用命名操作码

概要

use Opcode;

描述

Perl 代码在执行之前始终被编译成内部格式。

评估 Perl 代码(例如通过“eval”或“do 'file'”)会导致代码被编译成内部格式,然后,如果编译过程中没有错误,则执行。内部格式基于许多不同的操作码

默认情况下,没有生效的操作掩码,任何代码都可以被编译。

Opcode 模块允许您定义一个操作符掩码,当 Perl 接下来编译任何代码时,该掩码将生效。尝试编译包含被屏蔽操作码的代码会导致编译失败并出现错误。代码将不会被执行。

注意

Opcode 模块通常不会直接使用。有关更典型的用法,请参见 ops pragma 和 Safe 模块。

警告

Opcode 模块没有实现有效的沙箱,用于使用 Perl 解释器评估不受信任的代码。

Perl 解释器中的错误可能被滥用以绕过 Opcode 限制,这些错误不被视为漏洞。有关更多信息,请参见 perlsecpolicy

作者对该软件在安全或安全目的方面的适用性不做任何明示或暗示的保证。

在任何情况下,作者均不对使用本软件引起的任何特殊、附带、后果性、间接或其他类似损害负责。

您的里程会有所不同。如有任何疑问,请勿使用它。

运算符名称和运算符列表

运算符名称的规范列表是 Perl 源代码分发版中文件 opcode.h 中定义和初始化的数组 PL_op_name 的内容(并安装到 Perl 库中)。

每个运算符都有一个简洁的名称(其 opname)和一个更详细或更易识别的描述性名称。opdesc 函数可用于返回运算符列表的描述列表。

下面列出的许多函数和方法都将运算符列表作为参数。大多数运算符列表可以由几种类型的元素组成。每个元素可以是以下之一

运算符名称 (opname)

运算符名称通常是像 enterloop、leaveloop、last、next、redo 等小写单词。有时它们相当隐晦,例如 gv2cv、i_ncmp 和 ftsvtx。

运算符标签名称 (optag)

运算符标签可用于引用运算符组(或集)。标签名称始终以冒号开头。Opcode 模块定义了几个 optag,用户可以使用 define_optag 函数定义其他 optag。

否定 opname 或 optag

opname 或 optag 可以以感叹号为前缀,例如,!mkdir。否定 opname 或 optag 表示从该点的累积操作集中删除相应的操作。

操作符集 (opset)

一个opset 是一个大约 44 字节的二进制字符串,它包含一组或零个或多个操作符。

opset 和 opset_to_ops 函数可用于将操作符列表转换为 opset,反之亦然。

在可以给出操作符列表的任何地方,都可以使用一个或多个 opset。另请参阅下文中的操作 opset。

操作码函数

Opcode 包含用于操作操作符名称标签和集合的函数。所有这些函数都可以由包导出。

opcodes

在标量上下文中,opcodes 返回此版本的 perl 中的操作码数量(对于 perl-5.7.0 约为 350 个)。

在列表上下文中,它返回所有操作符名称的列表。(尚未实现,请使用 @names = opset_to_ops(full_opset)。)

opset (OP, ...)

返回包含列出操作符的 opset。

opset_to_ops (OPSET)

返回与集合中这些操作符相对应的操作符名称列表。

opset_to_hex (OPSET)

返回 opset 的字符串表示形式。对于调试很有用。

full_opset

返回包含所有操作符的 opset。

empty_opset

返回不包含任何操作符的 opset。

invert_opset (OPSET)

返回与提供的 opset 相反的 opset。

verify_opset (OPSET, ...)

如果提供的 opset 看起来像一个有效的 opset(长度正确等),则返回 true,否则返回 false。如果可选的第二个参数为 true,则 verify_opset 将在无效的 opset 上 croak,而不是返回 false。

大多数其他 Opcode 函数会自动调用 verify_opset,如果给定无效的 opset,则会 croak。

define_optag (OPTAG, OPSET)

将 OPTAG 定义为 OPSET 的符号名称。Optag 名称始终以冒号:开头。

使用的 optag 名称必须尚未定义(如果已定义,define_optag 将 croak)。Optag 名称对 perl 进程是全局的,并且 optag 定义一旦定义就不能更改或删除。

强烈建议使用 Opcode 的应用程序在其标签名称上使用首字母大写,因为小写名称保留供 Opcode 模块使用。如果在模块中使用 Opcode,您应该在标签名称前加上模块名称以确保唯一性,从而避免与其他模块发生冲突。

opmask_add (OPSET)

将提供的 opset 添加到当前的 opmask。请注意,目前没有机制可以取消屏蔽操作,一旦它们被屏蔽。这是故意的。

opmask

返回与当前 opmask 对应的 opset。

opdesc (OP, ...)

这将获取一个运算符名称列表,并返回相应的运算符描述列表。

opdump (PAT)

将两列的运算符名称和运算符描述列表转储到 STDOUT。如果给出了可选模式,则只输出与(不区分大小写)模式匹配的行。

它被设计为一个方便的命令行实用程序

perl -MOpcode=opdump -e opdump
perl -MOpcode=opdump -e 'opdump Eval'

操作 Opsets

可以使用 perl 位向量运算符 &(与)、|(或)、^(异或)和 ~(否定/反转)来操作 Opsets。

但是,您永远不应该依赖任何 opcode 在 opset 中的数值位置。换句话说,位向量运算符的两侧都应该是从 Opcode 函数返回的 opset。

此外,由于您当前版本的 perl 中的 opcode 数量可能不是 8 的精确倍数,因此 opset 的最后一个字节中可能存在未使用的位。这不会造成任何问题(Opcode 函数会忽略这些额外的位),但这意味着使用 ~ 运算符通常不会产生与 invert_opset 函数相同的“物理”opset“字符串”。

待办事项(也许)

    $bool = opset_eq($opset1, $opset2)	true if opsets are logically
					equivalent
    $yes = opset_can($opset, @ops)	true if $opset has all @ops set

    @diff = opset_diff($opset1, $opset2) => ('foo', '!bar', ...)

预定义的 Opcode 标签

:base_core
    null stub scalar pushmark wantarray const defined undef

    rv2sv sassign padsv_store

    rv2av aassign aelem aelemfast aelemfast_lex aslice kvaslice
    av2arylen aelemfastlex_store

    rv2hv helem hslice kvhslice each values keys exists delete
    aeach akeys avalues multideref argelem argdefelem argcheck

    preinc i_preinc predec i_predec postinc i_postinc
    postdec i_postdec int hex oct abs pow multiply i_multiply
    divide i_divide modulo i_modulo add i_add subtract i_subtract

    left_shift right_shift bit_and bit_xor bit_or nbit_and
    nbit_xor nbit_or sbit_and sbit_xor sbit_or negate i_negate not
    complement ncomplement scomplement

    lt i_lt gt i_gt le i_le ge i_ge eq i_eq ne i_ne ncmp i_ncmp
    slt sgt sle sge seq sne scmp
    isa

    substr vec stringify study pos length index rindex ord chr

    ucfirst lcfirst uc lc fc quotemeta trans transr chop schop
    chomp schomp

    match split qr

    list lslice splice push pop shift unshift reverse

    cond_expr flip flop andassign orassign dorassign and or dor xor
    helemexistsor

    warn die lineseq nextstate scope enter leave

    rv2cv anoncode prototype coreargs avhvswitch anonconst
    emptyavhv

    entersub leavesub leavesublv return method method_named
    method_super method_redir method_redir_super
     -- XXX loops via recursion?

    cmpchain_and cmpchain_dup

    is_bool
    is_weak weaken unweaken

    leaveeval -- needed for Safe to operate, is safe
		 without entereval

    methstart initfield
:base_mem

这些与内存相关的操作未包含在 :base_core 中,因为它们很容易被用来实施资源攻击(例如,消耗所有可用内存)。

concat multiconcat repeat join range

anonlist anonhash

请注意,即使存在此 optag,仍然可以使用 :base_core 操作来实施内存资源攻击。

禁用这些操作是尝试阻止内存资源攻击的一种非常强硬的方法。在不久的将来,perl 中可能会添加一个特定的内存限制机制。

:base_loop

这些循环操作未包含在 :base_core 中,因为它们很容易被用来实施资源攻击(例如,消耗所有可用的 CPU 时间)。

grepstart grepwhile
mapstart mapwhile
enteriter iter
enterloop leaveloop unstack
last next redo
goto
:base_io

这些操作启用基于文件句柄(而不是文件名)的输入和输出。假设只有预先存在的文件句柄可用,这些操作是安全的。通常,要创建新的文件句柄,需要启用其他操作,例如 open,除非你考虑 ARGV 的神奇打开。

readline rcatline getc read

formline enterwrite leavewrite

print say sysread syswrite send recv

eof tell seek sysseek

readdir telldir seekdir rewinddir
:base_orig

这些是一些杂七杂八的 opcode,仍在等待考虑。

    gvsv gv gelem

    padsv padav padhv padcv padany padrange introcv clonecv

    once

    rv2gv refgen srefgen ref refassign lvref lvrefslice lvavref
    blessed refaddr reftype

    bless -- could be used to change ownership of objects
	     (reblessing)

     regcmaybe regcreset regcomp subst substcont

    sprintf prtf -- can core dump

    crypt

    tie untie

    dbmopen dbmclose
    sselect select
    pipe_op sockpair

    getppid getpgrp setpgrp getpriority setpriority
    localtime gmtime

    entertry leavetry -- can be used to 'hide' fatal errors
    entertrycatch poptry catch leavetrycatch -- similar

    entergiven leavegiven
    enterwhen leavewhen
    break continue
    smartmatch

    pushdefer

    custom -- where should this go

    ceil floor

    is_tainted
:base_math

这些操作未包含在 :base_core 中,因为它们存在被用来生成浮点异常的风险(这需要使用 $SIG{FPE} 处理程序来捕获)。

atan2 sin cos exp log sqrt

这些操作未包含在 :base_core 中,因为它们对隔室范围之外有影响。

rand srand
:base_thread

这些操作与多线程相关。

lock
:default

一个方便的标签名称,用于表示一组合理的默认操作。(当前允许的操作在开发过程中不稳定,将会改变。)

:base_core :base_mem :base_loop :base_orig :base_thread

在 Opcode 1.07 之前,此列表包含 :base_io。

如果你关心安全性(为什么你会使用 Opcode 模块?),那么你不应该依赖此定义,或者任何其他 optag 的定义!

:filesys_read
stat lstat readlink

ftatime ftblk ftchr ftctime ftdir fteexec fteowned
fteread ftewrite ftfile ftis ftlink ftmtime ftpipe
ftrexec ftrowned ftrread ftsgid ftsize ftsock ftsuid
fttty ftzero ftrwrite ftsvtx

fttext ftbinary

fileno
:sys_db
ghbyname ghbyaddr ghostent shostent ehostent      -- hosts
gnbyname gnbyaddr gnetent snetent enetent         -- networks
gpbyname gpbynumber gprotoent sprotoent eprotoent -- protocols
gsbyname gsbyport gservent sservent eservent      -- services

gpwnam gpwuid gpwent spwent epwent getlogin       -- users
ggrnam ggrgid ggrent sgrent egrent                -- groups
:browse

一个方便的标签名称,用于表示除 :default optag 之外的合理默认操作集。与 :default(以及所有其他 optag)一样,其当前定义在开发过程中不稳定,将会发生变化。

:browse 标签代表着比 :default 更进一步。它是 :default 操作的超集,并添加了 :filesys_read 和 :sys_db。其目的是让脚本可以访问更多(可能敏感)的系统信息,但不能更改系统。

:default :filesys_read :sys_db
:filesys_open
sysopen open close
umask binmode

open_dir closedir -- other dir ops are in :base_io
:filesys_write
    link unlink rename symlink truncate

    mkdir rmdir

    utime chmod chown

    fcntl -- not strictly filesys related, but possibly as
	     dangerous?
:subprocess
backtick system

fork

wait waitpid

glob -- access to Cshell via <`rm *`>
:ownprocess
exec exit kill

time tms -- could be used for timing attacks (paranoid?)
:others

此标签包含各种专业操作码的组,这些操作码不值得为它们定义 optag。

SystemV 进程间通信

msgctl msgget msgrcv msgsnd

semctl semget semop

shmctl shmget shmread shmwrite
:load

此标签包含与加载模块以及获取有关调用环境和参数的信息相关的操作码。

require dofile 
caller runcv
:still_to_be_decided
chdir
flock ioctl

socket getpeername ssockopt
bind connect listen accept shutdown gsockopt getsockname

sleep alarm -- changes global timer state and signal handling
sort -- assorted problems including core dumps
tied -- can be used to access object implementing a tie
pack unpack -- can be used to create/use memory pointers

hintseval -- constant op holding eval hints

entereval -- can be used to hide code from initial compile

reset

dbstate -- perl -d version of nextstate(ment) opcode
:dangerous

此标签只是一个用于操作码的容器,这些操作码不太可能通过标签名称使用,但需要标记以确保完整性和文档。

syscall dump chroot

另请参阅

ops -- perl 针对 Opcode 模块的 pragma 接口。

Safe -- 操作码和命名空间受限的执行隔间

作者

最初由 Malcolm Beattie ([email protected]) 设计和实现,作为 Safe 版本 1 的一部分。

从 Safe 模块版本 1 中分离出来,由 Tim Bunce 添加了操作码标签和其他更改。