目錄

名稱

Opcode - 編譯 Perl 程式碼時停用指定 opcode

語法

use Opcode;

說明

Perl 程式碼在執行前會先編譯成內部格式。

評估 Perl 程式碼(例如透過「eval」或「do 'file'」)會導致程式碼編譯成內部格式,然後在編譯過程中沒有錯誤時執行。內部格式基於許多不同的操作碼

預設情況下,沒有任何操作碼遮罩生效,任何程式碼都可以編譯。

Opcode 模組允許您定義運算子遮罩,以便在 Perl 接下來編譯任何程式碼時生效。嘗試編譯包含遮罩操作碼的程式碼將導致編譯失敗並顯示錯誤。程式碼不會執行。

注意

Opcode 模組通常不會直接使用。請參閱 ops 實用程式和 Safe 模組以了解更典型的用法。

警告

Opcode 模組不會實作有效沙箱,無法使用 Perl 解譯器評估不受信任的程式碼。

可以濫用以繞過 Opcode 限制的 Perl 解譯器錯誤不會被視為漏洞。請參閱 perlsecpolicy 以取得更多資訊。

作者對本軟體是否適用於安全目的不提供任何保證,無論明示或暗示。

在任何情況下,作者都不應對因使用本軟體而產生的特殊、附帶、後果性、間接或其他類似損害負責。

您的使用情況可能有所不同。如有任何疑慮,請勿使用

運算子名稱和運算子清單

運算子名稱的正規清單是陣列 PL_op_name 的內容,此陣列定義並初始化在 Perl 原始碼發行版的檔案 opcode.h 中(並安裝到 Perl 函式庫中)。

每個運算子都有簡潔的名稱(其 opname)和更詳細或可辨識的描述性名稱。opdesc 函式可用於傳回運算子清單的描述清單。

下列列出的許多函數和方法會將運算子清單作為參數。大多數運算子清單都可以由數種元素類型組成。每個元素可以為下列之一

運算子名稱 (opname)

運算子名稱通常是小寫單字,例如 enterloop、leaveloop、last、next、redo 等。有時它們相當難懂,例如 gv2cv、i_ncmp 和 ftsvtx。

運算子標籤名稱 (optag)

運算子標籤可用於指稱運算子群組 (或集合)。標籤名稱總是從冒號開始。Opcode 模組定義了數個 optag,而使用者可以使用 define_optag 函數定義其他 optag。

否定運算子名稱或標籤

運算子名稱或標籤可以加上驚嘆號為前綴,例如 !mkdir。否定運算子名稱或標籤表示移除對應的運算子,使其不在該點累積的運算子集合中。

運算子集合 (opset)

opset 是一個二進位字串,約有 44 個位元組,其中包含一個集合或零個或更多個運算子。

opset 和 opset_to_ops 函數可用於將運算子清單轉換為 opset,反之亦然

只要可以提供運算子清單,就可以使用一個或多個 opset。另請參閱下方的「操作 Opset」。

Opcode 函數

Opcode 套件包含用於操作運算子名稱、標籤和集合的函數。所有函數都可供套件匯出。

opcodes

在標量內容中,opcodes 會傳回此 perl 版本中的 opcode 數量(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。

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 會出錯)。Optag 名稱是 Perl 程序的全局變數,一旦定義,optag 定義就不能更改或刪除。

強烈建議使用 Opcode 的應用程式在標籤名稱上使用開頭大寫字母,因為小寫名稱是保留給 Opcode 模組使用的。如果在模組中使用 Opcode,您應該在標籤名稱前面加上模組名稱,以確保唯一性,從而避免與其他模組發生衝突。

opmask_add (OPSET)

將提供的 opset 加入目前的 opmask。請注意,目前沒有機制可以在遮罩 ops 之後取消遮罩。這是故意的。

opmask

傳回與目前的 opmask 相應的 opset。

opdesc (OP, ...)

這會取得一個運算子名稱清單,並傳回對應的運算子描述清單。

opdump (PAT)

將 op 名稱和 op 描述的兩欄清單傾印到 STDOUT。如果給定一個選用樣式,則只會輸出與(不區分大小寫)樣式相符的行。

它被設計為一個方便的命令列工具

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

Manipulating Opsets

Opsets 可以使用 Perl 位元向量運算子 &(and)、|(or)、^(xor)和 ~(negate/invert)進行操作。

但是,您永遠不應該依賴 opset 中任何 opcode 的數字位置。換句話說,位元向量運算子的兩邊都應該是從 Opcode 函數傳回的 opsets。

此外,由於您目前 Perl 版本中的 opcode 數量可能不是 8 的倍數,因此 opset 的最後一個位元組中可能會有未使用的位元。這不應該造成任何問題(Opcode 函數會忽略這些額外的位元),但這表示使用 ~ 運算子通常不會產生與 invert_opset 函數相同的「實體」opset「字串」。

TO DO (maybe)

    $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', ...)

預定義操作碼標籤

: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

請注意,儘管有這個運算子標籤,但僅使用 :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 的神奇 open。

readline rcatline getc read

formline enterwrite leavewrite

print say sysread syswrite send recv

eof tell seek sysseek

readdir telldir seekdir rewinddir
:base_orig

這些是一堆仍等待考慮的運算子

    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 之外,一個合理預設 ops 集合的便利標籤名稱。與 :default(以及所有其他 optag)一樣,其目前的定義在開發過程中是不穩定的。它會改變。

:browse 標籤代表超越 :default 的下一步。它是 :default ops 的超集,並新增 :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

此標籤包含各種專門 opcode 的群組,不值得為它們定義 optag。

SystemV 跨處理通訊

msgctl msgget msgrcv msgsnd

semctl semget semop

shmctl shmget shmread shmwrite
:load

此標籤包含與載入模組和取得呼叫環境和參數相關的 opcode。

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

此標籤只是一個儲存桶,用於不太可能透過標籤名稱使用,但需要標記以完整性和文件記錄的 opcode。

syscall dump chroot

另請參閱

ops -- perl pragma 介面至 Opcode 模組。

Safe -- opcode 和命名空間限制的執行區隔

作者

最初由 Malcolm Beattie 設計和實作,mbeattie@sable.ox.ac.uk,作為 Safe 1 版的一部分。

從 Safe 模組 1 版中拆分出來,命名 opcode 標籤和其他變更由 Tim Bunce 新增。