[Bug]: libmilvus-storage.so is built with executable stack
Environment
- Milvus version: 2.7.0 / master image
- Milvus image:
harbor.milvus.io/manta/milvus:master-20260616-778f53f-profile - Deployment mode: cluster, but this issue is a build artifact issue and is not tied to deployment mode
- MQ type: N/A, independent of MQ
- SDK version: N/A
- OS: Linux x86_64
- CPU/Memory: N/A
- GPU: N/A
Current Behavior
libmilvus-storage.so is built with an executable stack (GNU_STACK RWE). After the library is loaded by Milvus, the process has many anonymous executable stack mappings. This makes eBPF profiling harder to unwind/symbolize and causes large [unknown] areas in Pyroscope eBPF CPU profiles.
Observed ELF stack flags from the Milvus image:
RW /milvus/bin/milvus
RW /milvus/lib/libmilvus_core.so
RW /milvus/lib/libknowhere.so
RWE /milvus/lib/libmilvus-storage.so
Observed runtime mappings from a Milvus datanode process:
threads=168
rwxp_anon_maps=171
7f77bd640000-7f77bde40000 rwxp 00000000 00:00 0
7f77c3dd0000-7f77c45d0000 rwxp 00000000 00:00 0
7f77c6deb000-7f77c75eb000 rwxp 00000000 00:00 0
7f77c8df0000-7f77c95f0000 rwxp 00000000 00:00 0
7f77cba80000-7f77cc280000 rwxp 00000000 00:00 0
In eBPF CPU profiles collected during import, [unknown] accounted for a large part of samples. For example:
v2 full profile: [unknown] flat 141.03s / 274.29s = 51.42%
v3 import profile: [unknown] flat 145.48s / 303.32s = 47.96%
Native symbols such as ZSTD and Rust/Tantivy functions can be resolved, so this is not simply caused by stripped binaries or missing symbols.
Expected Behavior
libmilvus-storage.so should be built with a non-executable stack:
GNU_STACK RW
Loading Milvus storage should not make process thread stacks executable, and eBPF profiling should not get large [unknown] regions because of anonymous executable stack mappings.
Steps To Reproduce
- Build or use a Milvus image that contains the current
libmilvus-storage.so. - Check ELF stack flags:
readelf -W -l /milvus/lib/libmilvus-storage.so | grep GNU_STACK
Actual result:
GNU_STACK ... RWE ...
- Start a Milvus component that loads
libmilvus-storage.so. - Check anonymous executable mappings:
pid=$(pidof milvus)
awk '$2 ~ /^rwxp$/ && $6=="" {print}' /proc/$pid/maps | head
Actual result: many anonymous rwxp mappings are present.
Minimal Reproduction Script
N/A: this is a native build artifact issue. It can be reproduced by checking the ELF program header of libmilvus-storage.so with readelf.
Milvus Log
N/A: this issue does not produce Milvus error logs. It affects native binary metadata and eBPF profiling quality.
Anything else?
The likely source is the Rust bridge linked into libmilvus-storage.so.
In milvus-storage:
cpp/CMakeLists.txt
-> adds src/format/bridge/rust
-> links prsbridge into milvus-storage
cpp/src/format/bridge/rust/Cargo.toml
-> crate-type = ["staticlib"]
-> depends on sqlparser
The dependency chain is:
rust-bridge -> sqlparser -> recursive -> stacker -> psm
psm 0.1.28 builds platform assembly. On Linux x86_64 it compiles:
psm-0.1.28/src/arch/x86_64.s
That object does not contain .note.GNU-stack.
A local object-level check showed:
psm_x86_64.o: .note.GNU-stack=ABSENT
zstd_huf.o: .note.GNU-stack=['-']
blake3_avx2.o: .note.GNU-stack=['-']
ring also has assembly, but its asm_base.h explicitly emits .note.GNU-stack, so it is less likely to be the source.
Suggested fix direction:
target_link_options(milvus-storage PRIVATE -Wl,-z,noexecstack)
This should be added to the milvus-storage target, preferably in the milvus-storage CMake itself or in the Milvus wrapper after add_subdirectory.
For diagnostics, a temporary linker warning can also confirm the source object:
target_link_options(milvus-storage PRIVATE -Wl,--warn-execstack)
Source: milvus-io/milvus