GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — ctypes: We do not correctly handle NULL dlsym() return values · Issue #126554 · python/cpython

ctypes: We do not correctly handle NULL dlsym() return values #126554

New issue
Copy link
New issue
Copy link
Closed
Closed
ctypes: We do not correctly handle NULL dlsym() return values#126554
Copy link
Labels
3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-ctypestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@grgalex
grgalex
opened on Nov 7, 2024
Issue body actions

Bug report

Bug description:

The man(3) page for dlsym() states:

In unusual cases (see NOTES) the value of the symbol  could  actually  be
NULL. Therefore, a NULL return from dlsym() need not indicate an error.
The correct way to distinguish an error from a symbol whose value is NULL
is  to  call  dlerror(3) to clear any old error conditions, then call dl‐
sym(), and then call dlerror(3) again, saving its  return  value  into  a
variable, and check whether this saved value is not NULL.

As such, there can be cases where a call to dlsym returns NULL, while no error has been encountered and the string that dlerror() returns has not been (re)set.

Currently, (https://github.com/python/cpython/blob/main/Modules/_ctypes/_ctypes.c#L970) we do:

<...>
address = (void *)dlsym(handle, name);
if (!address) {
#ifdef __CYGWIN__
<snip Windows stuff>
#else
        PyErr_SetString(PyExc_ValueError, dlerror());
<...>

If dlsym() returns NULL, then by calling dlerror() we pass either NULL or a previous, unconsumed error string to PyErr_SetString.

In the context of ctypes, a NULL return by dlsym() might indeed always be considered an error.

To correctly express this, we should:

  • Call dlerror() before dlsym(), to clear any previous error
  • Call dlerror() after dlsym(), to see if dlsym() encountered any error
    • If dlerror() returns a non-NULL value, then pass its result to PyErr_SetString
    • If dlerror() returns NULL, then check if address is NULL, and if so, pass a custom error string to PyErr_SetString.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

  • gh-126554: ctypes: Correctly handle NULL dlsym values #126555
  • [3.13] gh-126554: ctypes: Correctly handle NULL dlsym values (GH-126555) #126861
  • [3.12] gh-126554: ctypes: Correctly handle NULL dlsym values (GH-126555) #127764
  • gh-126554: correct detection of gcc for TestNullDlsym.test_null_dlsym #129872
  • [3.13] gh-126554: correct detection of gcc for TestNullDlsym.test_null_dlsym (GH-129872) #129944
  • [3.12] gh-126554: correct detection of gcc for TestNullDlsym.test_null_dlsym (GH-129872) #129945

Activity

  1. grgalex
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Nov 7, 2024
  2. efimov-mikhail commented on Nov 7, 2024

    @efimov-mikhail
    efimov-mikhail
    on Nov 7, 2024
    Member
    More actions

    Is it actually a bug?
    Can we make a repro?

  3. grgalex commented on Nov 7, 2024

    @grgalex
    grgalex
    on Nov 7, 2024
    ContributorAuthor
    More actions

    EDIT: See Reproducer below.

  4. grgalex commented on Nov 7, 2024

    @grgalex
    grgalex
    on Nov 7, 2024
    ContributorAuthor
    More actions

    I managed to create a reproducer using Indirect Functions (IFUNCS) by adapting this SO answer: https://stackoverflow.com/a/53590014

    1. Create a file named foo.c with the following contents:
    #include <stdio.h>
    
    /* This is a 'GNU indirect function' (IFUNC) that will be called by
       dlsym() to resolve the symbol "foo" to an address. Typically, such
       a function would return the address of an actual function, but it
       can also just return NULL.  For some background on IFUNCs, see
       https://willnewton.name/uncategorized/using-gnu-indirect-functions/ */
    
    asm (".type foo, @gnu_indirect_function");
    
    void *
    foo(void)
    {
        fprintf(stderr, "foo called\n");
        return NULL;
    }
    
    1. Create a file named main.c with the following contents:
    #include <dlfcn.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int
    main(int argc, char *argv[])
    {
        void *handle;
        void (*funcp)(void);
    
        handle  = dlopen("./foo.so", RTLD_LAZY);
        if (handle == NULL) {
            fprintf(stderr, "dlopen: %s\n", dlerror());
            exit(EXIT_FAILURE);
        }
    
        dlerror();      /* Clear any outstanding error */
    
        funcp = dlsym(handle, "foo");
    
        printf("Results after dlsym(): funcp = %p; dlerror = %s\n",
                (void *) funcp, dlerror());
    
        exit(EXIT_SUCCESS);
    }
    
    1. Compile foo.c into a shared library named libfoo.so:
    gcc -Wall -fPIC -shared -o libfoo.so foo.c
    
    1. Compile the main executable:
    gcc -Wall -o main main.c -L. -lfoo -ldl
    
    1. Run main:
    ./main
    foo called ### This is from the IFUNC ###
    Results after dlsym(): funcp = (nil); dlerror = (null)
    
  5. grgalex commented on Nov 7, 2024

    @grgalex
    grgalex
    on Nov 7, 2024
    ContributorAuthor
    More actions

    When using ctypes to search for symbol foo in libfoo.so we get a Segmentation Fault.
    (Tested on Python 3.10 from my system, as well as one built from main.)

    python3 -c 'import ctypes; C = ctypes.CDLL("./libfoo.so"); C.foo'
    
    foo called
    Segmentation fault (core dumped)
    

    So this turned out to be a bug after all!

    Reacted by Mikhail Efimov
  6. grgalex commented on Nov 7, 2024

    @grgalex
    grgalex
    on Nov 7, 2024
    ContributorAuthor
    More actions

    With the interpreter built from my PR we instead get:

    ./python -c 'import ctypes; C = ctypes.CDLL("./libfoo.so"); C.foo'
    
    foo called
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
        import ctypes; C = ctypes.CDLL("./libfoo.so"); C.foo
                                                       ^^^^^
      File "/home/grg/a-lab/cpython/Lib/ctypes/__init__.py", line 415, in __getattr__
        func = self.__getitem__(name)
      File "/home/grg/a-lab/cpython/Lib/ctypes/__init__.py", line 420, in __getitem__
        func = self._FuncPtr((name_or_ordinal, self))
    AttributeError: function 'foo' not found
    
    Reacted by Xuanteng Huang
  7. grgalex commented on Nov 7, 2024

    @grgalex
    grgalex
    on Nov 7, 2024
    ContributorAuthor
    More actions

    cc: @efimov-mikhail

  8. ZeroIntensity
    added
    topic-ctypes
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    3.12only security fixesonly security fixes
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    on Nov 7, 2024
  9. grgalex commented on Nov 8, 2024

    @grgalex
    grgalex
    on Nov 8, 2024
    ContributorAuthor
    More actions

    Fun fact:

    The StackOverflow answer, which I adapted to form the reproducer is actually written by Michael Kerrisk [1].

    So, he was the one who came up to clarify his statements in the man page, when noone else {c,w}ould :)

    [1] https://en.wikipedia.org/wiki/Michael_Kerrisk

    Reacted by Mikhail Efimov
  10. encukou
    added a commit that references this issue on Nov 15, 2024

    gh-126554: ctypes: Correctly handle NULL dlsym values (GH-126555)

    8717f79
  11. miss-islington
    added a commit that references this issue on Nov 15, 2024

    pythongh-126554: ctypes: Correctly handle NULL dlsym values (pythonGH…

    5b4116e
  12. encukou commented on Nov 15, 2024

    @encukou
    encukou
    on Nov 15, 2024
    Member
    More actions

    Thanks @grgalex for the fix, and @ZeroIntensity & @picnixz for the thorough reviews!

    When using ctypes to search for symbol foo in libfoo.so we get a Segmentation Fault.
    [...]
    So this turned out to be a bug after all!

    Well, when a symbol you asked for points to uninitialized memory (like a NULL), a segfault seems rather reasonable to me. (Granted, it does happen for the wrong reasons.)

    Treating NULL specially could possibly be considered a feature, rather than a bug.
    Given how hard this is to reproduce, I wouldn't mind having the fix to 3.14 only, and omitting the backports.

    Reacted by George Alexopoulos
  13. ambv
    added a commit that references this issue on Nov 17, 2024

    [3.13] gh-126554: ctypes: Correctly handle NULL dlsym values (GH-126555…

    52efb95
  14. picnixz
    added a commit that references this issue on Dec 8, 2024

    pythongh-126554: ctypes: Correctly handle NULL dlsym values (pythonGH…

    583e01a
  15. encukou
    closed this as completedon Dec 9, 2024
  16. serhiy-storchaka
    added a commit that references this issue on Dec 17, 2024

    [3.12] gh-126554: ctypes: Correctly handle NULL dlsym values (GH-126555…

    6ac578c
  17. ebonnal
    added a commit that references this issue on Jan 12, 2025

    pythongh-126554: ctypes: Correctly handle NULL dlsym values (pythonGH…

    1a7fa4b
  18. encukou
    added a commit that references this issue on Feb 10, 2025

    gh-126554: correct detection of `gcc` for `TestNullDlsym.test_null_dl…

    978211c
  19. miss-islington
    added 2 commits that reference this issue on Feb 10, 2025

    pythongh-126554: correct detection of `gcc` for `TestNullDlsym.test_n…

    b9f8346

    pythongh-126554: correct detection of `gcc` for `TestNullDlsym.test_n…

    c3994fa
  20. picnixz
    added 2 commits that reference this issue on Feb 10, 2025

    [3.12] gh-126554: correct detection of `gcc` for `TestNullDlsym.test_…

    3d2ca74

    [3.13] gh-126554: correct detection of `gcc` for `TestNullDlsym.test_…

    cef406b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-ctypestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.