Fix VTOY_LINUX_REMOUNT option does not work with latest linux kernel version. (#2661 #2674)

This commit is contained in:
longpanda 2024-01-24 12:09:29 +08:00
parent 4527e1db79
commit c7693d4ecd
10 changed files with 247 additions and 36 deletions

View File

@ -53,6 +53,9 @@ typedef struct ko_param
unsigned long sym_put_size;
unsigned long kv_major;
unsigned long ibt;
unsigned long kv_minor;
unsigned long blkdev_get_addr;
unsigned long blkdev_put_addr;
unsigned long padding[1];
}ko_param;
@ -150,10 +153,11 @@ static volatile ko_param g_ko_param =
#define vdebug(fmt, args...) if(kprintf) kprintf(KERN_ERR fmt, ##args)
static unsigned int g_claim_ptr = 0;
static unsigned char *g_get_patch[MAX_PATCH] = { NULL };
static unsigned char *g_put_patch[MAX_PATCH] = { NULL };
static void notrace dmpatch_restore_code(unsigned char *opCode)
static void notrace dmpatch_restore_code(int bytes, unsigned char *opCode, unsigned int code)
{
unsigned long align;
@ -161,7 +165,14 @@ static void notrace dmpatch_restore_code(unsigned char *opCode)
{
align = (unsigned long)opCode / g_ko_param.pgsize * g_ko_param.pgsize;
set_mem_rw(align, 1);
*opCode = 0x80;
if (bytes == 1)
{
*opCode = (unsigned char)code;
}
else
{
*(unsigned int *)opCode = code;
}
set_mem_ro(align, 1);
}
}
@ -235,6 +246,121 @@ static int notrace dmpatch_replace_code
return 0;
}
static unsigned long dmpatch_find_call_offset(unsigned long addr, unsigned long size, unsigned long func)
{
unsigned long i = 0;
unsigned long dest;
unsigned char *opCode = NULL;
unsigned char aucOffset[8] = { 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF };
opCode = (unsigned char *)addr;
for (i = 0; i + 4 < size; i++)
{
if (opCode[i] == 0xE8)
{
aucOffset[0] = opCode[i + 1];
aucOffset[1] = opCode[i + 2];
aucOffset[2] = opCode[i + 3];
aucOffset[3] = opCode[i + 4];
dest = addr + i + 5 + *(unsigned long *)aucOffset;
if (dest == func)
{
return i;
}
}
}
return 0;
}
static unsigned int dmpatch_patch_claim_ptr(void)
{
unsigned long i = 0;
unsigned long t = 0;
unsigned long offset1;
unsigned long offset2;
unsigned long align;
unsigned char *opCode = NULL;
vdebug("Get addr: 0x%lx %lu 0x%lx\n", g_ko_param.sym_get_addr, g_ko_param.sym_get_size, g_ko_param.blkdev_get_addr);
vdebug("Put addr: 0x%lx %lu 0x%lx\n", g_ko_param.sym_put_addr, g_ko_param.sym_put_size, g_ko_param.blkdev_put_addr);
opCode = (unsigned char *)g_ko_param.sym_get_addr;
for (i = 0; i < 4; i++)
{
vdebug("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
opCode[i + 0], opCode[i + 1], opCode[i + 2], opCode[i + 3],
opCode[i + 4], opCode[i + 5], opCode[i + 6], opCode[i + 7],
opCode[i + 8], opCode[i + 9], opCode[i + 10], opCode[i + 11],
opCode[i + 12], opCode[i + 13], opCode[i + 14], opCode[i + 15]);
}
offset1 = dmpatch_find_call_offset(g_ko_param.sym_get_addr, g_ko_param.sym_get_size, g_ko_param.blkdev_get_addr);
offset2 = dmpatch_find_call_offset(g_ko_param.sym_put_addr, g_ko_param.sym_put_size, g_ko_param.blkdev_put_addr);
if (offset1 == 0 || offset2 == 0)
{
vdebug("call blkdev_get or blkdev_put Not found, %lu %lu\n", offset1, offset2);
return 1;
}
vdebug("call addr1:0x%lx call addr2:0x%lx\n",
g_ko_param.sym_get_addr + offset1,
g_ko_param.sym_put_addr + offset2);
opCode = (unsigned char *)g_ko_param.sym_get_addr;
for (i = offset1 - 1, t = 0; (i > 0) && (t < 24); i--, t++)
{
/* rdx */
if (opCode[i] == 0x48 && opCode[i + 1] == 0xc7 && opCode[i + 2] == 0xc2)
{
g_claim_ptr = *(unsigned int *)(opCode + i + 3);
g_get_patch[0] = opCode + i + 3;
vdebug("claim_ptr(%08X) found at get addr 0x%lx\n", g_claim_ptr, g_ko_param.sym_get_addr + i + 3);
break;
}
}
if (g_claim_ptr == 0)
{
vdebug("Claim_ptr not found in get\n");
return 1;
}
opCode = (unsigned char *)g_ko_param.sym_put_addr;
for (i = offset2 - 1, t = 0; (i > 0) && (t < 24); i--, t++)
{
/* rsi */
if (opCode[i] == 0x48 && opCode[i + 1] == 0xc7 && opCode[i + 2] == 0xc6)
{
if (*(unsigned int *)(opCode + i + 3) == g_claim_ptr)
{
vdebug("claim_ptr found at put addr 0x%lx\n", g_ko_param.sym_put_addr + i + 3);
g_put_patch[0] = opCode + i + 3;
break;
}
}
}
if (g_put_patch[0] == 0)
{
vdebug("Claim_ptr not found in put\n");
return 1;
}
align = (unsigned long)g_get_patch[0] / g_ko_param.pgsize * g_ko_param.pgsize;
set_mem_rw(align, 1);
*(unsigned int *)(g_get_patch[0]) = 0;
set_mem_ro(align, 1);
align = (unsigned long)g_put_patch[0] / g_ko_param.pgsize * g_ko_param.pgsize;
set_mem_rw(align, 1);
*(unsigned int *)(g_put_patch[0]) = 0;
set_mem_ro(align, 1);
return 0;
}
#ifdef VTOY_IBT
static __always_inline unsigned long long dmpatch_rdmsr(unsigned int msr)
{
@ -297,7 +423,8 @@ static int notrace dmpatch_init(void)
kprintf = (printk_pf)(g_ko_param.printk_addr);
vdebug("dmpatch_init start pagesize=%lu ...\n", g_ko_param.pgsize);
vdebug("dmpatch_init start pagesize=%lu kernel=%lu.%lu ...\n",
g_ko_param.pgsize, g_ko_param.kv_major, g_ko_param.kv_minor);
if (g_ko_param.struct_size != sizeof(ko_param))
{
@ -316,20 +443,27 @@ static int notrace dmpatch_init(void)
reg_kprobe = (kprobe_reg_pf)g_ko_param.reg_kprobe_addr;
unreg_kprobe = (kprobe_unreg_pf)g_ko_param.unreg_kprobe_addr;
r = dmpatch_replace_code(1, g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 2, "dm_get_table_device", g_get_patch);
if (r && g_ko_param.kv_major >= 5)
if (g_ko_param.kv_major > 6 || (g_ko_param.kv_major == 6 && g_ko_param.kv_minor >= 5))
{
vdebug("new2 patch dm_get_table_device...\n");
r = dmpatch_replace_code(2, g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 1, "dm_get_table_device", g_get_patch);
vdebug("new interface patch dm_get_table_device...\n");
r = dmpatch_patch_claim_ptr();
}
else
{
r = dmpatch_replace_code(1, g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 2, "dm_get_table_device", g_get_patch);
if (r && g_ko_param.kv_major >= 5)
{
vdebug("new2 patch dm_get_table_device...\n");
r = dmpatch_replace_code(2, g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 1, "dm_get_table_device", g_get_patch);
}
if (r && g_ko_param.kv_major >= 5)
{
vdebug("new3 patch dm_get_table_device...\n");
r = dmpatch_replace_code(3, g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 1, "dm_get_table_device", g_get_patch);
}
}
if (r && g_ko_param.kv_major >= 5)
{
vdebug("new3 patch dm_get_table_device...\n");
r = dmpatch_replace_code(3, g_ko_param.sym_get_addr, g_ko_param.sym_get_size, 1, "dm_get_table_device", g_get_patch);
}
if (r)
{
rc = -EINVAL;
@ -337,7 +471,14 @@ static int notrace dmpatch_init(void)
}
vdebug("patch dm_get_table_device success\n");
r = dmpatch_replace_code(1, g_ko_param.sym_put_addr, g_ko_param.sym_put_size, 1, "dm_put_table_device", g_put_patch);
if (g_ko_param.kv_major >= 6 && g_ko_param.kv_minor >= 5)
{
r = 0;
}
else
{
r = dmpatch_replace_code(1, g_ko_param.sym_put_addr, g_ko_param.sym_put_size, 1, "dm_put_table_device", g_put_patch);
}
if (r)
{
rc = -EINVAL;
@ -369,10 +510,18 @@ static void notrace dmpatch_exit(void)
msr = dmpatch_ibt_save();
}
for (i = 0; i < MAX_PATCH; i++)
if (g_claim_ptr)
{
dmpatch_restore_code(g_get_patch[i]);
dmpatch_restore_code(g_put_patch[i]);
dmpatch_restore_code(4, g_get_patch[0], g_claim_ptr);
dmpatch_restore_code(4, g_put_patch[0], g_claim_ptr);
}
else
{
for (i = 0; i < MAX_PATCH; i++)
{
dmpatch_restore_code(1, g_get_patch[i], 0x80);
dmpatch_restore_code(1, g_put_patch[i], 0x80);
}
}
vdebug("dmpatch_exit success\n");

View File

@ -344,6 +344,15 @@ ventoy_dm_patch() {
get_addr=$(echo $vtLine | $AWK '{print $1}')
get_size=$(echo $vtLine | $AWK '{print $2}')
vtLine=$($VTOY_PATH/tool/vtoyksym blkdev_get_by_dev $VTOY_PATH/kallsyms)
vtlog "get blkdev_get_by_dev address $vtLine"
blkdev_get_addr=$(echo $vtLine | $AWK '{print $1}')
vtLine=$($VTOY_PATH/tool/vtoyksym blkdev_put $VTOY_PATH/kallsyms)
vtlog "get blkdev_put address $vtLine"
blkdev_put_addr=$(echo $vtLine | $AWK '{print $1}')
if $GREP -m1 -q 'close_table_device.isra' $VTOY_PATH/kallsyms; then
vtLine=$($VTOY_PATH/tool/vtoyksym close_table_device.isra $VTOY_PATH/kallsyms)
vtlog "get close_table_device.isra address $vtLine"
@ -383,6 +392,7 @@ ventoy_dm_patch() {
vtlog get_addr=$get_addr get_size=$get_size
vtlog put_addr=$put_addr put_size=$put_size
vtlog blkdev_get_addr=$blkdev_get_addr blkdev_put_addr=$blkdev_put_addr
vtlog kprobe_reg_addr=$kprobe_reg_addr kprobe_unreg_addr=$kprobe_unreg_addr
vtlog ro_addr=$ro_addr rw_addr=$rw_addr printk_addr=$printk_addr
@ -397,6 +407,8 @@ ventoy_dm_patch() {
vtKv=$($BUSYBOX_PATH/uname -r)
vtKVMajor=$(echo $vtKv | $AWK -F. '{print $1}')
vtKVMinor=$(echo $vtKv | $AWK -F. '{print $2}')
if [ ! -d /lib/modules/$vtKv ]; then
vtlog "No modules directory found"
@ -437,13 +449,18 @@ ventoy_dm_patch() {
#step1: modify vermagic/mod crc/relocation
vtlog "$VTOY_PATH/tool/vtoykmod -u $VTOY_PATH/tool/$vtKoName $VTOY_PATH/$vtModName $vtDebug"
$VTOY_PATH/tool/vtoykmod -u $VTOY_PATH/tool/$vtKoName $VTOY_PATH/$vtModName $vtDebug >>$VTLOG 2>&1
vtlog "$VTOY_PATH/tool/vtoykmod -u $vtKVMajor $vtKVMinor $VTOY_PATH/tool/$vtKoName $VTOY_PATH/$vtModName $vtDebug"
$VTOY_PATH/tool/vtoykmod -u $vtKVMajor $vtKVMinor $VTOY_PATH/tool/$vtKoName $VTOY_PATH/$vtModName $vtDebug >>$VTLOG 2>&1
#step2: fill parameters
vtPgsize=$($VTOY_PATH/tool/vtoyksym -p)
vtlog "$VTOY_PATH/tool/vtoykmod -f $VTOY_PATH/tool/$vtKoName $vtPgsize 0x$printk_addr 0x$ro_addr 0x$rw_addr $get_addr $get_size $put_addr $put_size 0x$kprobe_reg_addr 0x$kprobe_unreg_addr $vtKv $vtIBT $vtDebug"
$VTOY_PATH/tool/vtoykmod -f $VTOY_PATH/tool/$vtKoName $vtPgsize 0x$printk_addr 0x$ro_addr 0x$rw_addr $get_addr $get_size $put_addr $put_size 0x$kprobe_reg_addr 0x$kprobe_unreg_addr $vtKv $vtIBT $vtDebug >>$VTLOG 2>&1
vtPrams="$VTOY_PATH/tool/$vtKoName $vtPgsize 0x$printk_addr 0x$ro_addr 0x$rw_addr $get_addr $get_size $put_addr $put_size 0x$kprobe_reg_addr 0x$kprobe_unreg_addr $vtKVMajor $vtIBT $vtKVMinor $blkdev_get_addr $blkdev_put_addr $vtDebug"
vtlog "$VTOY_PATH/tool/vtoykmod -f $vtPrams"
$VTOY_PATH/tool/vtoykmod -f $vtPrams >>$VTLOG 2>&1
vtlog "insmod $VTOY_PATH/tool/$vtKoName"
$BUSYBOX_PATH/insmod $VTOY_PATH/tool/$vtKoName >>$VTLOG 2>&1

View File

@ -188,6 +188,9 @@ typedef struct ko_param
unsigned long sym_put_size;
unsigned long kv_major;
unsigned long ibt;
unsigned long kv_minor;
unsigned long blkdev_get_addr;
unsigned long blkdev_put_addr;
unsigned long padding[1];
}ko_param;
@ -243,7 +246,7 @@ static int vtoykmod_read_file(char *name, char **buf)
return size;
}
static int vtoykmod_find_section64(char *buf, char *section, int *offset, int *len)
static int vtoykmod_find_section64(char *buf, char *section, int *offset, int *len, Elf64_Shdr **shdr)
{
uint16_t i;
int cmplen;
@ -265,6 +268,10 @@ static int vtoykmod_find_section64(char *buf, char *section, int *offset, int *l
{
*offset = (int)(sec[i].sh_offset);
*len = (int)(sec[i].sh_size);
if (shdr)
{
*shdr = sec + i;
}
return 0;
}
}
@ -272,7 +279,7 @@ static int vtoykmod_find_section64(char *buf, char *section, int *offset, int *l
return 1;
}
static int vtoykmod_find_section32(char *buf, char *section, int *offset, int *len)
static int vtoykmod_find_section32(char *buf, char *section, int *offset, int *len, Elf32_Shdr **shdr)
{
uint16_t i;
int cmplen;
@ -294,6 +301,10 @@ static int vtoykmod_find_section32(char *buf, char *section, int *offset, int *l
{
*offset = (int)(sec[i].sh_offset);
*len = (int)(sec[i].sh_size);
if (shdr)
{
*shdr = sec + i;
}
return 0;
}
}
@ -411,7 +422,7 @@ static int vtoykmod_update_vermagic(char *oldbuf, int oldsize, char *newbuf, int
return 0;
}
int vtoykmod_update(char *oldko, char *newko)
int vtoykmod_update(int kvMajor, int kvMinor, char *oldko, char *newko)
{
int rc = 0;
int modver = 0;
@ -419,6 +430,7 @@ int vtoykmod_update(char *oldko, char *newko)
int newoff, newlen;
int oldsize, newsize;
char *newbuf, *oldbuf;
Elf64_Shdr *sec = NULL;
oldsize = vtoykmod_read_file(oldko, &oldbuf);
newsize = vtoykmod_read_file(newko, &newbuf);
@ -435,13 +447,13 @@ int vtoykmod_update(char *oldko, char *newko)
{
if (oldbuf[EI_CLASS] == ELFCLASS64)
{
rc = vtoykmod_find_section64(oldbuf, "__versions", &oldoff, &oldlen);
rc += vtoykmod_find_section64(newbuf, "__versions", &newoff, &newlen);
rc = vtoykmod_find_section64(oldbuf, "__versions", &oldoff, &oldlen, NULL);
rc += vtoykmod_find_section64(newbuf, "__versions", &newoff, &newlen, NULL);
}
else
{
rc = vtoykmod_find_section32(oldbuf, "__versions", &oldoff, &oldlen);
rc += vtoykmod_find_section32(newbuf, "__versions", &newoff, &newlen);
rc = vtoykmod_find_section32(oldbuf, "__versions", &oldoff, &oldlen, NULL);
rc += vtoykmod_find_section32(newbuf, "__versions", &newoff, &newlen, NULL);
}
if (rc == 0)
@ -459,8 +471,8 @@ int vtoykmod_update(char *oldko, char *newko)
{
Elf64_Rela *oldRela, *newRela;
rc = vtoykmod_find_section64(oldbuf, ".rela.gnu.linkonce.this_module", &oldoff, &oldlen);
rc += vtoykmod_find_section64(newbuf, ".rela.gnu.linkonce.this_module", &newoff, &newlen);
rc = vtoykmod_find_section64(oldbuf, ".rela.gnu.linkonce.this_module", &oldoff, &oldlen, NULL);
rc += vtoykmod_find_section64(newbuf, ".rela.gnu.linkonce.this_module", &newoff, &newlen, NULL);
if (rc == 0)
{
oldRela = (Elf64_Rela *)(oldbuf + oldoff);
@ -478,13 +490,31 @@ int vtoykmod_update(char *oldko, char *newko)
{
debug("section .rela.gnu.linkonce.this_module not found\n");
}
if (kvMajor > 6 || (kvMajor == 6 && kvMinor >= 3))
{
rc = vtoykmod_find_section64(oldbuf, ".gnu.linkonce.this_module", &oldoff, &oldlen, &sec);
rc += vtoykmod_find_section64(newbuf, ".gnu.linkonce.this_module", &newoff, &newlen, NULL);
if (rc == 0)
{
debug("section .gnu.linkonce.this_module change oldlen:0x%x to newlen:0x%x\n", oldlen, newlen);
if (sec)
{
sec->sh_size = newlen;
}
}
else
{
debug("section .gnu.linkonce.this_module not found\n");
}
}
}
else
{
Elf32_Rel *oldRel, *newRel;
rc = vtoykmod_find_section32(oldbuf, ".rel.gnu.linkonce.this_module", &oldoff, &oldlen);
rc += vtoykmod_find_section32(newbuf, ".rel.gnu.linkonce.this_module", &newoff, &newlen);
rc = vtoykmod_find_section32(oldbuf, ".rel.gnu.linkonce.this_module", &oldoff, &oldlen, NULL);
rc += vtoykmod_find_section32(newbuf, ".rel.gnu.linkonce.this_module", &newoff, &newlen, NULL);
if (rc == 0)
{
oldRel = (Elf32_Rel *)(oldbuf + oldoff);
@ -542,8 +572,11 @@ int vtoykmod_fill_param(char **argv)
param->sym_put_size = strtoul(argv[8], NULL, 10);
param->reg_kprobe_addr = strtoul(argv[9], NULL, 16);
param->unreg_kprobe_addr = strtoul(argv[10], NULL, 16);
param->kv_major = (unsigned long)(argv[11][0] - '0');
param->kv_major = strtoul(argv[11], NULL, 10);
param->ibt = strtoul(argv[12], NULL, 16);;
param->kv_minor = strtoul(argv[13], NULL, 10);
param->blkdev_get_addr = strtoul(argv[14], NULL, 16);
param->blkdev_put_addr = strtoul(argv[15], NULL, 16);
debug("pgsize=%lu (%s)\n", param->pgsize, argv[1]);
debug("printk_addr=0x%lx (%s)\n", param->printk_addr, argv[2]);
@ -557,6 +590,9 @@ int vtoykmod_fill_param(char **argv)
debug("unreg_kprobe_addr=0x%lx (%s)\n", param->unreg_kprobe_addr, argv[10]);
debug("kv_major=%lu (%s)\n", param->kv_major, argv[11]);
debug("ibt=0x%lx (%s)\n", param->ibt, argv[12]);
debug("kv_minor=%lu (%s)\n", param->kv_minor, argv[13]);
debug("blkdev_get_addr=0x%lx (%s)\n", param->blkdev_get_addr, argv[14]);
debug("blkdev_put_addr=0x%lx (%s)\n", param->blkdev_put_addr, argv[15]);
break;
}
@ -596,6 +632,8 @@ static int vtoykmod_check_ibt(void)
int vtoykmod_main(int argc, char **argv)
{
int i;
int kvMajor = 0;
int kvMinor = 0;
for (i = 0; i < argc; i++)
{
@ -612,7 +650,9 @@ int vtoykmod_main(int argc, char **argv)
}
else if (argv[1][0] == '-' && argv[1][1] == 'u')
{
return vtoykmod_update(argv[2], argv[3]);
kvMajor = (int)strtol(argv[2], NULL, 10);
kvMinor = (int)strtol(argv[3], NULL, 10);
return vtoykmod_update(kvMajor, kvMinor, argv[4], argv[5]);
}
else if (argv[1][0] == '-' && argv[1][1] == 'I')
{

View File

@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
@ -30,10 +31,12 @@ static int verbose = 0;
int vtoyksym_main(int argc, char **argv)
{
int i;
int len = 0;
unsigned long long addr1 = 0;
unsigned long long addr2 = 0;
char sym[256];
char line[1024];
char *start = NULL;
const char *name = NULL;
FILE *fp;
@ -68,9 +71,11 @@ int vtoyksym_main(int argc, char **argv)
snprintf(sym, sizeof(sym), " %s", argv[1]);
debug("lookup for <%s>\n", sym);
len = (int)strlen(sym);
while (fgets(line, sizeof(line), fp))
{
if (strstr(line, sym))
start = strstr(line, sym);
if (start && (start > line) && isspace(*(start + len)))
{
addr1 = strtoull(line, NULL, 16);
if (!fgets(line, sizeof(line), fp))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.