On Thu, Feb 11, 2021 at 9:44 PM Michał Górny <mgo...@gentoo.org> wrote:
> I feel that vulnerability fixes do not make it to end users fast enough.

I think that it's time to put that into perspective with past vulnerabilities.

Ok, let me look at the timeline of the discussed vulnerability, ctypes
CVE-2021-3177:
https://python-security.readthedocs.io/vuln/ctypes-buffer-overflow-pycarg_repr.html

    2021-01-16: Python issue bpo-42938 reported by Jordy Zomer
    ...
    2021-01-18 (+2 days): commit c347cbe (branch 3.9)
    2021-01-18 (+2 days): commit ece5dfd (branch 3.8)
    2021-01-19 (+3 days): CVE-2021-3177 published
    ...
    2021-02-19 (+34 days): Python 3.8.8 released
    2021-02-19 (+34 days): Python 3.9.2 released

Ok. What about vulnerabilities fixes released last years?

"HTTP header injection in urllib, urrlib2, httplib and http.client modules"
https://python-security.readthedocs.io/vuln/http-header-injection.html
2017-09-19 (+1030 days): Python 3.3.7 released

"CGI directory traversal"
https://python-security.readthedocs.io/vuln/cgi-directory-traversal-is_cgi.html
2011-05-09 (+1158 days): CVE-2011-1015 published
2013-04-07 (+1857 days): Python 3.2.4 released
2013-04-07 (+1857 days): Python 3.3.1 released

"httplib unlimited read"
https://python-security.readthedocs.io/vuln/httplib-unlimited-read.html
2011-06-11 (+652 days): Python 2.7.2 released
2011-06-11 (+652 days): Python 3.1.4 released

"rgbimg and imageop overflows"
https://python-security.readthedocs.io/vuln/rgbimg-imageop-overflows.html
2008-12-19 (+460 days): Python 2.5.3 released

So the CVE-2021-3177 fix was delivery between 14x and 55x faster than
the other listed fixes (I picked a few worst cases to put numbers in
perspective).

Congrats to the core developers for fixing the vulnerability in only
*3* days and to release manager for releasing *4* (!) Python versions
(3.6.13, 3.7.10, 3.8.8, 3.9.2) in only 34 days!

I would like to highlight that exploiting a directory traversal or
HTTP header injection is really trivial. Once you find a pattern to
explore the filesystem / inject a HTTP header, the exploit is 100%
reliable.

On the other side, there is no known exploit for ctypes CVE-2021-3177
and ctypes is rarely used. I read that Django's GIS uses ctypes and
floats, but so far nobody shows that PyCArg_repr() is called, and
nobody published an exploit.

To write a CVE-2021-3177 exploit, you must create a 64-bit floating
point number (only 8 bytes!) which becomes valid machine code, and
this code should allow to take control on the machine, once it's
formatted as decimal. For example, PyCArg_repr(123.5) writes "123.5\0"
string into the stack memory. but I don't think that it's valid x86-64
machine code. It is also hard to write a reliable exploit by injecting
machine code in the stack memory.

---

Nowadays it's way more difficult than 10 years ago to write an exploit
using a stack overflow, C compilers provide multiple hardening layers:
- FORTIFY_SOURCE,
- Control flow Enforcement Technology (Intel CET),
- Address Space Layout Randomization (ASLR),
- stack protector,
- Position Independent Executable (PIE),
- etc.

See https://wiki.debian.org/Hardening for example of C flags and
linker flags for harderning.

Did anyone notice that Red Hat Entreprise Linux 8 (RHEL) is *not*
affected by the ctypes CVE-2021-3177 vulnerability thanks to
hardening?

"Red Hat Enterprise Linux 8: python36:3.6/python36: Not affected"
and
"This flaw could have had a higher Impact, however our packages are
compiled with FORTIFY_SOURCE, which provides runtime protection to
some memory and string functions and prevents this flaw from actually
overwriting the buffer and potentially executing code."
=> https://access.redhat.com/security/cve/cve-2021-3177

I suggest you checking how your operating system built your Python
executable, and libpython if Python is built in shared mode: hardening
can prevent the ctypes vulnerabiliy, but also against *future*
vulnerabilities!

For example, Fedora 33 builds Python 3.9 with the following C flags:

-Werror=format-security
-Wp,-D_FORTIFY_SOURCE=2
-fcf-protection
-fstack-clash-protection
-fstack-protector-strong
-fPIC
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 => add the -fPIE flag
(...)

And linker flags:

-Wl,-z,now
-Wl,-z,relro
-specs=/usr/lib/rpm/redhat/redhat-hardened-ld => add the -pie flag
(...)

You can inspect hardening options on a ELF binary using hardening-check tool:

$ hardening-check /usr/bin/python3.9
/usr/bin/python3.9:
 Position Independent Executable: yes
 Stack protected: no, not found!
 Fortify Source functions: unknown, no protectable libc functions used
 Read-only relocations: yes
 Immediate binding: yes
 Stack clash protection: unknown, no -fstack-clash-protection instructions found
 Control flow integrity: yes

$ hardening-check /usr/lib64/libpython3.9.so.1.0
/usr/lib64/libpython3.9.so.1.0:
 Position Independent Executable: no, regular shared library (ignored)
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes
 Stack clash protection: unknown, no -fstack-clash-protection instructions found

Note: I don't know if this tool is reliable, but at least I can see
that multiple hardening options are enabled ;-)


On Fedora and RHEL 8, packages are built with the "annobin" extension
which records C and linker flags (and much more information). So you
check hardening using annocheck tool:

$ annocheck /usr/lib64/libpython3.6m.so.1.0
annocheck: Version 9.50.
Hardened: libpython3.6m.so.1.0: PASS.

$ annocheck /usr/lib64/libpython3.6m.so.1.0 -v|grep -vE '(skip|warn|info):'
annocheck: Version 9.50.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: One dynamic
section/segment found.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: Stack not executable.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: DT_RPATH/DT_RUNPATH
absent or rooted at /usr.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: No RWX segments found.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: No text relocations found.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: No thread
cancellation problems.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS: GOT/PLT relocations
are read only.
Hardened: /usr/lib64/libpython3.6m.so.1.0: PASS.

More information about annobin:
https://developers.redhat.com/blog/2018/02/20/annobin-storing-information-binaries/

Victor
-- 
Night gathers, and now my watch begins. It shall not end until my death.
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/XF33457KYRJPUZAN4C4E3KCNOA7TDL6S/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to