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 函数可用于返回运算符列表的描述列表。
下面列出的许多函数和方法都将运算符列表作为参数。大多数运算符列表可以由几种类型的元素组成。每个元素可以是以下之一
运算符名称通常是像 enterloop、leaveloop、last、next、redo 等小写单词。有时它们相当隐晦,例如 gv2cv、i_ncmp 和 ftsvtx。
运算符标签可用于引用运算符组(或集)。标签名称始终以冒号开头。Opcode 模块定义了几个 optag,用户可以使用 define_optag 函数定义其他 optag。
opname 或 optag 可以以感叹号为前缀,例如,!mkdir。否定 opname 或 optag 表示从该点的累积操作集中删除相应的操作。
一个opset 是一个大约 44 字节的二进制字符串,它包含一组或零个或多个操作符。
opset 和 opset_to_ops 函数可用于将操作符列表转换为 opset,反之亦然。
在可以给出操作符列表的任何地方,都可以使用一个或多个 opset。另请参阅下文中的操作 opset。
Opcode 包含用于操作操作符名称标签和集合的函数。所有这些函数都可以由包导出。
在标量上下文中,opcodes 返回此版本的 perl 中的操作码数量(对于 perl-5.7.0 约为 350 个)。
在列表上下文中,它返回所有操作符名称的列表。(尚未实现,请使用 @names = opset_to_ops(full_opset)。)
返回包含列出操作符的 opset。
返回与集合中这些操作符相对应的操作符名称列表。
返回 opset 的字符串表示形式。对于调试很有用。
返回包含所有操作符的 opset。
返回不包含任何操作符的 opset。
返回与提供的 opset 相反的 opset。
如果提供的 opset 看起来像一个有效的 opset(长度正确等),则返回 true,否则返回 false。如果可选的第二个参数为 true,则 verify_opset 将在无效的 opset 上 croak,而不是返回 false。
大多数其他 Opcode 函数会自动调用 verify_opset,如果给定无效的 opset,则会 croak。
将 OPTAG 定义为 OPSET 的符号名称。Optag 名称始终以冒号:
开头。
使用的 optag 名称必须尚未定义(如果已定义,define_optag 将 croak)。Optag 名称对 perl 进程是全局的,并且 optag 定义一旦定义就不能更改或删除。
强烈建议使用 Opcode 的应用程序在其标签名称上使用首字母大写,因为小写名称保留供 Opcode 模块使用。如果在模块中使用 Opcode,您应该在标签名称前加上模块名称以确保唯一性,从而避免与其他模块发生冲突。
将提供的 opset 添加到当前的 opmask。请注意,目前没有机制可以取消屏蔽操作,一旦它们被屏蔽。这是故意的。
返回与当前 opmask 对应的 opset。
这将获取一个运算符名称列表,并返回相应的运算符描述列表。
将两列的运算符名称和运算符描述列表转储到 STDOUT。如果给出了可选模式,则只输出与(不区分大小写)模式匹配的行。
它被设计为一个方便的命令行实用程序
perl -MOpcode=opdump -e opdump
perl -MOpcode=opdump -e 'opdump Eval'
可以使用 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', ...)
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_core 中,因为它们很容易被用来实施资源攻击(例如,消耗所有可用内存)。
concat multiconcat repeat join range
anonlist anonhash
请注意,即使存在此 optag,仍然可以使用 :base_core 操作来实施内存资源攻击。
禁用这些操作是尝试阻止内存资源攻击的一种非常强硬的方法。在不久的将来,perl 中可能会添加一个特定的内存限制机制。
这些循环操作未包含在 :base_core 中,因为它们很容易被用来实施资源攻击(例如,消耗所有可用的 CPU 时间)。
grepstart grepwhile
mapstart mapwhile
enteriter iter
enterloop leaveloop unstack
last next redo
goto
这些操作启用基于文件句柄(而不是文件名)的输入和输出。假设只有预先存在的文件句柄可用,这些操作是安全的。通常,要创建新的文件句柄,需要启用其他操作,例如 open,除非你考虑 ARGV 的神奇打开。
readline rcatline getc read
formline enterwrite leavewrite
print say sysread syswrite send recv
eof tell seek sysseek
readdir telldir seekdir rewinddir
这些是一些杂七杂八的 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_core 中,因为它们存在被用来生成浮点异常的风险(这需要使用 $SIG{FPE} 处理程序来捕获)。
atan2 sin cos exp log sqrt
这些操作未包含在 :base_core 中,因为它们对隔室范围之外有影响。
rand srand
这些操作与多线程相关。
lock
一个方便的标签名称,用于表示一组合理的默认操作。(当前允许的操作在开发过程中不稳定,将会改变。)
:base_core :base_mem :base_loop :base_orig :base_thread
在 Opcode 1.07 之前,此列表包含 :base_io。
如果你关心安全性(为什么你会使用 Opcode 模块?),那么你不应该依赖此定义,或者任何其他 optag 的定义!
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
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
一个方便的标签名称,用于表示除 :default optag 之外的合理默认操作集。与 :default(以及所有其他 optag)一样,其当前定义在开发过程中不稳定,将会发生变化。
:browse 标签代表着比 :default 更进一步。它是 :default 操作的超集,并添加了 :filesys_read 和 :sys_db。其目的是让脚本可以访问更多(可能敏感)的系统信息,但不能更改系统。
:default :filesys_read :sys_db
sysopen open close
umask binmode
open_dir closedir -- other dir ops are in :base_io
link unlink rename symlink truncate
mkdir rmdir
utime chmod chown
fcntl -- not strictly filesys related, but possibly as
dangerous?
backtick system
fork
wait waitpid
glob -- access to Cshell via <`rm *`>
exec exit kill
time tms -- could be used for timing attacks (paranoid?)
此标签包含各种专业操作码的组,这些操作码不值得为它们定义 optag。
SystemV 进程间通信
msgctl msgget msgrcv msgsnd
semctl semget semop
shmctl shmget shmread shmwrite
此标签包含与加载模块以及获取有关调用环境和参数的信息相关的操作码。
require dofile
caller runcv
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
此标签只是一个用于操作码的容器,这些操作码不太可能通过标签名称使用,但需要标记以确保完整性和文档。
syscall dump chroot
ops -- perl 针对 Opcode 模块的 pragma 接口。
Safe -- 操作码和命名空间受限的执行隔间
最初由 Malcolm Beattie ([email protected]) 设计和实现,作为 Safe 版本 1 的一部分。
从 Safe 模块版本 1 中分离出来,由 Tim Bunce 添加了操作码标签和其他更改。