python / python/cpython

`_decimal::CURRENT_CONTEXT`: UAF via borrowed reference across Python callbacks

Ouverte
#148,382 6 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

extension-modules type-crash
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

Crash report

Originally reported by @PidSS as a security advisory

What happened?

The CURRENT_CONTEXT() macro in Modules/_decimal/_decimal.c:1951 obtains a new reference from PyContextVar_Get(), then immediately calls Py_DECREF, leaving a borrowed reference. If Python code executes before the context pointer is next used — via warning handlers, GC finalizers, instancecheck, etc. — and that code calls decimal.setcontext(), the old context is freed while C code still holds a dangling pointer. The macro is used at 20+ call sites covering virtually every decimal operation.

Original reproducer (I will try to make a shorter one):

import decimal, warnings, gc, sys, ctypes

gc.disable()
ctx = decimal.getcontext()
CTX_ID, CTX_SIZE = id(ctx), sys.getsizeof(ctx)
del ctx  # refcount = 1, held only by ContextVar HAMT

def evil_warning_handler(message, category, filename, lineno, file=None, line=None):
    if 'Format specifier' not in str(message):
        return
    ctx = decimal.getcontext()                       # refcount -> 2
    decimal.setcontext(decimal.Context(prec=999))    # HAMT ref dropped -> 1
    del ctx                                          # refcount -> 0, FREED
    spray = [bytearray(b'\xCC' * (CTX_SIZE - 32)) for _ in range(100000)]

warnings.showwarning = evil_warning_handler
warnings.filterwarnings('always', category=DeprecationWarning)
format(decimal.Decimal('123.456'), 'N')

FTR, I saw that we have this macro twice, but it depends on whether we have WITH_DECIMAL_CONTEXTVAR. If I build Python with --without-decimal-contextvar, I also have a crash so it's a bit weird.

Related but not with the same root cause: https://github.com/python/cpython/issues/146011.

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

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

No response

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez dans Modules/_decimal/_decimal.c, au niveau de la macro CURRENT_CONTEXT vers la ligne 1951, puis examinez ses plus de 20 sites d’appel ainsi que la seconde macro utilisée sans WITH_DECIMAL_CONTEXTVAR. Exécutez le reproducteur fourni du gestionnaire d’avertissements sur une build main de CPython. Le travail est terminé lorsque le chemin de callback reproduit n’utilise plus de contexte libéré dans aucune des deux configurations.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
c, python
Domaine
security
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
Calme
Clarté
Plutôt claire
Accessibilité débutants
45/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.