gentooLTO icon indicating copy to clipboard operation
gentooLTO copied to clipboard

Trim unused exported kernel symbols (CONFIG_TRIM_UNUSED_KSYMS)

Open ellisonpatterson opened this issue 6 years ago • 23 comments

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!

ellisonpatterson avatar Oct 11 '19 12:10 ellisonpatterson

the risk is that out-of-tree kernel modules, like wireguard and (formerly?) zfs won't be able to stop stripping of the symbols they need.

also any kernel modules you install as precompiled binaries are at risk of missing symbols, unless you have other modules that need the same symbols.

for most users I betthe main risk would be nvidia drivers. it would be interesting to see if they still work, and if not whether there are other drivers that could be built to preserve the right dependencies (nouveau?).

alternatively there may be a list used for stripping we could add needed symbols to.

On Fri, Oct 11, 2019, 05:43 Ellison Patterson [email protected] wrote:

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!

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/InBetweenNames/gentooLTO/issues/423?email_source=notifications&email_token=AAAHXYSO4W547YLURRLNRVLQOBYGVA5CNFSM4I7ZJIP2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HRGLILA, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAHXYQBYZ4UKPBNXVI7XQTQOBYGVANCNFSM4I7ZJIPQ .

wolfwood avatar Oct 11 '19 14:10 wolfwood

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

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

elsandosgrande avatar Nov 01 '19 20:11 elsandosgrande

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.

ellisonpatterson avatar Nov 07 '19 14:11 ellisonpatterson

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.

jiblime avatar Nov 08 '19 04:11 jiblime

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).

elsandosgrande avatar Nov 09 '19 13:11 elsandosgrande

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

jiblime avatar Nov 13 '19 07:11 jiblime

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

elsandosgrande avatar Nov 14 '19 01:11 elsandosgrande

@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!)

ellisonpatterson avatar Nov 14 '19 12:11 ellisonpatterson

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.

nivedita76 avatar Jan 05 '20 22:01 nivedita76

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. :wink:

pchome avatar Jan 07 '20 09:01 pchome

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.

pchome avatar Jan 24 '20 22:01 pchome

In what unit is the size?

elsandosgrande avatar Jan 25 '20 12:01 elsandosgrande

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 avatar Jan 29 '20 03:01 javashin

nope i still cannot compile the modules even with CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS disabled

javashin avatar Jan 29 '20 12:01 javashin

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

CaptainBloodz avatar Mar 30 '20 02:03 CaptainBloodz

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

CaptainBloodz avatar Apr 01 '20 13:04 CaptainBloodz

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

CaptainBloodz avatar Apr 09 '20 23:04 CaptainBloodz

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

CaptainBloodz avatar Apr 10 '20 23:04 CaptainBloodz

@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.

CaptainBloodz avatar Apr 22 '20 22:04 CaptainBloodz

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 avatar Dec 09 '21 10:12 Sherulez

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

CaptainBloodz avatar Jan 03 '22 05:01 CaptainBloodz