Linux 编译内核模块出现--Unknown symbol mcount

文章讲述了在SUSELinuxEnterpriseServer12SP2上使用低版本docker编译内核模块时遇到的SpectreV2漏洞问题,涉及如何通过启用Retpoline缓解漏洞以及检查内核配置和gcc版本的重要性。
摘要由CSDN通过智能技术生成

文章目录

Linux suse:

# cat /etc/os-release
NAME="SLES"
VERSION="12-SP2"
VERSION_ID="12.2"
PRETTY_NAME="SUSE Linux Enterprise Server 12 SP2"
ID="sles"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:suse:sles:12:sp2"

# uname -r
4.4.120-92.70-default

在编译SUSE Linux Enterprise Server 12 SP时,使用低版本的docker镜像编译内核模块时,加载内核模块时出现:

# dmesg
[12996.210792] Spectre V2 : System may be vulnerable to spectre v2
[12996.210892] test: loading module not compiled with retpoline compiler.
[13299.232906] test: Unknown symbol mcount (err 0)

加载内核模块时:
(1)

# dmesg
[12996.210792] Spectre V2 : System may be vulnerable to spectre v2
[12996.210892] test: loading module not compiled with retpoline compiler.

指示系统可能受到 Spectre V2 漏洞的影响,并且正在加载的模块没有使用 retpoline 编译器进行编译。

Spectre V2(CVE-2017-5715)是 Spectre 漏洞家族中的一个变种,它是一种基于推测执行的侧信道攻击。Spectre V2 漏洞影响现代处理器,可能允许攻击者访问其他进程内存中的敏感信息。

Spectre V2 漏洞利用了分支预测的缺陷,这是一种现代处理器使用的性能优化技术。通过操纵分支的推测执行,攻击者可以欺骗处理器泄露应该是不可访问的敏感信息。

为了解决 Spectre V2 漏洞,需要在硬件和软件层面上采取综合的缓解措施。硬件厂商发布了包含处理器固件更新的微码更新,以在硬件层面上缓解漏洞。此外,操作系统厂商提供了软件补丁和更新,包括支持 Retpoline 的编译器和更新的内核,以在软件层面上缓解漏洞。

Retpoline(Return Trampoline)是一种软件缓解技术,用于应对 Spectre V2 漏洞。它是一种编译器技术,修改代码中的间接分支指令,防止推测执行访问未经授权的内存位置。Retpoline 可以在不需要昂贵的硬件修改的情况下缓解 Spectre V2 漏洞。

检查内核配置:检查您的内核配置,确保已启用retpoline支持。可以通过查看内核配置文件/proc/config.gz是否启用了retpoline选项:

# zgrep CONFIG_RETPOLINE /proc/config.gz
CONFIG_RETPOLINE=y

如果输出显示 CONFIG_RETPOLINE=y,则表示retpoline已启用。

这只是警告而已,不影响模块的加载运行。

(2)

# dmesg
[13299.232906] test: Unknown symbol mcount (err 0)

gcc 的 -pg 选项,它插入 mcount() 调用以与 gprof 一起使用。

当在Linux系统中加载内核模块时遇到 “Unknown symbol mcount (err 0)” 的错误消息时,这通常表示所加载的内核模块依赖于 mcount 符号,但该符号在当前系统内核中不可用或未定义。

mcount 是一个用于性能分析和跟踪的内核符号,通常由 gcc 编译器生成的代码调用。它用于计算函数调用的计数,以便进行性能分析和跟踪操作。

从 gcc 4.6 版开始,这个 mcount() 调用现在是 fentry()。

使用的 docker 容器 gcc 版本过低,低于 gcc 4.6,因此编译内核模块时出现了mcount符号,该符号在当前系统内核中是未定义。

# nm test.ko | grep mcount
                 U mcount
# cat /proc/kallsyms | grep mcount
ffffffff81eecb60 T __start_mcount_loc
ffffffff81f1dd78 T __stop_mcount_loc

可以看到当前内核版本没有 mcount 符号。

__start_mcount_loc 和 __stop_mcount_loc 这两个符号实际上是用于标记函数fentry()插装跟踪信息的起始和结束位置,这些符号是由编译器自动插入的。当使用 -pg 选项编译程序时,编译器会在每个函数的入口和出口处插入这些符号,以便在程序运行时收集函数调用和执行时间的数据。

__start_mcount_loc 标记了函数调用跟踪信息的起始位置,而 __stop_mcount_loc 则标记了其结束位置。这两个符号之间的范围表示了fentry() 插装数据的范围。

使用较高版本的docker(gcc)即可,比如 gcc 4.8:

# nm test.ko| grep __fentry__
                 U __fentry__
# cat /proc/kallsyms | grep __fentry__
ffffffff815f89d0 T __fentry__

内核当前镜像中有该内核符号__fentry__。

(3)内核顶层 makefile

vim /usr/src/linux-4.4.120-92.70/Makefile
KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
                   -Werror-implicit-function-declaration \
                   -Wno-format-security \
                   -std=gnu89 $(call cc-option,-fno-PIE)
ifdef CONFIG_FUNCTION_TRACER
ifndef CC_FLAGS_FTRACE
CC_FLAGS_FTRACE := -pg
endif
export CC_FLAGS_FTRACE
ifdef CONFIG_HAVE_FENTRY
CC_USING_FENTRY := $(call cc-option, -mfentry -DCC_USING_FENTRY)
endif
KBUILD_CFLAGS   += $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY)
KBUILD_AFLAGS   += $(CC_USING_FENTRY)
ifdef CONFIG_DYNAMIC_FTRACE
        ifdef CONFIG_HAVE_C_RECORDMCOUNT
                BUILD_C_RECORDMCOUNT := y
                export BUILD_C_RECORDMCOUNT
        endif
endif
endif
# zgrep CONFIG_FUNCTION_TRACER /proc/config.gz
CONFIG_FUNCTION_TRACER=y

# zgrep CONFIG_HAVE_FENTRY /proc/config.gz
CONFIG_HAVE_FENTRY=y

# zgrep CONFIG_DYNAMIC_FTRACE /proc/config.gz
CONFIG_DYNAMIC_FTRACE=y
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值