Conversation
awilczyns
requested review from
DawidWesierski4,
Sakoram,
moleksy and
soopel
as code owners
October 1, 2026 10:38
awilczyns
added this pull request to stack #1778
October 1, 2026 10:48
awilczyns
force-pushed
the
fix/compiler-hardening
branch
from
October 2, 2026 11:26
12a6cb4 to
ccd1a77
Compare
Ubuntu gcc adds -z now to PIE executables only, so the shared objects of DPDK, FFmpeg, openh264 and the MTL, GStreamer and codec plugins had partial RELRO and a writable GOT. RHEL-family gcc applies none of the hardening flags by default. Set the hardening flags in the meson projects of the shipped MTL components and pass them to DPDK, openh264 and FFmpeg from their build scripts. The format flags are passed without a probe: meson probes each flag alone, which drops -Werror=format-security on RHEL gcc. systemtap's dtrace compiles the USDT object with CFLAGS from the environment only, so it gets -fcf-protection=full there, or ld drops IBT and SHSTK from libmtl.so. _FORTIFY_SOURCE=2 is added only when optimizing and when the compiler does not already set a level (Ubuntu 24.04 gcc sets 3). The level is read from the compiler's predefined macros, as meson 1.11 and later run cc.get_define() with -U_FORTIFY_SOURCE. Signed-off-by: Wilczynski, Andrzej <andrzej.wilczynski@intel.com>
x86inc.asm marks every NASM object SHSTK only and emits no endbr64. ld ANDs the CET property over all objects, so libavcodec, libavfilter, libavutil, libswresample and libswscale were linked without IBT however the C code was compiled. The new FFmpeg 7.0 patch makes the x86 code IBT-correct first: endbr64 at every indirect branch target, notrack for the computed jumps into the unrolled mlpdsp filter. Only then does it mark the NASM objects IBT and SHSTK. endbr64 is a NOP on CPUs without CET. Signed-off-by: Wilczynski, Andrzej <andrzej.wilczynski@intel.com>
validate-cache.sh now runs check-hardening.sh on the dpdk, mtl, ffmpeg, gstreamer and plugins caches, and the rocky9 image build runs it on what it installs. Each fails on any x86-64 executable or shared object without full RELRO, a non-executable stack, PIE, or CET IBT and SHSTK, and on a given path that holds no such file. libopenh264 is exempt from the CET check only: its assembly carries no CET mark. .dockerignore lets the script into the image build context, and a change to it reruns the image builds. In branch mode, CI from the workflow commit validates the trees of another ref, HEAD. validate-cache.sh checks them with HEAD's own check-hardening.sh, and not at all when HEAD predates it. Signed-off-by: Wilczynski, Andrzej <andrzej.wilczynski@intel.com>
awilczyns
force-pushed
the
fix/compiler-hardening
branch
from
October 2, 2026 16:20
ccd1a77 to
3938f00
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds the shipped MTL components, DPDK, openh264 and FFmpeg on Linux with hardening flags: stack protector, stack clash protection, CET,
_FORTIFY_SOURCE, format checks, full RELRO, a non-executable stack and PIE.It also fixes a security scan finding on the FFmpeg 7.0 libraries MTL delivers:
A CI check keeps both fixed. 3 commits, 20 files, +481/−13.
Root causes
-z nowonly to PIE executables, never to-shared. FFmpeg'sconfigure, DPDK and several MTL meson projects don't pass it themselves.st22_avcodecand 2 sample plugins.x86inc.asmmarks every NASM object SHSTK only and emits noendbr64.ldANDs the CET property over all input objects.docker/rocky9.dockerfile), MTL, DPDK and FFmpeg got no stack protector, CET, FORTIFY or PIE, and onlylibmtl.sohad full RELRO.What each commit does
Build: Add compiler hardening flags
lib,app,plugins,plugins/st22_avcodec,manager,tests,tests/tools/RxTxApp,tests/tools/gstreamer_tools,ecosystem/gstreamer_plugin,ecosystem/obs_mtl/linux-mtlandgpu_direct.-fstack-protector-strong -fstack-clash-protection -fcf-protection=fullthroughget_supported_arguments, which drops a flag a compiler doesn't support instead of failing the build.-Wformat -Wformat-security -Werror=format-securitywithout a probe. meson probes each flag on its own, and on RHEL gcc the probe of-Werror=format-securityfails with'-Wformat-security' ignored without '-Wformat', which would drop it. Every gcc and clang MTL builds with accepts the three.-Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack.if not is_windows.-z now -z relroinlib/meson.buildis replaced by the block, not duplicated._FORTIFY_SOURCE.-D_FORTIFY_SOURCE=2is added only when optimizing and when neither the compiler norc_args/cpp_argssets a level.=2without a warning and lower the level, so it must not be added there.cc -O2 -dM -E). meson 1.11 and later runcc.get_define()with-U_FORTIFY_SOURCE, so it can't see the level.dtrace -Gcompiles the USDT provider object withCFLAGSfrom the environment only. Without-fcf-protection=fullthere, the object has no.note.gnu.property, andlddrops IBT and SHSTK fromlibmtl.so. That is what happened on RHEL, where gcc doesn't enable CET by default.b_pie=trueinapp,manager,testsandtests/tools/RxTxApp.script/build_dpdk.shpasses the flags with-Dc_args,-Dc_link_argsand-Db_pie=true.-Dc_argsreplacesCFLAGS, so the script prepends the caller'sCFLAGS/LDFLAGS.ecosystem/ffmpeg_plugin/build.shpasses the flags:--extra-cflags,--extra-ldflagsand--extra-ldexeflags=-pie;CFLAGS/LDFLAGSin the environment, which its Makefile appends to.doc/build.md§4.5 documents the flags and the manual DPDK command.Fix: Add CET IBT to the FFmpeg 7.0 x86 assembly
New
ecosystem/ffmpeg_plugin/7.0/0002-x86-add-Intel-CET-IBT-support.patch(4 FFmpeg files, +38/−4). The existing patch loop applies it after 0001. It makes the assembly IBT-correct first, and only then marks it IBT:libavutil/x86/x86inc.asmendbr64at everycglobal/cvisibleentry, and the property note becomes IBT and SHSTK. Both apply only with NASM ≥ 2.15.01; older NASM builds exactly as before.libavcodec/x86/vvc/vvc_mc.asm.wN_ibt:labels, each anendbr64that falls through into.wN. That keeps the endbr out of the loop.libavcodec/x86/mlpdsp_init.cnotrack jmp, which is what GCC emits for switch tables.libswscale/x86/hscale_fast_bilinear_simd.cendbr64(x86-64 only). The size pass counts those 4 bytes.endbr64is a NOP on CPUs without CET, and.textgrows by 0.8 %. OpenBSD, which enforces IBT in user space, has similar patches in its FFmpeg port, including the same.wN_ibtlabels in vvc_mc. dav1d MR 1775 does the same for x86inc.Setting only the note bit, or linking with
-z ibt, would produce a false mark that faults under IBT enforcement.Ci: Check compiler hardening of the dependency caches
.github/scripts/ci/check-hardening.sh PATH...checks every x86-64 executable and shared object under the given paths. It requires all of:GNU_RELROandBIND_NOW(full RELRO);GNU_STACK, with any alignment;ET_DYN);x86 feature: IBT, SHSTK.It is fail-closed. Every check needs a positive match, and every given path must hold at least one x86-64 ELF file, so a missing or empty path fails, also next to a good one.
validate-cache.shruns it on thedpdk,mtl,ffmpeg,gstreamerandpluginscaches. So their builds and restores are checked, without a new workflow.branchinput ofbuild.ymland the pytest workflows), the trees come from another ref,HEAD, and CI from the workflow commit.validate-cache.shchecks them withHEAD's owncheck-hardening.sh, and not at all whenHEADpredates it, so a ref is held to its own hardening. A git error fails the validation./install,RxTxApp,MtlManagerandKahawaiTest, so a regression that only RHEL-family gcc shows failsDocker Build..dockerignorelets the script into the build context, and a change to the script reruns the image builds.libopenh264is exempt from the CET check only. Its assembly has no CET mark and no flag can add one. RELRO, BIND_NOW, NX and PIE are still required of it. A process that loads it runs without CET, as on main.Verification
Toolchain: Ubuntu 24.04, gcc 13.3, nasm 2.16.01 and binutils 2.42 (the CI runners' toolchain). All builds ran in a private clone.
The CI flow on main and on this branch (
build-dependencies.sh, thenvalidate-cache.sh):On main, the ffmpeg check finds what the scan found, and two libraries the scan doesn't list:
no BIND_NOW IBT/SHSTK;no BIND_NOW;no BIND_NOW IBT/SHSTK.Rocky 9 (gcc 11.5). The rocky9 image build passes the check:
libmtl.sohasx86 feature: IBT, SHSTK, and 54 of 54 compile commands carry-Werror=format-security. The same dockerfile on the tree without the format and USDT changes fails it withlibmtl.so is not hardened: no IBT/SHSTK.The check really fails:
-z norelro,-z lazy,-z execstack,-no-pie,-fcf-protection=none, and with an SHSTK-only NASM object linked in.no IBT/SHSTK, and main's openh264 still fails withno BIND_NOW.Branch mode:
build.ymldispatched on this branch withbranchset to today's main restored main's caches and failedEvaluate cache results: 210 of 231 dpdk filesno BIND_NOW(run 37025547441).overlay-testsleaves them and forged trees that pass every other check:HEADis main, and fails withno BIND_NOWwhenHEADis this branch or a later ref;hardening: 1 ELF files checked, also when the workflow commit carries a strictercheck-hardening.shthat no tree passes;evaluate-caches.shgives the same results;if(a git error skips the check), an always-skipped check, a probe of the index instead ofHEAD, and the workflow commit'scheck-hardening.shinstead ofHEAD's.The IBT is real, not just a mark:
Static audit of every NASM object:
endbr64;Intel SDE with IBT enforcement (
sde64 -spr -cet 1 -cet_raise 0). ENDBRANCH errors with the x86inc hunk only, then with the full patch:checkasm, all 9729 testsffmpegWithout any patch, a full run gives 65845.
The output is the same with and without the patch: checkasm passes, and the MLP and swscale checksums match.
The flags are really applied (compile flags leave no mark in the ELF):
compile_commands.jsonentries carry the flags.__stack_chk_failand__*_chk._FORTIFY_SOURCEblock, in all 11 projects built with--werror, with each meson version the CI uses with that compiler (0.61.2 to 1.12.1):-D_FORTIFY_SOURCE=2;-D_FORTIFY_SOURCE=1inCFLAGSstays 1;Nothing broken:
b_pielinks, and the result runs under wine.Notes for reviewers
ice:script/build_dpdk.shis in thedpdkcache key, at the root of the chain, andecosystem/ffmpeg_plugin/build.shis in thejpegxskey.-Werror=format-securityis new for DPDK, openh264 and FFmpeg. All three build clean with it.-z nowmoves symbol binding to load time. On Ubuntu the generated C code doesn't change, because those compile flags are already gcc defaults there. On RHEL it does change, and that cost isn't benchmarked.Not in this PR
FFmpeg CVEs. The same scan lists 20 CVEs against FFmpeg 7.0.3:
release/7.0already contains the fixes for 12 of them;zmqsendtool, or the TensorFlow filter);FFmpeg 8.1.3 is the lowest release that has all the fixes and isn't matched by NVD's version ranges. Moving to it means porting the MTL avdevice plugin and patch 0002 to FFmpeg 8 (
libavcodec.so.62), so it is a separate PR.openh264 CET. It needs
endbr64in openh264's assembly, and upstream openh264 has none.FFmpeg 6.1 and 4.4. Their assembly has no CET note, so they build without IBT and SHSTK.
tools/set_tai_offset, and libbpf and libxdp fromscript/build_ebpf_xdp.sh. They keep their own build flags and aren't checked.set_tai_offsetisn't installed; the images ship libbpf and libxdp.SVT-JPEG-XS, the ICE kernel module, Windows. Their build flags are unchanged. The Windows equivalents (
/guard:cf,/CETCOMPAT) aren't covered.Unpinned FFmpeg source.
build.shstill downloads the movingrelease/7.0branch head, not a tag.