如何解决如何在禁用 SMP 支持的情况下运行“invd”指令?
我正在尝试从内核模块执行“invd”指令。我之前问过一个类似的问题 How to execute “invd” instruction? 并且从@Peter Cordes 的回答中,我知道系统启动后我无法在 SMP 系统上安全地运行此指令。那么,我不应该在没有 SMP 支持的情况下在启动后运行这条指令吗?因为没有其他核心在运行,所以内存不一致没有变化?我使用 -o0
标志编译了以下内核模块,
static int __init deviceDriver_init(void){
unsigned long flags;
int LEN=10;
int STEP=1;
int VALUE=1;
int arr[LEN];
int i;
unsigned long dummy;
printk(KERN_INFO "invd Driver loaded\n");
//wbinvd();
//asm volatile("cpuid\n":::);
local_irq_disable();
__asm__ __volatile__(
"wbinvd\n"
"loop:"
"movq %%rdx,(%%rbx);"
"leaq (%%rbx,%%rcx,8),%%rbx;"
"cmpq %%rbx,%%rax;"
"jg loop;"
"invd\n"
: "=b"(dummy) // output
: "b" (arr),"a" (arr+LEN),"c" (STEP),"d" (VALUE)
: "cc","memory"
);
local_irq_enable();
//asm volatile("invd\n":::);
printk(KERN_INFO "invd execute\n");
return 0;
}
在插入模块时我仍然收到以下错误,我在终端中得到 Segmentation fault (core dumped)
并且 dmesg 显示,
[ 2590.518614] invd Driver loaded
[ 2590.518840] general protection fault: 0000 [#5] SMP PTI
我用 nosmp
启动内核,但我不明白为什么 dmesg
仍然显示 SMP PTI
$cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-4.15.0-136-generic root=UUID=dbe747ff-a6a5-45cb-8553-c6db6d445d3d ro quiet splash nosmp vt.handoff=7
更新帖子:
正如我在评论部分提到的,在从 BIOS 禁用 SGX 后,我能够毫无错误地运行此 invd
。但是,当我尝试在具有相同内核版本的不同机器上运行相同的代码时,我仍然收到相同的错误消息。这很奇怪,我无法解释为什么会发生这种情况。在评论部分,@prl 提到错误可能来自 invd
后面的指令。我开始认为这也许是真的。因为 dmesg
中倒数第二行在 RED [ 153.527386] RIP: loop+0xc/0xf22 [noSmp8] RSP: ffffb8d9450a7be0
中突出显示。因此,错误似乎来自 loop
内部。我已经根据建议更新了 __init 函数代码。我不擅长汇编代码,谁能告诉我内联汇编代码是否正确?如果这个内联汇编代码不正确如何修复代码?我的整个 dmesg
跟踪是,
[ 153.514293] invd Driver loaded
[ 153.514547] general protection fault: 0000 [#1] SMP PTI
[ 153.514656] Modules linked in: noSmp8(OE+) xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack libcrc32c ipt_REJECT nf_reject_ipv4 xt_tcpudp bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables iptable_filter ip_tables x_tables ccm arc4 intel_rapl rt2800usb rt2x00usb x86_pkg_temp_thermal intel_powerclamp rt2800lib coretemp rt2x00lib mac80211 cfg80211 kvm_intel kvm irqbypass snd_hda_codec_realtek crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec_hdmi pcbc aesni_intel aes_x86_64 crypto_simd glue_helper cryptd intel_cstate intel_rapl_perf dell_smm_hwmon dell_wmi dell_smbios dcdbas intel_wmi_thunderbolt snd_hda_codec_generic dell_wmi_descriptor wmi_bmof snd_seq_midi snd_seq_midi_event
[ 153.515454] serio_raw snd_hda_intel snd_hda_codec snd_hda_core sparse_keymap snd_hwdep snd_rawmidi joydev input_leds snd_seq snd_pcm snd_seq_device snd_timer snd soundcore mei_me mei shpchp intel_pch_thermal mac_hid acpi_pad parport_pc ppdev lp parport autofs4 hid_generic usbhid hid nouveau mxm_wmi ttm drm_kms_helper psmouse syscopyarea sysfillrect sysimgblt igb e1000e dca i2c_algo_bit ptp pps_core ahci libahci fb_sys_fops drm wmi video
[ 153.516038] cpu: 0 PID: 4024 Comm: insmod Tainted: G OE 4.15.0-136-generic #140~16.04.1-Ubuntu
[ 153.516331] Hardware name: Dell Inc. BIOS 1.3.2 01/25/2016
[ 153.516626] RIP: 0010:loop+0xc/0xf22 [noSmp8]
[ 153.516917] RSP: 0018:ffffb8d9450a7be0 EFLAGS: 00010046
[ 153.517213] RAX: ffffb8d9450a7c08 RBX: ffffb8d9450a7c08 RCX: 0000000000000001
[ 153.517513] RDX: 0000000000000001 RSI: ffffb8d9450a7be0 RDI: ffff8edaadc16490
[ 153.517814] RBP: ffffb8d9450a7c60 R08: 0000000000012c40 R09: ffffffffb39624c4
[ 153.518119] R10: ffffb8d9450a7c78 R11: 000000000000038c R12: ffffb8d9450a7c10
[ 153.518427] R13: 0000000000000000 R14: 0000000000000001 R15: ffff8eda4c6bd660
[ 153.518730] FS: 00007fd7f09cf700(0000) GS:ffff8edaadc00000(0000) knlGS:0000000000000000
[ 153.519036] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 153.519346] CR2: 00005634f95fde50 CR3: 000000040dd2c001 CR4: 00000000003606f0
[ 153.519656] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 153.519980] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 153.520289] Call Trace:
[ 153.520597] ? 0xffffffffc050d000
[ 153.520899] do_one_initcall+0x55/0x1ac
[ 153.521201] ? do_one_initcall+0x55/0x1ac
[ 153.521504] ? do_init_module+0x27/0x223
[ 153.521808] ? _cond_resched+0x32/0x50
[ 153.522107] ? kmem_cache_alloc_trace+0x165/0x1c0
[ 153.522408] do_init_module+0x5f/0x223
[ 153.522710] load_module+0x188c/0x1ea0
[ 153.523016] ? ima_post_read_file+0x83/0xa0
[ 153.523320] SYSC_finit_module+0xe5/0x120
[ 153.523623] ? SYSC_finit_module+0xe5/0x120
[ 153.523927] SyS_finit_module+0xe/0x10
[ 153.524231] do_syscall_64+0x73/0x130
[ 153.524534] entry_SYSCALL_64_after_hwframe+0x41/0xa6
[ 153.524838] RIP: 0033:0x7fd7f04fd599
[ 153.525144] RSP: 002b:00007ffda61c2968 EFLAGS: 00000202 ORIG_RAX: 0000000000000139
[ 153.525455] RAX: ffffffffffffffda RBX: 00005643631d7210 RCX: 00007fd7f04fd599
[ 153.525768] RDX: 0000000000000000 RSI: 0000564361c3226b RDI: 0000000000000003
[ 153.526084] RBP: 0000564361c3226b R08: 0000000000000000 R09: 00007fd7f07c2ea0
[ 153.526403] R10: 0000000000000003 R11: 0000000000000202 R12: 0000000000000000
[ 153.526722] R13: 00005643631d7ca0 R14: 0000000000000000 R15: 0000000000000000
[ 153.527040] Code: 00 48 8b 75 c8 48 8b 45 c8 8b 55 b8 48 63 d2 48 c1 e2 02 48 01 d0 8b 4d b4 8b 55 bc 48 89 f3 48 89 13 48 8d 1c cb 48 39 d8 7f f4 <0f> 08 48 89 d8 48 89 45 d0 e8 40 ef 73 00 48 c7 c7 c7 d0 c4 c0
[ 153.527386] RIP: loop+0xc/0xf22 [noSmp8] RSP: ffffb8d9450a7be0
[ 153.530228] ---[ end trace cc9ea64985c9fe34 ]---
那么,即使没有 SMP 也无法运行 invd
?
解决方法
这里有两个问题:
a) 如何执行 INVD(不安全)
为此,您需要在 CPL=0 下运行,并且您必须确保 CPU 没有使用任何“处理器保留内存保护”,这是英特尔软件保护扩展(允许程序运行的扩展)的一部分具有操作系统无法篡改的屏蔽/私有/加密空间,通常用于数字权限管理方案,但也可能用于增强其他事物的安全性/机密性)。
请注意,最新版本的 Linux 支持 SGX,但我不确定何时引入支持或您的内核有多旧,或者是否启用/禁用。
如果其中任何一个不正确(例如,您处于 CPL=3 或存在“处理器保留内存保护”),您将收到一般保护错误异常。
b) 如何安全地执行 INVD
为此,您必须确保缓存(包括“外部缓存”——例如可能包括 eDRAM 和内置于非易失性 RAM 中的缓存之类的东西)不包含任何会在丢失时导致问题的修改数据.这包括来自以下方面的数据:
-
IRQ。这些可以被禁用。
-
NMI 和机器检查异常。对于正在运行的操作系统,几乎不可能停止/禁用这些,如果您可以禁用它们,那么就像交叉手指而忽略严重的硬件故障(一个非常糟糕的主意)。
-
固件的系统管理模式。这是一种特殊的 CPU 模式,固件用于各种不受操作系统/内核控制的事情(例如 ECC 清理、某些电源管理、旧设备的仿真)。它不能被禁用。
-
写入由 CPU 本身完成。这包括更新页表中的访问/脏标志(无法禁用),以及将数据存储在内存中的任何性能监控或调试功能(可以“未启用”)。
由于这些限制(并且不要忘记性能问题),只有两种情况下 INVD 可能是正常的 - 需要确定 RAM 芯片大小和配置内存控制器的早期固件代码(它很可能有用/正常) ,以及计算机关闭前的瞬间(这可能毫无意义)。
猜测
我猜测(基于我无法想到任何其他合理的原因)您想要构建临时屏蔽/私有内存区域(以增强安全性 - 例如,这样您放入该区域的数据不会/ 不能泄漏到 RAM 中)。在这种情况下(具有讽刺意味的是),专为此工作 (SGX) 设计的工具可能会阻止您做得不好。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。