Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trim unused exported kernel symbols (CONFIG_TRIM_UNUSED_KSYMS) #423

Open
ellisonpatterson opened this issue Oct 11, 2019 · 23 comments
Open

Comments

@ellisonpatterson
Copy link

ellisonpatterson commented Oct 11, 2019

I'm tweaking my kernel config, when I ran across this option CONFIG_TRIM_UNUSED_KSYMS.

The title is Trim unused exported kernel symbols with a snippit of the description being:

This option allows for unused exported symbols to be dropped from the build.
In turn, this provides the compiler more opportunities (especially when using LTO) for optimizing the code and reducing binary size.
This might have some security advantages as well.

Anyone have any knowledge about the implications of this option?

Thanks!

@wolfwood
Copy link
Contributor

wolfwood commented Oct 11, 2019 via email

@elsandosgrande
Copy link
Contributor

That was sudden closure. Why close it all of a sudden @ellisonpatterson?

Also, I wonder if the option would affect VirtualBox's modules...

@ellisonpatterson
Copy link
Author

That was sudden closure. Why close it all of a sudden @ellisonpatterson?

Also, I wonder if the option would affect VirtualBox's modules...

It seems to affect various modules (ZFS for my build) and I'm not sure if it's worth pursuing since the feature itself could lead to issues.

@jiblime
Copy link
Contributor

jiblime commented Nov 8, 2019

CONFIG_TRIM_UNUSED_KSYMS will break all external modules.

If unsure, or if you need to build out-of-tree modules, say N.

You can patch in the module like this for example. The reason ZFS isn't an in-kernel option is due to GPL licensing. For something as small as ZFS it should be simple, I'm not sure not sure how difficult it would be for NVIDIA. Ofc you shouldn't redistribute it if you do decide to do it for yourself.

@elsandosgrande
Copy link
Contributor

elsandosgrande commented Nov 9, 2019

Hmm... I wonder if VirtualBox modules are affected. Those are the only modules I have, period. Yeah, I build everything in (instead of "M", I select "Y" in menuconfig).

Edit

I just realized that I already said that (regarding VB modules).

@jiblime
Copy link
Contributor

jiblime commented Nov 13, 2019

The mainline kernel (5.4-rc7) currently has CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS

If MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is enabled (default=n), the
requirement for modules to import all namespaces that are used by
the module is relaxed.

Enabling this option effectively allows (invalid) modules to be loaded
while only a warning is emitted.

Disabling this option keeps the enforcement at module loading time and
loading is denied if the module's imports are not satisfactory.

It seems as if this option would you allow you to load external modules that are invalid due to their signatures/required symbols being stripped.

Edit: didn't work..for now

@elsandosgrande
Copy link
Contributor

@ellisonpatterson Given that the discussion has sparked yet again, maybe you consider reopening the ticket?

@ellisonpatterson
Copy link
Author

ellisonpatterson commented Nov 14, 2019

@ellisonpatterson Given that the discussion has sparked yet again, maybe you consider reopening the ticket?

Sorry about that, I have reopened it for further discussion (thank you!)

@nivedita76
Copy link

The mainline kernel (5.4-rc7) currently has CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS

If MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is enabled (default=n), the
requirement for modules to import all namespaces that are used by
the module is relaxed.

Enabling this option effectively allows (invalid) modules to be loaded
while only a warning is emitted.

Disabling this option keeps the enforcement at module loading time and
loading is denied if the module's imports are not satisfactory.

It seems as if this option would you allow you to load external modules that are invalid due to their signatures/required symbols being stripped.

Edit: didn't work..for now

That's an unrelated option. The kernel is cleaning up the module source interface and this option will break ones that haven't been updated. It won't help with external modules that depend on some symbol that got dropped from the kernel though.

Note that the LTO advantage isn't relevant unless you've got a patched kernel that you're compiling with LTO turned on.

@pchome
Copy link
Contributor

pchome commented Jan 7, 2020

I'm staring at initial changes for CONFIG_TRIM_UNUSED_KSYMS support, and from what I understand we just need to add required symbols into include/generated/autoksyms.h, which adjusting by the scripts/adjust_autoksyms.sh script during build. So I collected main work into separate script for external modules, and patched autoksyms.h generation logic a bit.

support-trim-unused-ksyms-for-external-modules.patch

--- a/scripts/adjust_autoksyms.sh
+++ b/scripts/adjust_autoksyms.sh
@@ -19,6 +19,7 @@

 cur_ksyms_file="include/generated/autoksyms.h"
 new_ksyms_file="include/generated/autoksyms.h.tmpnew"
+ext_ksyms_file="include/generated/autoksyms.h.extern"

 info() {
        if [ "$quiet" != "silent_" ]; then
@@ -49,7 +50,11 @@
 sed 's/ko$/mod/' modules.order |
 xargs -n1 sed -n -e '2{s/ /\n/g;/^$/!p;}' -- |
 sort -u |
-sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$new_ksyms_file"
+sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$new_ksyms_file".tmp
+
+# Merge external and new ksym files
+sort -u "$new_ksyms_file".tmp "$ext_ksyms_file" >> "$new_ksyms_file"
+rm -f "$new_ksyms_file".tmp

 # Special case for modversions (see modpost.c)
 if [ -n "$CONFIG_MODVERSIONS" ]; then
@@ -82,7 +87,8 @@
        # Replace the old list with tne new one
        old=$(grep -c "^#define __KSYM_" "$cur_ksyms_file" || true)
        new=$(grep -c "^#define __KSYM_" "$new_ksyms_file" || true)
-       info "KSYMS" "symbols: before=$old, after=$new, changed=$changed"
+       ext=$(grep -c "^#define __KSYM_" "$ext_ksyms_file" || true)
+       info "KSYMS" "symbols: before=$old, after=$new, external=$ext, changed=$changed"
        info "UPD" "$cur_ksyms_file"
        mv -f "$new_ksyms_file" "$cur_ksyms_file"
        # Then trigger a rebuild of affected source files
extern-ksym.sh
#!/bin/sh

#CUR_KERNEL_VER=5.4.8-gentoo
CUR_KERNEL_VER=$(uname -r)

. /usr/src/linux-${CUR_KERNEL_VER}/include/config/auto.conf

list_required_ksyms() {
    nm $1 |
        sed -n 's/^ \+U //p' |
        sed -ns -e '{s/ /\n/g;/^$/!p;}' |
        sort -u |
        while read sym; do
            if [ -n "$CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX" ]; then
                sym="${sym#_}"
            fi
            echo "#define __KSYM_${sym} 1"
        done
}


# Find all external modules
mod_dir_list=$(find /lib/modules/${CUR_KERNEL_VER} -mindepth 1 -maxdepth 1 -type d  \! -name 'kernel' | xargs)

for mod_dir in $mod_dir_list; do
    for ko in ${mod_dir}/*.ko; do
        list_required_ksyms ${ko}
    done
done | sort -u

Here should be a clean-up, because some symbols are defined in neighbour *.ko modules, but no big deal for now. This will propose kernel to include unknown symbols, like KSYM_nvUvmInterfaceRetainChannelResources, which I guess it don't care about.

Test

cd /usr/src/linux
sh /path/to/extern-ksym.sh > include/generated/autoksyms.h.extern
patch -p1 < /path/to/support-trim-unused-ksyms-for-external-modules.patch
make nconfig # enable CONFIG_TRIM_UNUSED_KSYMS
make
# check output:
#  CHK     include/generated/autoksyms.h
#  KSYMS   symbols: before=0, after=2965, external=563, changed=2965
#  UPD     include/generated/autoksyms.h

Result

file 5.4.8-gentoo 5.4.8-gentoo.old
System.map 2344152 2932044
vmlinuz 7062064 7164464

Note

  • External modules should be built/updated BEFORE kernel update, this mean if you going to update both module and kernel, then you should
    1. update module for current kernel
    2. generate autoksyms.h.extern file
    3. switch to new kernel, build it and rebuild external modules again
  • I guess autoksyms.h.extern should be regenerated by every external module update, and put in an known place.
  • There is a guard currently for external kernel modules, which says "CONFIG_TRIM_UNUSED_KSYMS: should not be set. But it is."
    https://bugs.gentoo.org/591832
    linux-mod.eclass:584

Status

  • I'm currently looking for solution to easily override the guard w/o modification of eclass and ebuilds
  • Then I'm going to rebuild all external modules and pray reboot.
  • UPD: Hello from CONFIG_TRIM_UNUSED_KSYMS + (NVIDIA + Virtualbox + etc.) modules installed. 😉

@pchome
Copy link
Contributor

pchome commented Jan 24, 2020

So, it's hard to fully automate process, but I already built several kernel versions with this, and in general I just copy generated autoksyms.h.extern list into installed kernel's include/generated/ directory, before build.

Some stats:

Size Version Notes
6959664 vmlinuz-5.3.10-gentoo
6963760 vmlinuz-5.3.11-gentoo
6992432 vmlinuz-5.4.0-gentoo
6984240 vmlinuz-5.4.1-gentoo
6984240 vmlinuz-5.4.2-gentoo
6988336 vmlinuz-5.4.3-gentoo
6988336 vmlinuz-5.4.5-gentoo
6988336 vmlinuz-5.4.6-gentoo
7160368 vmlinuz-5.4.7-gentoo BPF forced by in-kernel Gentoo systemd option (likely)
7164464 vmlinuz-5.4.8-gentoo.old Normal build
7062064 vmlinuz-5.4.8-gentoo.old Trimmed ksyms
5898800 vmlinuz-5.4.8-gentoo Minor modules cleanup (unused VBox, etc.)
5624368 vmlinuz-5.4.10-gentoo More cleanups (unused BPF, Perf, Debugfs,etc. are dropped)
5624368 vmlinuz-5.4.11-gentoo
5624368 vmlinuz-5.4.12-gentoo
5628464 vmlinuz-5.4.13-gentoo
5628464 vmlinuz-5.4.14-gentoo

Probably placebo effect: very fast content (re)draw in Firefox.

@elsandosgrande
Copy link
Contributor

In what unit is the size?

@javashin
Copy link

hi i compiled the new kernel 5.5 today and i was not able to compile VirtualBox Modules and get here and i dont know why ????

is this

zcat /proc/config.gz | grep CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y

enabled by default ..... im recompiling now Thanks for the info.

@javashin
Copy link

nope i still cannot compile the modules even with CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS disabled

@CaptainBloodz
Copy link

CaptainBloodz commented Mar 30, 2020

Thks,
Little gentoo forum post on the subject:
https://forums.gentoo.org/viewtopic-p-8437576.html#8437576
Thks 4 ur attention.

@CaptainBloodz
Copy link

Calling script updated, cf above link.
Thks 4 ur attention.

@CaptainBloodz
Copy link

Calling script updated, cf above link.
Hopefully near beta.
Thks 4 ur attention.

@CaptainBloodz
Copy link

Single script version, cf above link.
Thks 4 ur attention.

@CaptainBloodz
Copy link

@pchome

. /usr/src/linux-${CUR_KERNEL_VER}/include/config/auto.conf
Sorry to disturb for a likely to be noob question:
I'm wondering about the purpose of the above command.
All I found it about it is that the file get displayed if set +x in bash script.

Is there any reason I'm missing?

Big up for your work, by the way ;)
Thks 4 ur attention, interest & support.

@Sherulez
Copy link

Sherulez commented Dec 9, 2021

CONFIG_UNUSED_KSYMS_WHITELIST Can also be a great alternative.
For example I use it to inform the kernel to keep the symbols used by the nvidia-dkms modules.

@CaptainBloodz
Copy link

Indeed CONFIG_UNUSED_KSYMS_WHITELIST allows single pass kernel build once WHITELIST has been elaborated

@makierika
Copy link

CONFIG_UNUSED_KSYMS_WHITELIST Can also be a great alternative. For example I use it to inform the kernel to keep the symbols used by the nvidia-dkms modules.

@Sherulez What symbols does nvidia-dkms use?

@pchome
Copy link
Contributor

pchome commented Mar 3, 2025

@makierika
Every release can add or remove symbols, so you should have a way to figure out which ones (w/o constantly rebuilding unless errors end).

For example (I don't do this now, so not sure):

  1. dkms
  2. objdumb/etc. to get the list
  3. rebuild w/ CONFIG_UNUSED_KSYMS_WHITELIST
  4. on new release goto 1.

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

No branches or pull requests

10 participants