kernel/x86: Use multibyte NOP constants in altcodepatch.

Follows up on a suggestion from the commits mailing list.
This commit is contained in:
Augustin Cavalier
2026-05-04 15:27:11 -04:00
parent b6878c0f30
commit e7cc89a038
2 changed files with 29 additions and 15 deletions
@@ -9,15 +9,15 @@
#include <arch/x86/arch_kernel.h> #include <arch/x86/arch_kernel.h>
#define ASM_NOP1 .byte 0x90 #define X86_NOP1 0x90
#define ASM_NOP2 .byte 0x66, 0x90 #define X86_NOP2 0x66, 0x90
#define ASM_NOP3 .byte 0x0f, 0x1f, 0x00 #define X86_NOP3 0x0f, 0x1f, 0x00
#define ASM_NOP4 .byte 0x0f, 0x1f, 0x40, 0x00 #define X86_NOP4 0x0f, 0x1f, 0x40, 0x00
#define ASM_NOP5 .byte 0x0f, 0x1f, 0x44, 0x00, 0x00 #define X86_NOP5 0x0f, 0x1f, 0x44, 0x00, 0x00
#define ASM_NOP6 .byte 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 #define X86_NOP6 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00
#define ASM_NOP7 .byte 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 #define X86_NOP7 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00
#define ASM_NOP8 .byte 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 #define X86_NOP8 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
#define ASM_NOP9 .byte 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 #define X86_NOP9 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
#define ALTCODEPATCH_TAG_STAC 1 #define ALTCODEPATCH_TAG_STAC 1
@@ -38,11 +38,11 @@
.popsection .popsection
#define ASM_STAC CODEPATCH_START \ #define ASM_STAC CODEPATCH_START \
ASM_NOP3 ; \ .byte X86_NOP3 ; \
CODEPATCH_END(ALTCODEPATCH_TAG_STAC) CODEPATCH_END(ALTCODEPATCH_TAG_STAC)
#define ASM_CLAC CODEPATCH_START \ #define ASM_CLAC CODEPATCH_START \
ASM_NOP3 ; \ .byte X86_NOP3 ; \
CODEPATCH_END(ALTCODEPATCH_TAG_CLAC) CODEPATCH_END(ALTCODEPATCH_TAG_CLAC)
#else #else
@@ -59,11 +59,11 @@
".popsection" ".popsection"
#define ASM_STAC CODEPATCH_START \ #define ASM_STAC CODEPATCH_START \
STRINGIFY(ASM_NOP3) "\n" \ STRINGIFY(.byte X86_NOP3) "\n" \
CODEPATCH_END(ALTCODEPATCH_TAG_STAC) CODEPATCH_END(ALTCODEPATCH_TAG_STAC)
#define ASM_CLAC CODEPATCH_START \ #define ASM_CLAC CODEPATCH_START \
STRINGIFY(ASM_NOP3) "\n"\ STRINGIFY(.byte X86_NOP3) "\n"\
CODEPATCH_END(ALTCODEPATCH_TAG_CLAC) CODEPATCH_END(ALTCODEPATCH_TAG_CLAC)
@@ -38,16 +38,30 @@ arch_altcodepatch_replace(uint16 tag, void* newcodepatch, size_t length)
const uint32 kernelProtection = B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA; const uint32 kernelProtection = B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA;
set_area_protection(info->text_region.id, kernelProtection | B_KERNEL_WRITE_AREA); set_area_protection(info->text_region.id, kernelProtection | B_KERNEL_WRITE_AREA);
const uint8 kNOPs[9][9] = {
{X86_NOP1}, {X86_NOP2}, {X86_NOP3}, {X86_NOP4}, {X86_NOP5}, {X86_NOP6},
{X86_NOP7}, {X86_NOP8}, {X86_NOP9}
};
for (altcodepatch* patch = &altcodepatch_begin; patch < &altcodepatch_end; for (altcodepatch* patch = &altcodepatch_begin; patch < &altcodepatch_end;
patch++) { patch++) {
if (patch->tag != tag) if (patch->tag != tag)
continue; continue;
void* address = (void*)(KERNEL_LOAD_BASE + patch->kernel_offset); uint8* address = (uint8*)(KERNEL_LOAD_BASE + patch->kernel_offset);
if (patch->length < length) if (patch->length < length)
panic("can't copy patch: new code is too long\n"); panic("can't copy patch: new code is too long\n");
memcpy(address, newcodepatch, length); memcpy(address, newcodepatch, length);
memset((uint8*)address + length, 0x90 /* nop */, patch->length - length); address += length;
size_t remainder = patch->length - length;
while (remainder > 0) {
size_t toWrite = min_c(remainder, 9);
memcpy(address, kNOPs[toWrite - 1], toWrite);
address += toWrite;
remainder -= toWrite;
}
count++; count++;
} }