Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opcode LIST_EXTEND not allowed #1734

Closed
magras opened this issue Dec 2, 2020 · 2 comments · Fixed by #1735
Closed

opcode LIST_EXTEND not allowed #1734

magras opened this issue Dec 2, 2020 · 2 comments · Fixed by #1735

Comments

@magras
Copy link
Contributor

magras commented Dec 2, 2020

Python 3.9.0 brings new opcode LIST_EXTEND, which leads to an error during pwn import:

$ cat ~/.pwn.conf
[context]
terminal = ['alacritty', '-e', 'sh', '-c']
$ ipython
Python 3.9.0 (default, Oct  7 2020, 23:09:01)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pwn
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-85301d96339b> in <module>
----> 1 import pwn

~/src/pwntools/pwn/toplevel.py in <module>
      6 pwnlib.args.initialize()
      7 pwnlib.log.install_default_handler()
----> 8 pwnlib.config.initialize()
      9
     10 log = pwnlib.log.getLogger('pwnlib.exploit')

~/src/pwntools/pwnlib/config.py in initialize()
     62             continue
     63         settings = dict(c.items(section))
---> 64         registered_configs[section](settings)

~/src/pwntools/pwnlib/context/__init__.py in update_context_defaults(section)
   1491
   1492         if isinstance(default, six.string_types + six.integer_types + (tuple, list, dict)):
-> 1493             value = safeeval.expr(value)
   1494         else:
   1495             log.warn("Unsupported configuration option %r in section %r" % (key, 'context'))

~/src/pwntools/pwnlib/util/safeeval.py in expr(expr)
    109     """
    110
--> 111     c = test_expr(expr, _expr_codes)
    112     return eval(c)
    113

~/src/pwntools/pwnlib/util/safeeval.py in test_expr(expr, allowed_codes)
     61     for code in codes:
     62         if code not in allowed_codes:
---> 63             raise ValueError("opcode %s not allowed" % dis.opname[code])
     64     return c
     65

ValueError: opcode LIST_EXTEND not allowed

Adding 'LIST_EXTEND' to _const_codes or _expr_codes seems to solve the issue, but I'm not familiar with this code.

Also, there are more new opcodes: LIST_TO_TUPLE, SET_UPDATE, etc.

@magras
Copy link
Contributor Author

magras commented Dec 2, 2020

Python 3.8.6 (default, Nov 18 2020, 13:49:49)

>>> pprint(list(dis.get_instructions(compile("[1,2,3]", "", "eval"))))
[Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=1, argrepr='1', offset=0, starts_line=1, is_jump_target=False),
 Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=2, argrepr='2', offset=2, starts_line=None, is_jump_target=False),
 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=3, argrepr='3', offset=4, starts_line=None, is_jump_target=False),
 Instruction(opname='BUILD_LIST', opcode=103, arg=3, argval=3, argrepr='', offset=6, starts_line=None, is_jump_target=False),
 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=8, starts_line=None, is_jump_target=False)]

Python 3.9.0 (default, Nov 18 2020, 13:28:38)

>>> pprint(list(dis.get_instructions(compile("[1,2]", "", "eval"))))
[Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=1, argrepr='1', offset=0, starts_line=1, is_jump_target=False),
 Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=2, argrepr='2', offset=2, starts_line=None, is_jump_target=False),
 Instruction(opname='BUILD_LIST', opcode=103, arg=2, argval=2, argrepr='', offset=4, starts_line=None, is_jump_target=False),
 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False)]
>>> pprint(list(dis.get_instructions(compile("[1,2,3]", "", "eval"))))
[Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False),
 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=(1, 2, 3), argrepr='(1, 2, 3)', offset=2, starts_line=None, is_jump_target=False),
 Instruction(opname='LIST_EXTEND', opcode=162, arg=1, argval=1, argrepr='', offset=4, starts_line=None, is_jump_target=False),
 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False)]

@magras
Copy link
Contributor Author

magras commented Dec 2, 2020

I'm not a security expert and python is my secondary language, but at first glance, LIST_EXTEND is currently generated by cpython compiler only to declare a list, a tuple, and to call a function. However, virtual machine is happy to modify an existing list using LIST_EXTEND if bytecode requests it.

So I'm not sure which direction to take. To name a few:

  • Add LIST_EXTEND to _expr_codes. It can violate safe evaluation promise in the future.
  • Look for other ways to guarantee safe evaluation.
  • Use unsafe evaluation for config. Actually, I did not check where safe evaluation used and what parts of pwntools can be affected by this issue.
  • Probably other ways that I do not see.

Arusekk added a commit to Arusekk/pwntools that referenced this issue Dec 2, 2020
Arusekk added a commit that referenced this issue Dec 7, 2020
* Add cpython 3.9 constant opcodes to safeeval

Closes #1734

* Update CHANGELOG.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant