ols-1.9.0-16k-page.patch
Summary
openlitespeed segfaults during startup on Linux systems where the kernel page size is 16 KB (Apple Silicon under Asahi Linux, Raspberry Pi 5 with the 16K-page kernel, some ARM server kernels). Root cause: LSSHM_PAGESIZE is hardcoded to 0x2000 (8 KB) in src/shm/lsshmtypes.h, and the cache-manager shared-memory code consequently uses 8 KB-aligned file offsets in mmap() calls. On a 16 KB-page kernel, an 8 KB-aligned offset that isn't also 16 KB-aligned makes mmap() return EINVAL (per POSIX — file offset must be a multiple of the system page size). OLS's error-handling path then dereferences a munmap()'d pointer, producing SIGSEGV.
Fix is a two-line constant change. The on-disk SHM format is unaffected (it's organised in LSSHM_SHM_UNITSIZE = 1 KB chunks, independent of the page constant).
Environment
- Hardware: Apple Mac Mini M2 (Apple Silicon, ARMv8.5-A)
- OS: Ubuntu Asahi 24.04 LTS Server
- Kernel: 6.17.0-1001-asahi-arm
- Page size:
getconf PAGESIZE → 16384
- OLS: 1.9.0, built from source (
./build.sh -s -o OFF)
- Toolchain: gcc 13.3, glibc 2.39
Also reproduces with the LiteSpeed apt-repo binary (apt install openlitespeed from https://repo.litespeed.sh) — identical crash, same EINVAL mmap signature — so it isn't a build-config issue.
Reproduction
- Install OLS on any Linux system with a 16 KB-page kernel.
- Run
openlitespeed -t (config test) or systemctl start lshttpd.
- Process exits with SIGSEGV during cache-manager shared-memory initialization, before any listener binds. systemd shows
status=11/SEGV and restart-loops.
Diagnostic evidence
strace -f /usr/local/lsws/bin/openlitespeed -t (relevant tail):
openat(AT_FDCWD, "/usr/local/lsws/cachedata/.cacheman.shm", O_RDWR|O_CREAT|O_EXCL, 0640) = 8
fallocate(8, 0, 0, 40960) = 0
mmap(NULL, 2097152, PROT_NONE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0xffff923d0000
mmap(0xffff92400000, 40960, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 8, 0) = 0xffff92400000
fallocate(8, 0, 40960, 8192) = 0
mmap(0xffff9240a000, 8192, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 8, 0xa000) = -1 EINVAL (Invalid argument)
unlinkat(AT_FDCWD, "/usr/local/lsws/cachedata/.cacheman.shm", 0) = 0
munmap(0xffff92400000, 1048576) = 0
close(8) = 0
munmap(0xffff92ba0000, 8192) = 0
close(9) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xffff92ba0028} ---
+++ killed by SIGSEGV (core dumped) +++
The failing call:
mmap(0xffff9240a000, 8192, ..., MAP_SHARED|MAP_FIXED, 8, 0xa000) = -1 EINVAL
File offset 0xa000 (40960 = 5 × 8 KB) is NOT a multiple of 16 KB (40960 ÷ 16384 = 2.5). On 4 KB-page systems the same offset is also 4 KB-aligned and the call succeeds; on 16 KB-page systems the kernel correctly rejects it. See mmap(2): "The offset argument is constrained to be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE)."
The binary itself is fine — readelf -l shows LOAD segments with Align 0x10000 (64 KB), more than sufficient for any current page size:
LOAD 0x0000000000000000 ... R E 0x10000
LOAD 0x0000000000804b60 ... RW 0x10000
So the issue is purely in runtime use of mmap, not in the binary's load-time mapping.
Root cause
In src/shm/lsshmtypes.h:
#define LSSHM_PAGESIZE 0x2000 // min pagesize 8k
#define LSSHM_PAGEMASK 0xFFFFE000
LSSHM_PAGESIZE is the "page size" that LsShm uses internally for file extension and mmap() offsets. It's hardcoded to 8 KB, with the implicit assumption that 8 KB is always ≥ the system page size. That assumption breaks on 16 KB-page kernels.
The relevant uses (all runtime, no on-disk format dependency):
src/shm/lsshm.cpp:111 — LsShmSize_t LsShm::s_iPageSize = LSSHM_PAGESIZE; (runtime variable, drives mmap offsets)
src/shm/lsshmlock.cpp:65 — static LsShmSize_t s_iPageSize = LSSHM_PAGESIZE;
src/shm/addrmap.cpp:192 — start_offset = start_offset & ~(LSSHM_PAGESIZE - 1); (alignment math, auto-follows the constant)
src/shm/lsshmtypes.h:125 — #define LSSHM_INITSIZE LSSHM_PAGESIZE (auto-follows)
Note src/shm/lsshm.cpp:56 already uses getpagesize() correctly inside the posix_fallocate EINVAL/EOPNOTSUPP fallback path — so the code is partially page-size aware. The main code path just uses the hardcoded constant.
Fix
Two-line patch:
--- a/src/shm/lsshmtypes.h
+++ b/src/shm/lsshmtypes.h
@@ -109,8 +109,8 @@
#define LSSHM_VER_TYPE \
(((sizeof(LsShmOffset_t)<<4) | sizeof(LsShmXSize_t)) & (0xff)) // 8 bits
-#define LSSHM_PAGESIZE 0x2000 // min pagesize 8k
-#define LSSHM_PAGEMASK 0xFFFFE000
+#define LSSHM_PAGESIZE 0x4000 // min pagesize 16k (for 16K-page kernels)
+#define LSSHM_PAGEMASK 0xFFFFC000
#define LSSHM_MAXNAMELEN 12 // only 11 characters.
This bumps the internal page size to 16 KB, which is a multiple of both 4 KB and 16 KB system page sizes — so the fix is safe on existing 4 KB-page x86_64 and ARM64 systems as well as on the new 16 KB-page kernels.
After patching, rebuilding, and clearing any pre-existing cachedata/*.shm and cachedata/*.lock files (they're not on-disk-incompatible, but the failed-init runs left them orphaned), OLS starts cleanly on Apple Silicon and serves requests normally.
A more thorough long-term fix
Making LSSHM_PAGESIZE dynamic — std::max((size_t)0x2000, (size_t)sysconf(_SC_PAGESIZE)) at startup — would future-proof against hypothetical 32 KB or 64 KB-page kernels. That's a more invasive change since several uses are compile-time constants (alignment masks, struct field expressions), so it isn't a strict one-liner. The constant bump above is sufficient for all currently-shipping Linux distributions.
Affected platforms
Any Linux kernel configured with a 16 KB page size, including:
- Apple Silicon (M1/M2/M3/M4) on Asahi Linux (Fedora Asahi, Ubuntu Asahi, etc.)
- Raspberry Pi 5 with the 16K-page kernel variant (
CONFIG_ARM64_16K_PAGES=y)
- ARM server SKUs configured for 16 KB pages
- Some custom embedded kernels
Worth noting that the prebuilt aarch64 binaries shipped via the LiteSpeed apt repo (https://repo.litespeed.sh) carry the same bug; rebuilding those after the source fix would close the loop for users who don't build from source.
Verification post-patch
Apple M2 / Ubuntu Asahi 24.04 / kernel 6.17:
$ sudo /usr/local/lsws/bin/lswsctrl status
litespeed is running with PID 70929.
$ sudo ss -tlnp | grep -E ':8088|:7080'
LISTEN 0 4096 0.0.0.0:8088 0.0.0.0:* users:(("litespeed",pid=...))
LISTEN 0 4096 0.0.0.0:7080 0.0.0.0:* users:(("litespeed",pid=...))
$ curl -I http://localhost:8088/
HTTP/1.1 200 OK
server: LiteSpeed
...
Clean startup, listener binding, 200 response. No SEGV in journalctl -u lshttpd.
Happy to submit a pull request with the patch if useful, or you can apply it directly — it's two lines and the diff above is in unified format ready to patch -p1.
ols-1.9.0-16k-page.patch
Summary
openlitespeedsegfaults during startup on Linux systems where the kernel page size is 16 KB (Apple Silicon under Asahi Linux, Raspberry Pi 5 with the 16K-page kernel, some ARM server kernels). Root cause:LSSHM_PAGESIZEis hardcoded to0x2000(8 KB) insrc/shm/lsshmtypes.h, and the cache-manager shared-memory code consequently uses 8 KB-aligned file offsets inmmap()calls. On a 16 KB-page kernel, an 8 KB-aligned offset that isn't also 16 KB-aligned makesmmap()returnEINVAL(per POSIX — file offset must be a multiple of the system page size). OLS's error-handling path then dereferences amunmap()'d pointer, producing SIGSEGV.Fix is a two-line constant change. The on-disk SHM format is unaffected (it's organised in
LSSHM_SHM_UNITSIZE = 1 KBchunks, independent of the page constant).Environment
getconf PAGESIZE→16384./build.sh -s -o OFF)Also reproduces with the LiteSpeed apt-repo binary (
apt install openlitespeedfromhttps://repo.litespeed.sh) — identical crash, sameEINVALmmap signature — so it isn't a build-config issue.Reproduction
openlitespeed -t(config test) orsystemctl start lshttpd.status=11/SEGVand restart-loops.Diagnostic evidence
strace -f /usr/local/lsws/bin/openlitespeed -t(relevant tail):The failing call:
File offset
0xa000(40960 = 5 × 8 KB) is NOT a multiple of 16 KB (40960 ÷ 16384 = 2.5). On 4 KB-page systems the same offset is also 4 KB-aligned and the call succeeds; on 16 KB-page systems the kernel correctly rejects it. Seemmap(2): "The offset argument is constrained to be a multiple of the page size as returned bysysconf(_SC_PAGE_SIZE)."The binary itself is fine —
readelf -lshowsLOADsegments withAlign 0x10000(64 KB), more than sufficient for any current page size:So the issue is purely in runtime use of mmap, not in the binary's load-time mapping.
Root cause
In
src/shm/lsshmtypes.h:LSSHM_PAGESIZEis the "page size" that LsShm uses internally for file extension andmmap()offsets. It's hardcoded to 8 KB, with the implicit assumption that 8 KB is always ≥ the system page size. That assumption breaks on 16 KB-page kernels.The relevant uses (all runtime, no on-disk format dependency):
src/shm/lsshm.cpp:111—LsShmSize_t LsShm::s_iPageSize = LSSHM_PAGESIZE;(runtime variable, drives mmap offsets)src/shm/lsshmlock.cpp:65—static LsShmSize_t s_iPageSize = LSSHM_PAGESIZE;src/shm/addrmap.cpp:192—start_offset = start_offset & ~(LSSHM_PAGESIZE - 1);(alignment math, auto-follows the constant)src/shm/lsshmtypes.h:125—#define LSSHM_INITSIZE LSSHM_PAGESIZE(auto-follows)Note
src/shm/lsshm.cpp:56already usesgetpagesize()correctly inside theposix_fallocateEINVAL/EOPNOTSUPP fallback path — so the code is partially page-size aware. The main code path just uses the hardcoded constant.Fix
Two-line patch:
This bumps the internal page size to 16 KB, which is a multiple of both 4 KB and 16 KB system page sizes — so the fix is safe on existing 4 KB-page x86_64 and ARM64 systems as well as on the new 16 KB-page kernels.
After patching, rebuilding, and clearing any pre-existing
cachedata/*.shmandcachedata/*.lockfiles (they're not on-disk-incompatible, but the failed-init runs left them orphaned), OLS starts cleanly on Apple Silicon and serves requests normally.A more thorough long-term fix
Making
LSSHM_PAGESIZEdynamic —std::max((size_t)0x2000, (size_t)sysconf(_SC_PAGESIZE))at startup — would future-proof against hypothetical 32 KB or 64 KB-page kernels. That's a more invasive change since several uses are compile-time constants (alignment masks, struct field expressions), so it isn't a strict one-liner. The constant bump above is sufficient for all currently-shipping Linux distributions.Affected platforms
Any Linux kernel configured with a 16 KB page size, including:
CONFIG_ARM64_16K_PAGES=y)Worth noting that the prebuilt aarch64 binaries shipped via the LiteSpeed apt repo (
https://repo.litespeed.sh) carry the same bug; rebuilding those after the source fix would close the loop for users who don't build from source.Verification post-patch
Apple M2 / Ubuntu Asahi 24.04 / kernel 6.17:
Clean startup, listener binding, 200 response. No SEGV in
journalctl -u lshttpd.Happy to submit a pull request with the patch if useful, or you can apply it directly — it's two lines and the diff above is in unified format ready to
patch -p1.