Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:ceph
User: [email protected]
Usertags: pu

Hi,

I'd like to upgrade Ceph in Trixie p-u to fix an issue
the ceph-mgr, where it cannot start. See debian bug #1148903.

[ Reason ]
As per the patch header:

 python3-bcrypt is built with PyO3, and PyO3 extensions cannot be
 imported inside a Python subinterpreter, which is how ceph-mgr loads
 its modules. With Python 3.13's python3-bcrypt, every mgr module
 fails to load with "ImportError: PyO3 modules do not yet support
 subinterpreters", breaking the mgr (and the dashboard module, which
 imports bcrypt as well).

So we got to fix that for ceph-mgr to work in Trixie.

[ Impact ]
Users can't start ceph-mgr, and therefore, cannot use cephfs.

[ Tests ]
I've tested this fix myself manually.

[ Risks ]
Not much risk: since ceph-mgr is currently broken, it cannot get worse.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
As per debdiff: the 0011-mgr-replace-bcrypt-with-crypt_r.patch, plus
replacing python3-bcrypt by python3-crypt-r as new runtime depends.

Please allow me to upload ceph/18.2.7+ds-1+deb13u2.

Cheers,

Thomas Goirand (zigo)
diff -Nru ceph-18.2.7+ds/debian/changelog ceph-18.2.7+ds/debian/changelog
--- ceph-18.2.7+ds/debian/changelog     2026-05-10 21:17:37.000000000 +0200
+++ ceph-18.2.7+ds/debian/changelog     2026-10-16 10:12:37.000000000 +0200
@@ -1,3 +1,16 @@
+ceph (18.2.7+ds-1+deb13u2) trixie; urgency=medium
+
+  * mgr: replace the python3-bcrypt import with crypt_r: PyO3 extensions
+    cannot be imported inside a Python subinterpreter, which is how
+    ceph-mgr loads its modules, so every mgr module failed to load with
+    Python 3.13's python3-bcrypt, including the dashboard module.
+    crypt_r computes the same $2b$ bcrypt hashes, so existing password
+    hashes keep verifying (Closes: #1148903).
+  * ceph-mgr, ceph-mgr-dashboard: replace the python3-bcrypt dependency
+    with python3-crypt-r.
+
+ -- Thomas Goirand <[email protected]>  Fri, 16 Oct 2026 11:14:03 +0200
+
 ceph (18.2.7+ds-1+deb13u1) trixie-security; urgency=high
 
   * Non-maintainer upload by the Security Team.
diff -Nru ceph-18.2.7+ds/debian/control ceph-18.2.7+ds/debian/control
--- ceph-18.2.7+ds/debian/control       2026-05-10 21:06:34.000000000 +0200
+++ ceph-18.2.7+ds/debian/control       2026-10-16 10:12:37.000000000 +0200
@@ -354,7 +354,7 @@
  ceph-mgr-modules-core (>= ${source:Version}),
  libsqlite3-mod-ceph (<< ${source:Version}.1~),
  libsqlite3-mod-ceph (>= ${source:Version}),
- python3-bcrypt,
+ python3-crypt-r,
  python3-ceph-argparse (= ${binary:Version}),
  python3-cephfs (= ${binary:Version}),
  python3-cherrypy3,
@@ -408,7 +408,7 @@
  ceph-common (>= ${binary:Version}),
  ceph-mgr (<< ${binary:Version}.1~),
  ceph-mgr (>= ${binary:Version}),
- python3-bcrypt,
+ python3-crypt-r,
  python3-cherrypy3,
  python3-jwt,
  python3-more-itertools,
diff -Nru 
ceph-18.2.7+ds/debian/patches/py313-compat/0011-mgr-replace-bcrypt-with-crypt_r.patch
 
ceph-18.2.7+ds/debian/patches/py313-compat/0011-mgr-replace-bcrypt-with-crypt_r.patch
--- 
ceph-18.2.7+ds/debian/patches/py313-compat/0011-mgr-replace-bcrypt-with-crypt_r.patch
       1970-01-01 01:00:00.000000000 +0100
+++ 
ceph-18.2.7+ds/debian/patches/py313-compat/0011-mgr-replace-bcrypt-with-crypt_r.patch
       2026-10-16 10:12:37.000000000 +0200
@@ -0,0 +1,68 @@
+Description: mgr: replace the bcrypt import with crypt_r
+ python3-bcrypt is built with PyO3, and PyO3 extensions cannot be
+ imported inside a Python subinterpreter, which is how ceph-mgr loads
+ its modules. With Python 3.13's python3-bcrypt, every mgr module
+ fails to load with "ImportError: PyO3 modules do not yet support
+ subinterpreters", breaking the mgr (and the dashboard module, which
+ imports bcrypt as well).
+ .
+ Use crypt_r (libxcrypt) instead: it computes the same $2b$ bcrypt
+ hashes, so existing password hashes keep verifying.
+ .
+ Patch based on the workaround posted by Jakob Haufe in #1148903,
+ with the blowfish cost kept at 12 (crypt_r.mksalt expects the
+ literal iteration count, hence rounds=4096 = 2^12) to match
+ bcrypt.gensalt()'s default.
+Author: Thomas Goirand <[email protected]>
+Assisted-By: Infomaniak Euria-Code
+Bug-Debian: https://bugs.debian.org/1148903
+Last-Update: 2026-10-16
+
+Index: ceph/src/pybind/mgr/dashboard/services/access_control.py
+===================================================================
+--- ceph.orig/src/pybind/mgr/dashboard/services/access_control.py
++++ ceph/src/pybind/mgr/dashboard/services/access_control.py
+@@ -11,8 +11,8 @@ import time
+ from datetime import datetime, timedelta
+ from string import ascii_lowercase, ascii_uppercase, digits, punctuation
+ from typing import List, Optional, Sequence
++import re
+ 
+-import bcrypt
+ from mgr_module import CLICheckNonemptyFileInput, CLIReadCommand, 
CLIWriteCommand
+ from mgr_util import password_hash
+ 
+@@ -888,7 +888,8 @@ def ac_user_set_password_hash(_, usernam
+     hashed_password = inbuf
+     try:
+         # make sure the hashed_password is actually a bcrypt hash
+-        bcrypt.checkpw(b'', hashed_password.encode('utf-8'))
++        if not re.fullmatch(r'\$2[aby]\$\d{2}\$[./A-Za-z0-9]{53}', 
hashed_password):
++            raise ValueError('Invalid bcrypt hash')
+         user = mgr.ACCESS_CTRL_DB.get_user(username)
+         user.set_password_hash(hashed_password)
+ 
+Index: ceph/src/pybind/mgr/mgr_util.py
+===================================================================
+--- ceph.orig/src/pybind/mgr/mgr_util.py
++++ ceph/src/pybind/mgr/mgr_util.py
+@@ -3,7 +3,7 @@ import os
+ if 'UNITTEST' in os.environ:
+     import tests
+ 
+-import bcrypt
++import crypt_r as crypt
+ import cephfs
+ import contextlib
+ import datetime
+@@ -880,7 +880,7 @@ def password_hash(password: Optional[str
+     if not password:
+         return None
+     if not salt_password:
+-        salt = bcrypt.gensalt()
++        salt = crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=4096)
+     else:
+-        salt = salt_password.encode('utf8')
+-    return bcrypt.hashpw(password.encode('utf8'), salt).decode('utf8')
++        salt = salt_password
++    return crypt.crypt(password, salt)
diff -Nru ceph-18.2.7+ds/debian/patches/series 
ceph-18.2.7+ds/debian/patches/series
--- ceph-18.2.7+ds/debian/patches/series        2026-05-10 21:15:52.000000000 
+0200
+++ ceph-18.2.7+ds/debian/patches/series        2026-10-16 10:12:37.000000000 
+0200
@@ -41,3 +41,4 @@
 py313-compat/0010-ceph-volume-fix-importlib.metadata-compat.patch
 mgr-alerts-enforce-ssl-context-to-SMTP_SSL.patch
 Check-if-HTTP_X_AMZ_COPY_SOURCE-header-is-empty.patch
+py313-compat/0011-mgr-replace-bcrypt-with-crypt_r.patch

Reply via email to