`_decimal::CURRENT_CONTEXT`: UAF via borrowed reference across Python callbacks
Personne n'a encore pris cette issue.
- 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
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- 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