Live data from Hacker News

Make CPython segfault in 5 lines of code

gist.github.com

21–30 of 78 posts

Re: Make CPython segfault in 5 lines of code

#21
post #3

A quick search in bugs.python.org shows several crashes. I don’t know much about Python. Is there anything particularly special about this one?

Not necessarily, but I just found it interesting that it wasn't really anything all that crazy - it could in theory be possible to encounter this in a big enough code base that makes heavy use of coroutines and custom exception types.

It is crazy to have a class constructor return something that isn't an instance of the class. That's nonsense code and is unlikely to occur in a codebase of any size, regardless of how often they define custom exception types.

I wouldn't have bothered filing the bug.

Re: Make CPython segfault in 5 lines of code

#22
post #17

Segfaults in scripting languages are remarkably common, especially if arbitrary bytecode can be loaded into the VM. One I ran into in the wild recently is that in older versions of Lua, exceptions in GC finalizers (the `__gc` metamethod) can trigger a segfault. In those same versions of Lua, the bytecode format is notoriously dangerous to load. I wonder whether this will be a large component of newer scripting langua…

> Segfaults in scripting languages are remarkably common What about Javascript running on V8?

V8 is not immune to memory corruption.

Re: Make CPython segfault in 5 lines of code

#23
post #15

Earlier quoted context omitted.

The problem isn't the segfault -- it's the earlier unsafe behavior. That is, the untrapped error that eventually caused the segfault. If the language only has trapped errors, which are indicated by seg faults, it's a safe language. Every language has such errors. What does divide by zero do? What does blowing the stack / infinite recursion do in Rust? It seg faults. The seg fault is the safe behavior. If the stack ov…

> What does divide by zero do? Returns a value, of course! (And that said, JavaScript does have some trapped errors, such as (1/0).foo.foo (and yes you need the second .foo…)) IMO, the execution "error" here (in this thread) is accessing memory illegally. Sometimes the runtime traps it, but sometimes it does not, and "sometimes" isn't always, so its effectively untrapped as we cannot depend on the trap. (Especially i…

> such as (1/0).foo.foo (and yes you need the second .foo…)

I don't understand the nuance here. In my Firefox developer tools, I can do the following:

> (1/0).foo.foo

---> TypeError: (intermediate value).foo is undefined

> (1/0).foo

---> undefined

> (1/1).foo.foo

---> TypeError: 1.foo is undefined

> Infinity.foo.foo

---> TypeError: Infinity.foo is undefined

> undefined.foo

---> TypeError: undefined has no properties

While these are all different errors, I don't really understand why the '(1/0).foo.foo' case is an example of a _trapped_ error, but the others are not.

Re: Make CPython segfault in 5 lines of code

#24
post #17

Segfaults in scripting languages are remarkably common, especially if arbitrary bytecode can be loaded into the VM. One I ran into in the wild recently is that in older versions of Lua, exceptions in GC finalizers (the `__gc` metamethod) can trigger a segfault. In those same versions of Lua, the bytecode format is notoriously dangerous to load. I wonder whether this will be a large component of newer scripting langua…

> Segfaults in scripting languages are remarkably common What about Javascript running on V8?

omfg. seriously?!!

Re: Make CPython segfault in 5 lines of code

#26

This would not have happened in a language with a proper type system as the type checker would have rejected the program at compile time.

Type confusion and memory corruption is still possible in statically-typed languages, generally due to bugs in the runtime.

Re: Make CPython segfault in 5 lines of code

#27
post #21

Earlier quoted context omitted.

Not necessarily, but I just found it interesting that it wasn't really anything all that crazy - it could in theory be possible to encounter this in a big enough code base that makes heavy use of coroutines and custom exception types.

It is crazy to have a class constructor return something that isn't an instance of the class. That's nonsense code and is unlikely to occur in a codebase of any size, regardless of how often they define custom exception types. I wouldn't have bothered filing the bug.

The Python interpreter should not segfault for this.

Re: Make CPython segfault in 5 lines of code

#28
post #15

Earlier quoted context omitted.

The problem isn't the segfault -- it's the earlier unsafe behavior. That is, the untrapped error that eventually caused the segfault. If the language only has trapped errors, which are indicated by seg faults, it's a safe language. Every language has such errors. What does divide by zero do? What does blowing the stack / infinite recursion do in Rust? It seg faults. The seg fault is the safe behavior. If the stack ov…

> What does divide by zero do? Returns a value, of course! (And that said, JavaScript does have some trapped errors, such as (1/0).foo.foo (and yes you need the second .foo…)) IMO, the execution "error" here (in this thread) is accessing memory illegally. Sometimes the runtime traps it, but sometimes it does not, and "sometimes" isn't always, so its effectively untrapped as we cannot depend on the trap. (Especially i…

> Somewhat interestingly, it detects it and SIGABRTs, which technically isn't a segfault. And that's now some black magic that I'm curious about as I really thought it would have segfaulted.

It's a signal handler, of course: https://github.com/rust-lang/rust/blob/d8bdb3fdcbd88eb16e1a6...

Re: Make CPython segfault in 5 lines of code

#29

If # of lines are important, this problem can actually be demonstrated in 1 line: for x, x.__new__ in [(__import__('queue').Full, print)]: __import__('glob').iglob(0).throw(x)

This doesn't trigger a segfault for me in Python 3.7, just an exception that `print_exception` expects an `Exception`.

Someone commented below the gist with this one-liner:

    (i for i in []).throw(type('E', (BaseException,), dict(__new__=lambda cls, *args: cls))())
I managed to golf it a bit down to this ;):

    n="__new__";(i for i in []).throw(type(n,(IOError,),{n:lambda c,*a:c})())

Re: Make CPython segfault in 5 lines of code

#30
post #18

Segfaults in scripting languages are remarkably common, especially if arbitrary bytecode can be loaded into the VM. One I ran into in the wild recently is that in older versions of Lua, exceptions in GC finalizers (the `__gc` metamethod) can trigger a segfault. In those same versions of Lua, the bytecode format is notoriously dangerous to load. I wonder whether this will be a large component of newer scripting langua…

Is anybody fuzzing Python bytecodes? This sounds like a super-great application for afl.

It has always been the position of the CPython developers that using python for sandboxing is unsupported. With that in mind it doesn't really matter if you can "exploit" python with weird bytecode because you are supposed to be on the other side of the airtight hatchway[0] anyways.

I don't know what the stance of other python runtimes are, but you should probably just use a sandbox at OS level which is likely to be tested far more thoroughly.

[0]: https://devblogs.microsoft.com/oldnewthing/20060508-22/?p=31...

Post reply on HN