Skip to content

Full kbuild support (atop of https://github.com/minipli-oss/open-gpu-kernel-modules/tree/fixes)#1069

Draft
minipli-oss wants to merge 37 commits intoNVIDIA:mainfrom
minipli-oss:kbuild
Draft

Full kbuild support (atop of https://github.com/minipli-oss/open-gpu-kernel-modules/tree/fixes)#1069
minipli-oss wants to merge 37 commits intoNVIDIA:mainfrom
minipli-oss:kbuild

Conversation

@minipli-oss
Copy link

This set of changes makes it possible to compile the OS-agnostic part below src/ to be compiled with Linux's kbuild which brings a lot of benefits, as in automatically picking up the right compiler flags and, hence, code instrumentation to support features like RANDSTRUCT, kCFI and various grsecurity features.

The changes build atop of the fixes branch (#1068).

Most significant changes are to get rid of system headers completely, which was kinda challenging for the C++ parts of src/nvidia-modeset/, as well as actually supporting C++ source files via kbuild. I took the poor man's approach and bend the rules for C to get all *FLAGS* / *flags* handling for free instead of reimplementing it. A "proper" implementation may do something more sophisticated.

Another challenge was to work around a limitation of kbuild for modules with lots of object files. kbuild simply doesn't allow compound object files for modules and there is, apparently, no interest in fixing this. So I had to implement a hack similar to this using a fake module. A little ugly under the hood, but works quite well.

The final obstacle was C++'s COMDAT sections confusing objtool and the linker. After finally understanding how they work, I was able fix that by simply collapsing them prior to linking the final module.

All in all quite some pragmatic choices, therefore just a proposed as a draft. However, I was able to successfully build the modules and actually use them.

Building with kbuild also allows to enable a lot of debugging options. For example, one of my build configs had UBSAN enabled which triggered a few interesting splats:

root@gpu-dev:~# dmesg | grep UBSAN -A1
[    8.831486] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/mem_mgr/io_vaspace.c:444:36
[    8.831490] index 1 is out of range for type 'RmPhysAddr [1]'
--
[    9.119483] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/arch/nvalloc/unix/src/registry.c:564:60
[    9.119487] index 1 is out of range for type 'PACKED_REGISTRY_ENTRY [*]'
--
[    9.924916] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/gpu/fifo/arch/maxwell/kernel_fifo_gm107.c:776:45
[    9.924920] index 15 is out of range for type 'NvU32 [15]'
--
[    9.957044] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/gpu/mem_mgr/mem_desc.c:2496:28
[    9.957047] index 1 is out of range for type 'RmPhysAddr [1]'
--
[    9.969087] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/mem_mgr/io_vaspace.c:336:68
[    9.969090] index 1 is out of range for type 'RmPhysAddr [1]'
--
[    9.981216] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/mem_mgr/io_vaspace.c:336:35
[    9.981219] index 1 is out of range for type 'RmPhysAddr [1]'
--
[   10.139401] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/rmapi/rmapi_cache_handlers.c:107:91
[   10.139470] index 4294967295 is out of range for type '<unknown> [32]'
--
[   10.150784] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/rmapi/rmapi_cache_handlers.c:108:91
[   10.150787] index 4294967295 is out of range for type '<unknown> [32]'
--
[   12.455149] UBSAN: array-index-out-of-bounds in /home/minipli/src/open-gpu-kernel-modules/kernel-open/../src/nvidia/src/kernel/gpu/mem_mgr/mem_desc.c:2503:32
[   12.455152] index 1 is out of range for type 'RmPhysAddr [1]'

Lots of these are false positives, as the code is making use of old-style flexibe arrays. However, the reports for kernel_fifo_gm107.c (letting though an invalid index (15)) and rmapi_cache_handlers.c or (index -1) may deserve a closer look.

minipli-oss and others added 30 commits March 18, 2026 06:35
The return type is expected to be 'enum drm_mode_status', fix that.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
nvswitch_task_dispatch() is supposed to be of type nv_q_func_t which
expects a void pointer argument.

Fix that to make it compatible with strongly type-based CFI
implementations like RAP, as found in grsecurity.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The retun type should be 'void' as all users of tmrCtrlCmdEventCreate()
pass a 'void (*)(void *)' function pointer.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
gcc warns about the use of the wrong enum type, fix that!

  .../src/nvidia/src/kernel/gpu/mem_mgr/arch/maxwell/virt_mem_allocator_gm107.c:1720:76: warning: implicit conversion from ‘GMMU_APERTURE’ to ‘FB_CACHE_MEMTYPE’ [-Wenum-conversion]
   1720 |         kmemsysCacheOp_HAL(pGpu, GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu), NULL, aperture, FB_CACHE_INVALIDATE);
        |                                                                            ^~~~~~~~
  .../src/nvidia/generated/g_kern_mem_sys_nvoc.h:632:135: note: in definition of macro ‘kmemsysCacheOp_HAL’
    632 | #define kmemsysCacheOp_HAL(pGpu, pKernelMemorySystem, arg3, arg4, operation) kmemsysCacheOp_DISPATCH(pGpu, pKernelMemorySystem, arg3, arg4, operation)
        |                                                                                                                                       ^~~~
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
In case tmrEventCreate() fails, we will copy the uninitialized value of
the stack local variable 'pEvent' and expose it to the caller.

Prevent that by initializing it to NULL, as all other users do.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Targets added to 'clean-files' shouldn't have the '$(obj)/' prefix or
won't be found for the 'make clean' target.

Fix that to ensure 'nv_compiler.h' will be removed on 'make clean'.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The drm_connector_helper_funcs.mode_valid() hook is expected to return a
'enum drm_mode_status' since Linux commit 0993f1d0d8a1 ("drm: Make the
connector mode_valid() func return a drm_mode_status enum") merged in
v3.14.

Add a conftest test for it to fix that without breaking older kernels.

The test is slightly evolved as C considers mismatched enum vs. int
return types as compatible but they still violate CFI checks for
advanced implementations like RAP as found in grsecurity.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
There is no need to initialize 'g_exported_uvm_events' at runtime,
initialize at compile time.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Actual implementations of the NVEvoSubDevRec.scanLockState hook want an
'NVEvoLockAction'-typed 'action' argument. Fix that.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Test the kernel for having RANDSTRUCT enabled and break the build, if it
is as this would otherwise lead to ABI-incompatibilities with the
OS-agnostic part that doesn't get compiled with RANDSTRCUT enabled.

A visible outcome of this would be calling the wrong callback function
via structures that purely consist of function pointers (which
RANDSTRUCT randomizes).

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Get rid of system header includes in preparation for upcoming kbuild
support which prevents their usage via -nostdinc.

The change is mostly mechanic, by making use of appropriate substitutes:

- stddef.h gets replaced by a new nv-stddef.h header that uses kernel
  headers when appropriate defines are set or the regular system header
  otherwise,

- stdarg.h gets replaced by nv_stdarg.h, which already uses kernel
  headers, if needed

For softfloat the additional headers get wrapped:

- stdbool.h, which makes use of Linux's <linux/types.h> for kernel
  builds and the system's <stdbool.h> otherwise.

- stdint.h, which also makes use of Linux's <linux/types.h> for kernel
  builds but also provide the missing [u]int_fast*_t typedefs

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Use designated initializers for initializing static nvswitch discovery
handler objects to resolve incompatibilities with Linux's RANDSTRUCT gcc
plugin.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Use designated initializers for initializing static Nv3dHal objects to
resolve incompatibilities with Linux's RANDSTRUCT gcc plugin.

Signed-off-by: PaX Team <pageexec@freemail.hu>
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Use designated initializers for initializing NvKmsNvPushImports to
resolve incompatibilities with Linux's RANDSTRUCT gcc plugin.

Signed-off-by: PaX Team <pageexec@freemail.hu>
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Use designated initializers for initializing static MMU walk callback
objects to resolve incompatibilities with Linux's RANDSTRUCT gcc plugin.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Make the union of GPUHWREG use proper flexible arrays to avoid UBSAN
out-of-bounds warnings when accessing hardware registers.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Define 'NULL' directly instead of depending on system headers to do so.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The ASSIGN_PER_OBJ_CFLAGS helper tries to support older kbuild versions
that used the full path as the target-stem by not only assigning the
basenamed "CFLAGS_" variable but also one with the full path. However,
if the object file's directory part is empty, ASSIGN_PER_OBJ_CFLAGS
would add the flags twice, as "$(notdir $(1))" and "$(1)" evaluate to
the same.

Avoid that by filtering duplicates via $(sort ...).

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Provide an ASSIGN_PER_OBJ_CFLAGS_REMOVE macro to be able to set
per-object-file CFLAGS_REMOVE variables.

For it to be effective, move the *.Kbuild include to after setting early
cflags, allowing to override these via ASSIGN_PER_OBJ_CFLAGS_REMOVE.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Add support for the GENERATE_NVIDSTRING macro for pure kbuild-based
builds.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Provide ASSIGN_PER_OBJ_LDFLAGS and ASSIGN_PER_OBJ_OBJCOPYFLAGS macros
that can be used to to set per-object-file LDFLAGS and OBJCOPYFLAGS
variables.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Add rules to work around kbuild's lack of compound object file support
for modules.

It's implemented by building stub modules composed of the object files
intended to group plus kernel-open/common/mod_stub.o for the .modinfo
bits which get stripped by an intermediate objcopy call.

The stub module should be named $foo.stub.o, the created (and depended
on) object file will be called $foo.clean.o.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Don't build the regular modules during preparation, which is an
intermediate step for full kbuild support.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Extract compiler flags into defs.mk for reuse by upcomming kbuild
support.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Move the definitions of LINKER_SCRIPT and EXPORTS_LINK_COMMAND to
srcs.mk.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Provide a Kbuild file to be able to build src/nvidia/ using Linux's
kbuild. It's meant to be included by kernel-open/nvidia/.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Support building the dependent src/nv-kernel.o using Linux's kbuild.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Try to deduce a fitting C++ compiler from the kernel's config and pass
it as CXX to the kernel's make file.

This is required for the upcomming kbuild support.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Wrap C++-defined types and keywords prior to including Linux kernel
headers to avoid clashing with the ones defined there.

This is required for the upcoming kbuild support which cannot make use
of standard system headers but has to rely on kernel headers.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Make sure to always declare xz_crc32_init() in xz.h as nvidia-3d-fermi.c
unconditionally makes use of it.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The preprocessor symbol DP_OPTION_AUTO_ENABLE_MST_STREAM_ENCR doesn't get
defined by the build system, causing build errors under '-Werror=undef'.

Fix that by providing a default definition of 0 for it.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Extract compiler flags into defs.mk as well as shaders to srcs.mk for
reuse by upcomming kbuild support.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Provide a Kbuild file to be able to build src/nvidia-modeset/ using
Linux's kbuild. It's meant to be included by
kernel-open/nvidia-modeset/.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The C++ code of nv-modeset-kernel.o causes a lot of comdat sections to
be generated which interferes badly with objtool trying to instrument /
reference these, especially when some of the comdat sections do get
dropped during linking of the final module.

Resolve this issue by collapsing the comdat sections early and squashing
the scattered sections with the help of a linker script.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Support building the dependent src/nvidia-modeset-kernel.o using Linux's
kbuild.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Add experimental support for using the Linux kernel's kbuild system to
not only compile code below kernel-open/ but src/ as well.

The build is still done in two phases, as in first building src/, then
kernel-open/ as otherwise the build would run into errors, trying to
link too many objects, hitting shell command argument limits.

Compiling the code below src/ via kbuild is needed to, e.g., support
more recent kernel features like IBT or to add required marker locations
via objtool for features like RETHUNK.

Using kbuild is disabled by default and needs to be explicitly opt-in
via `make USE_KBUILD=1`.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The RANDSTRUCT limitation isn't needed when all sources get compiled
with kbuild.

Guard it like that.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
@CLAassistant
Copy link

CLAassistant commented Mar 19, 2026

CLA assistant check
All committers have signed the CLA.

@minipli-oss
Copy link
Author

I just realized, I completely forget about mentioning how to actually build the modules with kbuild:

$ make modules -j $(nproc) USE_KBUILD=1
[...]
$ sudo make modules_install -j $(nproc) USE_KBUILD=1

The key is to mention USE_KBUILD=1 for both, building and installing the modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants