Executable space protection: NX bit,

Rationale ========= - Separation of executable code and non-executable data is a good thing. - Additional security in Python is a good idea. - Python should support things like the NX bit to separate code and non-executable data. Discussion ========== How could Python implement support for the NX bit? (And/or additional modern security measures; as appropriate). What sort of an API would C extensions need? Would this be easier in PyPy or in CPython? - https://en.wikipedia.org/wiki/NX_bit - https://en.wikipedia.org/wiki/Executable_space_protection Here's one way to identify whether an executable supports NX: https://github.com/longld/peda/blob/e0eb0af4bcf3ee/peda.py#L2543

I'm not a security expert, but I believe the NX bit is a hardware protection against a specific class of attack: buffer overflow attacks. These attacks are possible because of the lack of safety in the C programming language: it is very easy for a programmer to forget to check the bounds of a receiving buffer, properly, and sometimes data copied from the network receives machine code. Or the stack is overwritten with the return address pointing to some machine code previously injected. Python is intrinsically a safer programming language and requires no such hardware protection. At most, a C library used by a Python extension can still have such bugs, but then again the OS already sets the NX bit for data segments anyway, so Python doesn't need to do anything. On Mon, 3 Sep 2018 at 08:00, Wes Turner <wes.turner@gmail.com> wrote:
-- Gustavo J. A. M. Carneiro Gambit Research "The universe is always one step beyond logic." -- Frank Herbert

Wes Turner wrote
When I saw this, I thought at first it was about preventing tricks such as def ask_save(): print('Save all files?') def ask_delete(): print('Delete all files?') >>> ask_save() Save all files? >>> ask_delete() Delete all files? # Evil code! ask_delete.__code__, ask_save.__code__ = ask_save.__code__, ask_delete.__code__ >>> ask_save() Delete all files? >>> ask_delete() Save all files? Any code that can directly call fn() and gn() can play this trick! -- Jonathan

On 03Sep2018 20:58, Wes Turner <wes.turner@gmail.com> wrote:
So, if an application accepts user-supplied input (such as a JSON payload), is that data marked as non-executable?
Unless you've hacked the JSON decoder (I think you can supply a custom decoder for some things) all you're doing to get back is ints, strs, dicts and lists. And floats. None of those is executable. Cheers, Cameron Simpson <cs@cskk.id.au>

This might be a bit off-topic. It's about the dangers of yaml.load. Cameron Simpson and Steve D'Aprano wrote
So, if an application accepts user-supplied input (such as a JSON payload), is that data marked as non-executable?
It's note the same with YAML. At last year's PyCon UK I went to Rae Knowler's talk about bad defaults. https://2017.pyconuk.org/sessions/keynotes/unsafe-at-any-speed/ https://speakerdeck.com/bellisk/unsafe-at-any-speed-pycon-uk-26th-october-20... and saw, in a nutshell (slide 21) yaml.load is the obvious function to use but it is dangerous https://security.openstack.org/guidelines/dg_avoid-dangerous-input-parsing-l... Rae's talk also mentioned (slides 19 and 20) Enabling certificate verification by default for stdlib http clients https://www.python.org/dev/peps/pep-0476/ Following Rae, I consider the using name *yaml.load* for the *unsafe* load is already a security flaw! -- Jonathan

Hey Wes, the checksec() function in PEDA that you cited has a standalone version as well: https://github.com/slimm609/checksec.sh Running this on my Python (installed from Ubuntu package): $ checksec --output json -f /usr/bin/python3.6 | python3 -m json.tool { "file": { "relro": "partial", "canary": "yes", "nx": "yes", "pie": "no", "rpath": "no", "runpath": "no", "fortify_source": "yes", "fortified": "17", "fortify-able": "41", "filename": "/usr/bin/python3.6" } } My Python has pretty typical security mitigations. Most of these features are determined at compile time, so you can try compiling Python yourself with different compiler flags and see what other configurations are possible. Some mitigations hurt performance and others may be incompatible with Python itself. If you search on bugs.python.org you'll find a few different issues on these topics. On Mon, Sep 3, 2018 at 3:01 AM Wes Turner <wes.turner@gmail.com> wrote:

There is no need to panic, though, because, as @tylerl points out,
What about ` -mindirect-branch=thunk -mindirect-branch-register `? Thanks! Looks like NX is on by default A quick search of the codebase doesn't find any mprotect() calls, so I'm assuming it's just the compiler flags defaulting to NX on for the main stack. This answer helped me understand a bit more; I'll take a look at the issue tracker as well: threads of the applications, simply by using a rarely used but legitimate and documented feature of GCC. protection afforded by the NX bit is not that great. It will make some exploits more awkward for the least competent of attackers; but good attackers will not be impeded. https://security.stackexchange.com/a/47825 So, a C extension with a nested function (e.g. a trampoline) causes the NX bit to be off? retpoline is a trampoline approach *partially mitigating* the Spectre (but not Meltdown?) vulns, right? https://security.googleblog.com/2018/01/more-details-about-mitigations-for-c... "What is a retpoline and how does it work?" https://stackoverflow.com/a/48099456 https://github.com/speed47/spectre-meltdown-checker/issues/119
mindirect-branch=thunk -mindirect-branch-register
Here's a helpful table of the 'Speculative execution exploit variants' discovered as of yet: https://en.wikipedia.org/wiki/Speculative_Store_Bypass#Speculative_execution... Everything built - including the kernel - needs to be recompiled with new thunk switches, AFAIU? How can we tell whether a python binary or C extension has been rebuilt with which appropriate compiler flags? On Tuesday, September 4, 2018, Mark E. Haase <mehaase@gmail.com> wrote:

I'm not a security expert, but I believe the NX bit is a hardware protection against a specific class of attack: buffer overflow attacks. These attacks are possible because of the lack of safety in the C programming language: it is very easy for a programmer to forget to check the bounds of a receiving buffer, properly, and sometimes data copied from the network receives machine code. Or the stack is overwritten with the return address pointing to some machine code previously injected. Python is intrinsically a safer programming language and requires no such hardware protection. At most, a C library used by a Python extension can still have such bugs, but then again the OS already sets the NX bit for data segments anyway, so Python doesn't need to do anything. On Mon, 3 Sep 2018 at 08:00, Wes Turner <wes.turner@gmail.com> wrote:
-- Gustavo J. A. M. Carneiro Gambit Research "The universe is always one step beyond logic." -- Frank Herbert

Wes Turner wrote
When I saw this, I thought at first it was about preventing tricks such as def ask_save(): print('Save all files?') def ask_delete(): print('Delete all files?') >>> ask_save() Save all files? >>> ask_delete() Delete all files? # Evil code! ask_delete.__code__, ask_save.__code__ = ask_save.__code__, ask_delete.__code__ >>> ask_save() Delete all files? >>> ask_delete() Save all files? Any code that can directly call fn() and gn() can play this trick! -- Jonathan

On 03Sep2018 20:58, Wes Turner <wes.turner@gmail.com> wrote:
So, if an application accepts user-supplied input (such as a JSON payload), is that data marked as non-executable?
Unless you've hacked the JSON decoder (I think you can supply a custom decoder for some things) all you're doing to get back is ints, strs, dicts and lists. And floats. None of those is executable. Cheers, Cameron Simpson <cs@cskk.id.au>

This might be a bit off-topic. It's about the dangers of yaml.load. Cameron Simpson and Steve D'Aprano wrote
So, if an application accepts user-supplied input (such as a JSON payload), is that data marked as non-executable?
It's note the same with YAML. At last year's PyCon UK I went to Rae Knowler's talk about bad defaults. https://2017.pyconuk.org/sessions/keynotes/unsafe-at-any-speed/ https://speakerdeck.com/bellisk/unsafe-at-any-speed-pycon-uk-26th-october-20... and saw, in a nutshell (slide 21) yaml.load is the obvious function to use but it is dangerous https://security.openstack.org/guidelines/dg_avoid-dangerous-input-parsing-l... Rae's talk also mentioned (slides 19 and 20) Enabling certificate verification by default for stdlib http clients https://www.python.org/dev/peps/pep-0476/ Following Rae, I consider the using name *yaml.load* for the *unsafe* load is already a security flaw! -- Jonathan

Hey Wes, the checksec() function in PEDA that you cited has a standalone version as well: https://github.com/slimm609/checksec.sh Running this on my Python (installed from Ubuntu package): $ checksec --output json -f /usr/bin/python3.6 | python3 -m json.tool { "file": { "relro": "partial", "canary": "yes", "nx": "yes", "pie": "no", "rpath": "no", "runpath": "no", "fortify_source": "yes", "fortified": "17", "fortify-able": "41", "filename": "/usr/bin/python3.6" } } My Python has pretty typical security mitigations. Most of these features are determined at compile time, so you can try compiling Python yourself with different compiler flags and see what other configurations are possible. Some mitigations hurt performance and others may be incompatible with Python itself. If you search on bugs.python.org you'll find a few different issues on these topics. On Mon, Sep 3, 2018 at 3:01 AM Wes Turner <wes.turner@gmail.com> wrote:

There is no need to panic, though, because, as @tylerl points out,
What about ` -mindirect-branch=thunk -mindirect-branch-register `? Thanks! Looks like NX is on by default A quick search of the codebase doesn't find any mprotect() calls, so I'm assuming it's just the compiler flags defaulting to NX on for the main stack. This answer helped me understand a bit more; I'll take a look at the issue tracker as well: threads of the applications, simply by using a rarely used but legitimate and documented feature of GCC. protection afforded by the NX bit is not that great. It will make some exploits more awkward for the least competent of attackers; but good attackers will not be impeded. https://security.stackexchange.com/a/47825 So, a C extension with a nested function (e.g. a trampoline) causes the NX bit to be off? retpoline is a trampoline approach *partially mitigating* the Spectre (but not Meltdown?) vulns, right? https://security.googleblog.com/2018/01/more-details-about-mitigations-for-c... "What is a retpoline and how does it work?" https://stackoverflow.com/a/48099456 https://github.com/speed47/spectre-meltdown-checker/issues/119
mindirect-branch=thunk -mindirect-branch-register
Here's a helpful table of the 'Speculative execution exploit variants' discovered as of yet: https://en.wikipedia.org/wiki/Speculative_Store_Bypass#Speculative_execution... Everything built - including the kernel - needs to be recompiled with new thunk switches, AFAIU? How can we tell whether a python binary or C extension has been rebuilt with which appropriate compiler flags? On Tuesday, September 4, 2018, Mark E. Haase <mehaase@gmail.com> wrote:
participants (8)
-
Cameron Simpson
-
Greg Ewing
-
Gustavo Carneiro
-
Jonathan Fine
-
Mark E. Haase
-
Stephan Houben
-
Steven D'Aprano
-
Wes Turner