SLES 15.7 io_uring Crash
Investigation · amd64-sles-1507-rpm-autobake-install · build 76750

MariaDB 12.3.4 segfaults while installing on SLES 15.7

Both crashes in the install test are the same failure. io_uring_get_sqe() returns NULL and MariaDB writes through it. Running the server with a liburing library older than 2.3 reproduces both crashes exactly, and the production VM that crashed has liburing2 2.1.

Date 2026-10-29 Server 12.3.4, revision e9ff0bf7 Branch bb-12.3-release Status reproduced confirmed on the VM

Summary

From liburing 2.3 on, the inline helper io_uring_get_sqe() reads two queue-size fields that libraries older than 2.3 leave at zero. When the server runs with such an old library, every call reports the submission queue as full and returns NULL. MariaDB's io_uring code doesn't check for NULL and writes the request into address 0. The install test hit this twice: first in mariadb-install-db, then in InnoDB's shutdown after the first crash had left ibdata1 empty.

The MariaDB-server RPM only asks for the LIBURING_2.1 symbol version, so zypper accepts an old liburing2 and never upgrades it. SUSE shipped liburing2 2.1 for SLES 15 until May 2025, and the production VM image still has liburing2-2.1-150400.2.4.

ReproducedBoth crashes, same backtrace offsets as the VM
CauseRuntime liburing < 2.3, binary built with 2.9 headers
Confirmed on the VMbbw5 has liburing2-2.1-150400.2.4; the dev VM has 2.9
Not the causeSELinux, plugin packages, kernel, filesystem
VM check

liburing on the SLES 15.7 workers

VMRoleKernelliburing2Reading
bb-hz-bbw5-sles-1507-amd64Production. Ran build 76750 and crashed6.4.0-150700.51 (2025-04-30)2.1-150400.2.4older than 2.3 the version that reproduces both crashes
bb-ro-apexis-bbw03-x64-sles-1507-amd64Dev. Checked on 2026-10-296.4.0-150700.53.732.9-150700.10.3.12.3 or newer same package as the container, where nothing crashed

The production VM that crashed has liburing2-2.1-150400.2.4, a package from the SLE 15 SP4 code stream (release 150400). That is the old-library case reproduced in the container. Its image was never updated to the 2.9 package that the dev VM has.

Each libvirt host keeps its own base image (<VM name>.qcow2), and dev and production use different hosts, which is how the two drifted apart. The dev VM also runs a later maintenance kernel, while bbw5 still has the April 2025 release kernel. Builds on the dev VM should not hit this crash.

What the VM log shows

Two crashes, one cause

  1. zypper installs MariaDB-server (package 33 of 51). Its post-install script runs mariadb-install-db --rpm --user=mysql. The plugin packages (rocksdb, duckdb, connect, oqgraph, videx…) and galera were installed after it, so none of them was present yet.
  2. Crash 1: the bootstrap server gets SIGSEGV in a background I/O thread (Thread pointer: 0x0). It is the first asynchronous page write that fails, so page 0 of ibdata1 is never written. The Aria system tables, which don't go through this code, were already on disk.
  3. systemctl start mariadb finds a header page of zeros: InnoDB: Header page consists of zero bytes in datafile: ./ibdata1, then Plugin initialization aborted with error Data structure corruption. This error is a result of crash 1; on its own it only stops InnoDB from starting.
  4. Crash 2: SIGSEGV during InnoDB: Starting shutdown... The shutdown tears down the io_uring queue and hits the same NULL. With a working liburing, the same corrupt datadir makes the server exit cleanly with rc=1.
Root cause

Header and library disagree about struct io_uring

liburing commit f5cd4eb2 (August 2022, released in 2.3) added cached copies of the queue mask and size to the public struct, in bytes that used to be padding. The inline helpers in the 2.3+ headers read those copies. Older libraries keep the library version liburing.so.2 and clear the padding in io_uring_queue_mmap(), so the cached size reads as 0.

Offsetliburing ≤ 2.2 (e.g. SUSE 2.1)liburing ≥ 2.3 (MariaDB built against 2.9)
0x38sqessqes
0x44sqe_tailsqe_tail
0x48ring_szring_sz
0x50ring_ptrring_ptr
0x58pad[0] = 0ring_mask
0x5cpad[1] = 0ring_entries
0x60pad[2], pad[3]pad[0], pad[1]

liburing 2.9 src/include/liburing.h, compiled into mariadbd

IOURINGINLINE struct io_uring_sqe *_io_uring_get_sqe(struct io_uring *ring)
{
	...
	head = *sq->khead;
	/* ring_entries is 0 with a pre-2.3 library */
	if (next - head <= sq->ring_entries) {
		sqe = &sq->sqes[(sq->sqe_tail & sq->ring_mask) << shift];
		...
		return sqe;
	}
	return NULL;
}

MariaDB tpool/aio_liburing.cc at e9ff0bf7

// line 99, ~aio_uring()  -> crash 2
io_uring_sqe *sqe= io_uring_get_sqe(&uring_);
io_uring_prep_nop(sqe);

// line 125, submit_io()  -> crash 1
io_uring_sqe *sqe= io_uring_get_sqe(&uring_);
if (cb->m_opcode == aio_opcode::AIO_PREAD)
  io_uring_prep_readv(sqe, ...);
else
  io_uring_prep_writev(sqe, ...);

Disassembly of the stripped 12.3.4 mariadbd (build ID 5e20b928…). uring_ sits at offset 8 inside aio_uring, so +0x60/+0x64 are the struct's 0x58/0x5c.

submit_io(), write request: crash 1 address +0x119a5e0
119a589: cmp    0x64(%r14),%r9d     ; next - head  vs  ring_entries (0)
119a58d: ja     119a640             ; queue reported full
119a640: xor    %eax,%eax           ; sqe = NULL
119a642: jmp    119a5d0             ; prepare the request anyway
119a5e0: movb   $0x2,(%rax)         ; sqe->opcode = IORING_OP_WRITEV at address 0

~aio_uring(): crash 2 address +0x119aa90 (compiler-isolated NULL path)
119aa90: movb   $0x0,0x0            ; sqe->opcode = IORING_OP_NOP at address 0
119aa98: ud2
Packaging

Why zypper installs it anyway

The RPM dependencies generated for MariaDB-server only record the newest liburing symbol version the binary calls:

rpm -q --requires MariaDB-server | grep uring

liburing.so.2()(64bit)
liburing.so.2(LIBURING_2.0)(64bit)
liburing.so.2(LIBURING_2.1)(64bit)

rpm -q --changelog liburing2 (SLE 15 SP7, 2.9-150700.10.3.1)

* Tue May 13 2025 gabriel.bertazi@suse.com
- Update to liburing 2.9 (PED-12844)
...
* Wed Oct 13 2021 ddiss@suse.com
- update to 2.1 (bsc#1193522)

A system with liburing2 2.1 satisfies every requirement, so the install succeeds and the server crashes on its first asynchronous write. Nothing in liburing's library version or symbol versions marks the 2.3 change.

Reproduction

What was run in a SLES 15.7 container

Base image registry.suse.com/bci/bci-base:15.7, MariaDB-server from build 76750, --security-opt seccomp=unconfined so InnoDB can use io_uring, host kernel 7.0.

SetupliburingInnoDB I/OResult
Datadir on overlayfs2.9io_uring, buffered log21 / 21 ok bootstrap runs
Datadir on an ext4 volume2.9io_uring, O_DIRECT log, same as the VM31 / 31 ok bootstrap runs
ext4, page 0 of ibdata1 zeroed2.9sameclean abort same InnoDB errors as the VM, rc=1, no crash
ext4, fresh datadir2.1sameSIGSEGV bootstrap at +0x119a5e0, ibdata1 header left as zeros
ext4, datadir left by the previous row2.1sameSIGSEGV server start at +0x119aa90 after "Data structure corruption", rc=139
FrameVM, crash 1Container, liburing 2.1VM, crash 2Container, liburing 2.1
crash site+0x119a5e0+0x119a5e0+0x119aa90+0x119aa90
caller+0xfdb8b2+0xfdb8b2+0xfdb004+0xfdb004
+0x112da43+0x112da43+0x1067ac6+0x1067ac6
+0x10f4268+0x10f4268+0xf71eb5+0xf71eb5
+0x10f5f3c+0x10f5f3cha_initialize_handlerton+0x87ha_initialize_handlerton+0x87
+0x7c9c5e+0x7c9c5eplugin_init+0x9daplugin_init+0x9da
thread entry+0x10f6b58+0x10f6b58mysqld_main+0x4a2mysqld_main+0x4a2

Minimal reproducer, inside a SLES 15.7 container with MariaDB-server from build 76750

zypper -n in gcc make
curl -sL https://github.com/axboe/liburing/archive/refs/tags/liburing-2.1.tar.gz | tar xz
cd liburing-liburing-2.1 && ./configure && make -C src
ln -s liburing.so.2.1.0 src/liburing.so.2
LD_LIBRARY_PATH=$PWD/src mariadb-install-db --rpm --user=mysql      # crash 1
LD_LIBRARY_PATH=$PWD/src /usr/sbin/mariadbd --user=mysql            # crash 2

The test itself copied the liburing-2.1 source from a local clone of the upstream repository instead of downloading the tarball; the build steps are the same.

Ruled out

Other suspects

SuspectWhy it isn't the cause
SELinuxThe log collection reports "SELinux config not present". SLES 15 uses AppArmor, and a denial returns a permission error, not SIGSEGV.
Other MariaDB packagesCrash 1 happened before any plugin package was installed. Crash 2 reproduces with MariaDB-server alone.
Kernel (VM 6.4.0-150700.51)Not needed for the crash. Both crashes reproduce on a 7.0 host kernel with liburing 2.1 and don't happen there with 2.9. The VM that crashed has liburing 2.1.
Container seccomp / filesystemio_uring was active in every run. The ext4 runs used the same O_DIRECT log path as the VM's xfs.
"Data structure corruption"A result of crash 1 leaving ibdata1 empty. With a working liburing it ends in a clean abort.
liburing history

Known upstream, never fixed in the library

  1. SUSE updates liburing2 to 2.1 for SLE 15. SUSE changelog, bsc#1193522
  2. Commit f5cd4eb2 "liburing: cache ring sizes and masks", released in 2.3. Old binaries keep working with the new library; new binaries don't work with an old one. axboe/liburing
  3. Issue #724 "liburing 2.3 breaks ABI w/o SOVERSION bump", filed by the Debian maintainer. It names this commit and this failure mode. axboe/liburing
  4. Azure Linux references #724 from two pull requests (#4530, #4607). microsoft/azurelinux
  5. Issue #890 "io_uring_get_sqe always returns null". The maintainer suspects a header/library mismatch. axboe/liburing
  6. #724 closed as completed, without a library version bump; it stays .so.2. In the thread, the Debian maintainer proposes raising the minimum liburing version in distro packaging instead. axboe/liburing
  7. Commit d1c10035 adds a header comment saying the inline io_uring_get_sqe() "breaks seamless updates of liburing.so". axboe/liburing
  8. SUSE updates liburing2 to 2.9 (PED-12844). Systems that never pulled this update still have 2.1. SUSE changelog
  9. Build 76750 install test crashes on bb-hz-bbw5-sles-1507-amd64, whose kernel is the April 2025 SP7 build. buildbot log
  10. rpm -q liburing2 on bb-ro-apexis-bbw03-x64-sles-1507-amd64 returns 2.9-150700.10.3.1. Its kernel is 6.4.0-150700.53.73, newer than bbw5's 6.4.0-150700.51, so the two hosts' images differ. worker console
  11. rpm -q liburing2 on bb-hz-bbw5-sles-1507-amd64, the VM that crashed, returns 2.1-150400.2.4. worker console
Next steps

Fixes

done

Check the VM

bbw5 has liburing2-2.1-150400.2.4. The dev VM has 2.9.

Owner: CI

CI

Update the VM image

Update liburing2 in the bbw5 SLES 15.7 image, or refresh the whole image to match the dev VM. Its kernel is also still the April 2025 release.

Owner: CI

MDEV

Require liburing2 ≥ 2.3

RPMs built against liburing 2.3+ headers should require liburing2 >= 2.3, so an old system fails at install time instead of crashing at runtime.

Owner: MariaDB packaging

MDEV

Check for a NULL entry

submit_io() and ~aio_uring() in tpool/aio_liburing.cc should handle a NULL from io_uring_get_sqe() instead of writing through it.

Owner: MariaDB server

Unrelated, found in the same log: scripts/rpm-install.sh writes wsrep_provider=/usr/lib*/galera*/libgalera_smm.so literally into galera.cnf, because shells don't expand wildcards in a variable assignment. It's harmless while wsrep is off.