Skip to content

Multiprocessing UNIX socket connection: client freeze if authkey is an empty byte string #88118

Description

@anon01
mannequin
BPO 43952
Nosy @miguendes
PRs
  • bpo-43952: Fix multiprocessing Listener authkey bug #25845
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-04-27.11:45:15.510>
    labels = ['type-bug', 'library', '3.11']
    title = 'Multiprocessing UNIX socket connection: client freeze if authkey is an empty byte string'
    updated_at = <Date 2021-05-13.21:12:02.688>
    user = 'https://bugs.python.org/anon01'

    bugs.python.org fields:

    activity = <Date 2021-05-13.21:12:02.688>
    actor = 'pitrou'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2021-04-27.11:45:15.510>
    creator = 'anon01'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 43952
    keywords = ['patch']
    message_count = 3.0
    messages = ['392056', '392591', '392790']
    nosy_count = 1.0
    nosy_names = ['miguendes']
    pr_nums = ['25845']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue43952'
    versions = ['Python 3.11']

    Linked PRs

    Activity

    1. anon01 commented on Apr 27, 2021

      anon01mannequin
      MannequinAuthor

      When I run this code (on a UNIX system with temporary directory /tmp/):

      from multiprocessing import connection
      import threading
      key=b"1"
      
      def run():
          c=connection.Client("/tmp/xxx", authkey=key)
          c.send("data")
      
      l=connection.Listener("/tmp/xxx", authkey=key)
      threading.Thread(target=run).start()
      c=l.accept()
      print("receive", c.recv())
      

      it prints out "receive data" normally.

      However, in the special case that key=b"" the doesn't print anything, and can only be interrupted with Ctrl+C.

      key=None doesn't have that issue.

      Note that this issue does happen when the client uses the key b"" and the server uses the key None, but the program works normally if the reverse situation.

      Python version: Python 3.9.3.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on Apr 27, 2021
    3. miguendes commented on May 1, 2021

      miguendesmannequin
      Mannequin

      I tried debugging this and from what I can see it's because there's an if that checks if the authkey is not None in the Client constructor:

      https://github.com/python/cpython/blob/v3.9.4/Lib/multiprocessing/connection.py#L512

          if authkey is not None:
              answer_challenge(c, authkey)
              deliver_challenge(c, authkey)
      

      Whereas in the Listener, the check is different:

      https://github.com/python/cpython/blob/v3.9.4/Lib/multiprocessing/connection.py#L469

              c = self._listener.accept()
              if self._authkey:
                  deliver_challenge(c, self._authkey)
                  answer_challenge(c, self._authkey)
              return c
      

      If I change the Listener to:

              if self._authkey is not None:
                  deliver_challenge(c, self._authkey)
                  answer_challenge(c, self._authkey)
              return c
      

      it works.

      The docs say:

      """
      If authkey is given and not None, it should be a byte string and will be used as the secret key for an HMAC-based authentication challenge. No authentication is done if authkey is None. AuthenticationError is raised if authentication fails. See Authentication keys.
      """

      Now the question is, if None is OK because no auth will be done what about empty bytes? Can it be used as secret key? If empty bytes is not accepted shouldn't Listener/Client raise an exception in the constructor?

    4. miguendes commented on May 3, 2021

      miguendesmannequin
      Mannequin

      I had a look at the HMAC RFC and apparently empty bytes sequence can be used as secret key.

      "The definition of HMAC requires a cryptographic hash function, which
      we denote by H, and a secret key K.

      ...

      The authentication key K can be of any length up to B, the
      block length of the hash function."

      https://tools.ietf.org/html/rfc2104.html#section-2

      Assuming that is the case, the fix would be to change the Listener to:

              if self._authkey is not None:
                  deliver_challenge(c, self._authkey)
                  answer_challenge(c, self._authkey)
              return c
      

      I created a PR for that, if anyone can review it, I appreciate it.
      #25845

    5. added
      3.11only security fixes
      and removed on May 13, 2021
    6. transferred this issue fromon Apr 10, 2022
    7. gpshead commented on Feb 27, 2024

      @gpshead
      Member

      A bit of an ironic issue as using an empty key seems kind of pointless... but thanks for the edge case fix! :)

    8. added a commit that references this issue on Mar 6, 2024
    9. added 2 commits that reference this issue on Mar 6, 2024
    10. added 2 commits that reference this issue on Mar 6, 2024
    11. added a commit that references this issue on Mar 25, 2024
    12. added a commit that references this issue on Apr 17, 2024
    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.11only security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-multiprocessingtype-bugAn unexpected behavior, bug, or error

      Projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions