Skip to content

Segmentation Fault in _curses #120378

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

Closed
kcatss opened this issue Jun 12, 2024 · 9 comments
Closed

Segmentation Fault in _curses #120378

kcatss opened this issue Jun 12, 2024 · 9 comments
Labels
3.12 only security fixes 3.13 bugs and security fixes 3.14 bugs and security fixes extension-modules C modules in the Modules dir type-crash A hard crash of the interpreter, possibly with a core dump

Comments

@kcatss
Copy link
Contributor

kcatss commented Jun 12, 2024

Crash report

What happened?

Build

./configure --with-pydebug --with-address-sanitizer
apt-get install libncurses5-dev

Root Cause

When calling _curses.initscr, initialised is set to True. Then, if _curses.resizeterm is called with an improper size for the first argument, an error occurs, and stdscr is freed. The error does not terminate even when wrapped in a try-except block.
Because initialised is set to True, a second call to _curses.initscr invokes wrefresh(stdscr) even though stdscr has already been freed.

_curses_initscr_impl(PyObject *module)
/*[clinic end generated code: output=619fb68443810b7b input=514f4bce1821f6b5]*/
{
WINDOW *win;
PyCursesWindowObject *winobj;
if (initialised) {
wrefresh(stdscr);
return (PyObject *)PyCursesWindow_New(stdscr, NULL);
}
win = initscr();
if (win == NULL) {
PyErr_SetString(PyCursesError, catchall_NULL);
return NULL;
}
initialised = initialised_setupterm = TRUE;

POC

import _curses
_curses.initscr()
try:
    _curses.resizeterm(+35000, 1)
except:
    pass
_curses.initscr()

ASAN

asan

AddressSanitizer:DEADLYSIGNAL
=================================================================
==1373==ERROR: AddressSanitizer: SEGV on unknown address 0x7f4c7b59d370 (pc 0x7f4c7b7eb5aa bp 0x61b000018880 sp 0x7ffd073842c0 T0)
==1373==The signal is caused by a READ memory access.
#0 0x7f4c7b7eb5aa  (/lib/x86_64-linux-gnu/libncursesw.so.6+0x275aa)
#1 0x7f4c7b7edd09 in doupdate_sp (/lib/x86_64-linux-gnu/libncursesw.so.6+0x29d09)
#2 0x7f4c7b7e16d7 in wrefresh (/lib/x86_64-linux-gnu/libncursesw.so.6+0x1d6d7)
#3 0x7f4c7b9908f6 in _curses_initscr_impl Modules/_cursesmodule.c:3258
#4 0x7f4c7b999675 in _curses_initscr Modules/clinic/_cursesmodule.c.h:2661
#5 0x562817924edd in cfunction_vectorcall_NOARGS Objects/methodobject.c:481
#6 0x5628175fddeb in _PyObject_VectorcallTstate Include/internal/pycore_call.h:92
#7 0x5628175fe0a0 in PyObject_Vectorcall Objects/call.c:325
#8 0x56281800d628 in _PyEval_EvalFrameDefault Python/bytecodes.c:2706
#9 0x5628180346d0 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:89
#10 0x5628180346d0 in _PyEval_Vector Python/ceval.c:1683
#11 0x562818034a7c in PyEval_EvalCode Python/ceval.c:578
#12 0x562818377486 in run_eval_code_obj Python/pythonrun.c:1691
#13 0x56281837cb70 in run_mod Python/pythonrun.c:1712
#14 0x56281837d4f1 in pyrun_file Python/pythonrun.c:1612
#15 0x562818397728 in _PyRun_SimpleFileObject Python/pythonrun.c:433
#16 0x562818398a0c in _PyRun_AnyFileObject Python/pythonrun.c:78
#17 0x5628184e2cf0 in pymain_run_file_obj Modules/main.c:360
#18 0x5628184e4c04 in pymain_run_file Modules/main.c:379
#19 0x5628184f0722 in pymain_run_python Modules/main.c:629
#20 0x5628184f0be4 in Py_RunMain Modules/main.c:709
#21 0x5628184f1077 in pymain_main Modules/main.c:739
#22 0x5628184f14f4 in Py_BytesMain Modules/main.c:763
#23 0x562817147c3a in main Programs/python.c:15
#24 0x7f4c7ec56d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#25 0x7f4c7ec56e3f in __libc_start_main_impl ../csu/libc-start.c:392
#26 0x562817072344 in _start (/cpython/python+0x3a7344)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libncursesw.so.6+0x275aa)
==1373==ABORTING

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.14.0a0 (heads/main:34f5ae69fe, Jun 9 2024, 21:27:54) [GCC 11.4.0]

Linked PRs

@kcatss kcatss added the type-crash A hard crash of the interpreter, possibly with a core dump label Jun 12, 2024
@devdanzin
Copy link
Contributor

devdanzin commented Aug 6, 2024

Here are some tests that show the problem in different places (i.e., a local fix to one of them might not fix the root issue):

    @requires_curses_func('resize_term')
    def test_resize_term_initscr_segfault(self):
        curses.initscr()
        lines = cols = 40000
        try:
            curses.resize_term(lines, cols)
        except:
            pass
        curses.initscr()
        curses.initscr()

    @requires_curses_func('resizeterm')
    def test_resizeterm_initscr_segfault(self):
        curses.initscr()
        lines = cols = 40000
        try:
            curses.resizeterm(lines, cols)
        except:
            pass
        curses.initscr()
        curses.initscr()

    def test_resize_term_refresh_segfault(self):
        curses.initscr()
        lines = cols = 40000
        try:
            curses.resize_term(lines, cols)
        except:
            pass
        c = curses.initscr()
        c.refresh()

@ZeroIntensity
Copy link
Member

Then, if _curses.resizeterm is called with an improper size for the first argument, an error occurs, and stdscr is freed.

That doesn't seem like the case. If that was true, then nearly every call to the window object should segfault after resizeterm fails. Quick example to show that this isn't the case:

import _curses
screen = _curses.initscr()
try:
    _curses.resizeterm(35000, 1)
except:
    screen.box()  # This should segfault if stdscr is freed!

As far as I can see, this is actually an upstream bug in curses. It seems that a failure in resizeterm causes something in stdscr to get invalidated, and then causes wrefresh to fail. Pure-C reproducer:

#include <curses.h>

int
main(void)
{
    initscr();
    if (resizeterm(35000, 1) < 0) {
        puts("no good!");
    }
    wrefresh(stdscr);
    return 0;
}

I wasn't able to find any good workaround, so there's nothing that we can do on our end. I'll leave this open temporarily if anyone has any other ideas.

@ZeroIntensity ZeroIntensity added the pending The issue will be closed if no feedback is provided label Sep 23, 2024
@ZeroIntensity
Copy link
Member

cc @picnixz, you've been working on _curses, right?

@picnixz
Copy link
Member

picnixz commented Sep 25, 2024

Not entirely sure that it's an issue in curses. The manual for resizeterm says:

Except as noted, these functions return the integer ERR upon failure and OK on success. They will fail if either of the dimensions are less than or equal to zero, or if an error occurs while (re)allocating memory for the windows.

I suggest reporting the issue upstream to confirm or not the behaviour.

@ZeroIntensity
Copy link
Member

I played around with this, and even manually reinitializing stdscr with initscr still causes wrefresh to crash. If it was just the case of something in stdscr being NULL, I would expect that to fix it.

I'm closing this as an upstream issue and reporting it to the GNU mailing lists.

@ZeroIntensity ZeroIntensity closed this as not planned Won't fix, can't repro, duplicate, stale Sep 25, 2024
@ZeroIntensity ZeroIntensity removed the pending The issue will be closed if no feedback is provided label Sep 25, 2024
@ZeroIntensity ZeroIntensity reopened this Sep 25, 2024
@ZeroIntensity ZeroIntensity added extension-modules C modules in the Modules dir 3.12 only security fixes 3.13 bugs and security fixes 3.14 bugs and security fixes labels Sep 25, 2024
@ZeroIntensity
Copy link
Member

According to GNU, it seems the function is erroneously documented as taking integers, while in reality they are shorts. A workaround for us is to disallow negatives and raise an exception for anything above the signed 16 bit integer limit. I'll get to this later today.

@ZeroIntensity
Copy link
Member

I was corrected on the mailing list: the functions don't necessarily take short, but rather store a short internally (at least, that was my understanding of it). It seems that they are working on fixing the crash on their end, but I've created #124555 as a bandaid for us.

vstinner pushed a commit that referenced this issue Oct 2, 2024
This is actually an upstream problem in curses, and has been reported
to them already:
https://lists.gnu.org/archive/html/bug-ncurses/2024-09/msg00101.html

This is a nice workaround in the meantime to prevent the segfault.

Co-authored-by: Bénédikt Tran <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 2, 2024
…thonGH-124555)

This is actually an upstream problem in curses, and has been reported
to them already:
https://lists.gnu.org/archive/html/bug-ncurses/2024-09/msg00101.html

This is a nice workaround in the meantime to prevent the segfault.

(cherry picked from commit c2ba931)

Co-authored-by: Peter Bierma <[email protected]>
Co-authored-by: Bénédikt Tran <[email protected]>
ZeroIntensity added a commit to ZeroIntensity/cpython that referenced this issue Oct 2, 2024
…es` (pythonGH-124555)

This is actually an upstream problem in curses, and has been reported
to them already:
https://lists.gnu.org/archive/html/bug-ncurses/2024-09/msg00101.html

This is a nice workaround in the meantime to prevent the segfault.

(cherry picked from commit c2ba931)

Co-authored-by: Peter Bierma <[email protected]>
Co-authored-by: Bénédikt Tran <[email protected]>
@vstinner
Copy link
Member

vstinner commented Oct 2, 2024

Fixed by c2ba931 in the main branch, backports will follow.

@vstinner vstinner closed this as completed Oct 2, 2024
@github-project-automation github-project-automation bot moved this from Bugs to Done in Curses issues Oct 2, 2024
@vstinner
Copy link
Member

vstinner commented Oct 2, 2024

Thanks for your bug report @kcatss.

vstinner pushed a commit that referenced this issue Oct 2, 2024
…H-124555) (#124911)

This is actually an upstream problem in curses, and has been reported
to them already:
https://lists.gnu.org/archive/html/bug-ncurses/2024-09/msg00101.html

This is a nice workaround in the meantime to prevent the segfault.

(cherry picked from commit c2ba931)

Co-authored-by: Bénédikt Tran <[email protected]>
vstinner pushed a commit that referenced this issue Oct 7, 2024
…H-124555) (#124905)

gh-120378: Fix crash caused by integer overflow in `curses` (GH-124555)

This is actually an upstream problem in curses, and has been reported
to them already:
https://lists.gnu.org/archive/html/bug-ncurses/2024-09/msg00101.html

This is a nice workaround in the meantime to prevent the segfault.

(cherry picked from commit c2ba931)

Co-authored-by: Peter Bierma <[email protected]>
Co-authored-by: Bénédikt Tran <[email protected]>
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
pmbarrett314 added a commit to pmbarrett314/windows-curses that referenced this issue Nov 28, 2024
stephanosio pushed a commit to pmbarrett314/windows-curses that referenced this issue Dec 30, 2024
stephanosio pushed a commit to zephyrproject-rtos/windows-curses that referenced this issue Dec 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 only security fixes 3.13 bugs and security fixes 3.14 bugs and security fixes extension-modules C modules in the Modules dir type-crash A hard crash of the interpreter, possibly with a core dump
Projects
Status: Done
Development

No branches or pull requests

5 participants