]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - VtoyTool/vtoykmod.c
1 /******************************************************************************
2 * vtoykmod.c ---- ventoy kmod
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
31 #define _ull unsigned long long
33 #define magic_sig 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF
35 #define EI_NIDENT (16)
37 #define EI_MAG0 0 /* e_ident[] indexes */
47 #define ELFMAG0 0x7f /* EI_MAG */
51 #define ELFMAG "\177ELF"
54 #define ELFCLASSNONE 0 /* EI_CLASS */
59 #define ELFDATANONE 0 /* e_ident[EI_DATA] */
63 #define EV_NONE 0 /* e_version, EI_VERSION */
67 #define ELFOSABI_NONE 0
68 #define ELFOSABI_LINUX 3
77 unsigned char e_ident
[EI_NIDENT
]; /* Magic number and other info */
78 uint16_t e_type
; /* Object file type */
79 uint16_t e_machine
; /* Architecture */
80 uint32_t e_version
; /* Object file version */
81 uint32_t e_entry
; /* Entry point virtual address */
82 uint32_t e_phoff
; /* Program header table file offset */
83 uint32_t e_shoff
; /* Section header table file offset */
84 uint32_t e_flags
; /* Processor-specific flags */
85 uint16_t e_ehsize
; /* ELF header size in bytes */
86 uint16_t e_phentsize
; /* Program header table entry size */
87 uint16_t e_phnum
; /* Program header table entry count */
88 uint16_t e_shentsize
; /* Section header table entry size */
89 uint16_t e_shnum
; /* Section header table entry count */
90 uint16_t e_shstrndx
; /* Section header string table index */
95 unsigned char e_ident
[EI_NIDENT
]; /* Magic number and other info */
96 uint16_t e_type
; /* Object file type */
97 uint16_t e_machine
; /* Architecture */
98 uint32_t e_version
; /* Object file version */
99 uint64_t e_entry
; /* Entry point virtual address */
100 uint64_t e_phoff
; /* Program header table file offset */
101 uint64_t e_shoff
; /* Section header table file offset */
102 uint32_t e_flags
; /* Processor-specific flags */
103 uint16_t e_ehsize
; /* ELF header size in bytes */
104 uint16_t e_phentsize
; /* Program header table entry size */
105 uint16_t e_phnum
; /* Program header table entry count */
106 uint16_t e_shentsize
; /* Section header table entry size */
107 uint16_t e_shnum
; /* Section header table entry count */
108 uint16_t e_shstrndx
; /* Section header string table index */
113 uint32_t sh_name
; /* Section name (string tbl index) */
114 uint32_t sh_type
; /* Section type */
115 uint32_t sh_flags
; /* Section flags */
116 uint32_t sh_addr
; /* Section virtual addr at execution */
117 uint32_t sh_offset
; /* Section file offset */
118 uint32_t sh_size
; /* Section size in bytes */
119 uint32_t sh_link
; /* Link to another section */
120 uint32_t sh_info
; /* Additional section information */
121 uint32_t sh_addralign
; /* Section alignment */
122 uint32_t sh_entsize
; /* Entry size if section holds table */
127 uint32_t sh_name
; /* Section name (string tbl index) */
128 uint32_t sh_type
; /* Section type */
129 uint64_t sh_flags
; /* Section flags */
130 uint64_t sh_addr
; /* Section virtual addr at execution */
131 uint64_t sh_offset
; /* Section file offset */
132 uint64_t sh_size
; /* Section size in bytes */
133 uint32_t sh_link
; /* Link to another section */
134 uint32_t sh_info
; /* Additional section information */
135 uint64_t sh_addralign
; /* Section alignment */
136 uint64_t sh_entsize
; /* Entry size if section holds table */
139 typedef struct elf32_rel
{
144 typedef struct elf64_rel
{
145 uint64_t r_offset
; /* Location at which to apply the action */
146 uint64_t r_info
; /* index and type of relocation */
149 typedef struct elf32_rela
{
155 typedef struct elf64_rela
{
156 uint64_t r_offset
; /* Location at which to apply the action */
157 uint64_t r_info
; /* index and type of relocation */
158 int64_t r_addend
; /* Constant addend used to compute value */
162 struct modversion_info
{
164 char name
[64 - sizeof(unsigned long)];
167 struct modversion_info2
{
168 /* Offset of the next modversion entry in relation to this one. */
175 typedef struct ko_param
177 unsigned char magic
[16];
178 unsigned long struct_size
;
179 unsigned long pgsize
;
180 unsigned long printk_addr
;
181 unsigned long ro_addr
;
182 unsigned long rw_addr
;
183 unsigned long reg_kprobe_addr
;
184 unsigned long unreg_kprobe_addr
;
185 unsigned long sym_get_addr
;
186 unsigned long sym_get_size
;
187 unsigned long sym_put_addr
;
188 unsigned long sym_put_size
;
189 unsigned long kv_major
;
191 unsigned long kv_minor
;
192 unsigned long blkdev_get_addr
;
193 unsigned long blkdev_put_addr
;
194 unsigned long padding
[1];
199 static int verbose
= 0;
200 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
202 static int vtoykmod_write_file(char *name
, void *buf
, int size
)
206 fp
= fopen(name
, "wb+");
212 fwrite(buf
, 1, size
, fp
);
218 static int vtoykmod_read_file(char *name
, char **buf
)
224 fp
= fopen(name
, "rb");
227 debug("failed to open %s %d\n", name
, errno
);
231 fseek(fp
, 0, SEEK_END
);
232 size
= (int)ftell(fp
);
233 fseek(fp
, 0, SEEK_SET
);
235 databuf
= malloc(size
);
238 debug("failed to open malloc %d\n", size
);
242 fread(databuf
, 1, size
, fp
);
249 static int vtoykmod_find_section64(char *buf
, char *section
, int *offset
, int *len
, Elf64_Shdr
**shdr
)
255 Elf64_Ehdr
*elf
= NULL
;
256 Elf64_Shdr
*sec
= NULL
;
258 cmplen
= (int)strlen(section
);
260 elf
= (Elf64_Ehdr
*)buf
;
261 sec
= (Elf64_Shdr
*)(buf
+ elf
->e_shoff
);
262 strtbl
= buf
+ sec
[elf
->e_shstrndx
].sh_offset
;
264 for (i
= 0; i
< elf
->e_shnum
; i
++)
266 name
= strtbl
+ sec
[i
].sh_name
;
267 if (name
&& strncmp(name
, section
, cmplen
) == 0)
269 *offset
= (int)(sec
[i
].sh_offset
);
270 *len
= (int)(sec
[i
].sh_size
);
282 static int vtoykmod_find_section32(char *buf
, char *section
, int *offset
, int *len
, Elf32_Shdr
**shdr
)
288 Elf32_Ehdr
*elf
= NULL
;
289 Elf32_Shdr
*sec
= NULL
;
291 cmplen
= (int)strlen(section
);
293 elf
= (Elf32_Ehdr
*)buf
;
294 sec
= (Elf32_Shdr
*)(buf
+ elf
->e_shoff
);
295 strtbl
= buf
+ sec
[elf
->e_shstrndx
].sh_offset
;
297 for (i
= 0; i
< elf
->e_shnum
; i
++)
299 name
= strtbl
+ sec
[i
].sh_name
;
300 if (name
&& strncmp(name
, section
, cmplen
) == 0)
302 *offset
= (int)(sec
[i
].sh_offset
);
303 *len
= (int)(sec
[i
].sh_size
);
315 static int vtoykmod_update_modcrc1(char *oldmodver
, int oldcnt
, char *newmodver
, int newcnt
)
318 struct modversion_info
*pold
, *pnew
;
320 pold
= (struct modversion_info
*)oldmodver
;
321 pnew
= (struct modversion_info
*)newmodver
;
323 debug("module update modver format 1\n");
324 for (i
= 0; i
< oldcnt
; i
++)
326 for (j
= 0; j
< newcnt
; j
++)
328 if (strcmp(pold
[i
].name
, pnew
[j
].name
) == 0)
330 debug("CRC 0x%08lx --> 0x%08lx %s\n", pold
[i
].crc
, pnew
[i
].crc
, pold
[i
].name
);
331 pold
[i
].crc
= pnew
[j
].crc
;
341 static int vtoykmod_update_modcrc2(char *oldmodver
, int oldlen
, char *newmodver
, int newlen
)
343 struct modversion_info2
*pold
, *pnew
, *pnewend
;
345 pold
= (struct modversion_info2
*)oldmodver
;
346 pnew
= (struct modversion_info2
*)newmodver
;
347 pnewend
= (struct modversion_info2
*)(newmodver
+ newlen
);
349 debug("module update modver format 2\n");
350 /* here we think that there is only module_layout in oldmodver */
352 for (; pnew
< pnewend
&& pnew
->next
; pnew
= (struct modversion_info2
*)((char *)pnew
+ pnew
->next
))
354 if (strcmp(pnew
->name
, "module_layout") == 0)
356 debug("CRC 0x%08x --> 0x%08x %s\n", pold
->crc
, pnew
->crc
, pnew
->name
);
357 memset(pold
, 0, oldlen
);
358 pold
->next
= 0x18; /* 8 + module_layout align 8 */
359 pold
->crc
= pnew
->crc
;
360 strcpy(pold
->name
, pnew
->name
);
369 static int vtoykmod_update_modcrc(char *oldmodver
, int oldlen
, char *newmodver
, int newlen
)
373 memcpy(&uiCrc
, newmodver
+ 4, 4);
377 return vtoykmod_update_modcrc2(oldmodver
, oldlen
, newmodver
, newlen
);
381 return vtoykmod_update_modcrc1(oldmodver
, oldlen
/ 64, newmodver
, newlen
/ 64);
385 static int vtoykmod_update_vermagic(char *oldbuf
, int oldsize
, char *newbuf
, int newsize
, int *modver
)
393 for (i
= 0; i
< oldsize
- 9; i
++)
395 if (strncmp(oldbuf
+ i
, "vermagic=", 9) == 0)
397 oldver
= oldbuf
+ i
+ 9;
398 debug("Find old vermagic at %d <%s>\n", i
, oldver
);
403 for (i
= 0; i
< newsize
- 9; i
++)
405 if (strncmp(newbuf
+ i
, "vermagic=", 9) == 0)
407 newver
= newbuf
+ i
+ 9;
408 debug("Find new vermagic at %d <%s>\n", i
, newver
);
413 if (oldver
&& newver
)
415 memcpy(oldver
, newver
, strlen(newver
) + 1);
416 //if (strstr(newver, "modversions"))
425 int vtoykmod_update(int kvMajor
, int kvMinor
, char *oldko
, char *newko
)
431 int oldsize
, newsize
;
432 char *newbuf
, *oldbuf
;
433 Elf64_Shdr
*sec
= NULL
;
435 oldsize
= vtoykmod_read_file(oldko
, &oldbuf
);
436 newsize
= vtoykmod_read_file(newko
, &newbuf
);
437 if (oldsize
< 0 || newsize
< 0)
442 /* 1: update vermagic */
443 vtoykmod_update_vermagic(oldbuf
, oldsize
, newbuf
, newsize
, &modver
);
445 /* 2: update modversion crc */
448 if (oldbuf
[EI_CLASS
] == ELFCLASS64
)
450 rc
= vtoykmod_find_section64(oldbuf
, "__versions", &oldoff
, &oldlen
, NULL
);
451 rc
+= vtoykmod_find_section64(newbuf
, "__versions", &newoff
, &newlen
, NULL
);
455 rc
= vtoykmod_find_section32(oldbuf
, "__versions", &oldoff
, &oldlen
, NULL
);
456 rc
+= vtoykmod_find_section32(newbuf
, "__versions", &newoff
, &newlen
, NULL
);
461 vtoykmod_update_modcrc(oldbuf
+ oldoff
, oldlen
, newbuf
+ newoff
, newlen
);
466 debug("no need to proc modversions\n");
469 /* 3: update relocate address */
470 if (oldbuf
[EI_CLASS
] == ELFCLASS64
)
472 Elf64_Rela
*oldRela
, *newRela
;
474 rc
= vtoykmod_find_section64(oldbuf
, ".rela.gnu.linkonce.this_module", &oldoff
, &oldlen
, NULL
);
475 rc
+= vtoykmod_find_section64(newbuf
, ".rela.gnu.linkonce.this_module", &newoff
, &newlen
, NULL
);
478 oldRela
= (Elf64_Rela
*)(oldbuf
+ oldoff
);
479 newRela
= (Elf64_Rela
*)(newbuf
+ newoff
);
481 debug("init_module rela: 0x%llx --> 0x%llx\n", (_ull
)(oldRela
[0].r_offset
), (_ull
)(newRela
[0].r_offset
));
482 oldRela
[0].r_offset
= newRela
[0].r_offset
;
483 oldRela
[0].r_addend
= newRela
[0].r_addend
;
485 debug("cleanup_module rela: 0x%llx --> 0x%llx\n", (_ull
)(oldRela
[1].r_offset
), (_ull
)(newRela
[1].r_offset
));
486 oldRela
[1].r_offset
= newRela
[1].r_offset
;
487 oldRela
[1].r_addend
= newRela
[1].r_addend
;
491 debug("section .rela.gnu.linkonce.this_module not found\n");
494 if (kvMajor
> 6 || (kvMajor
== 6 && kvMinor
>= 3))
496 rc
= vtoykmod_find_section64(oldbuf
, ".gnu.linkonce.this_module", &oldoff
, &oldlen
, &sec
);
497 rc
+= vtoykmod_find_section64(newbuf
, ".gnu.linkonce.this_module", &newoff
, &newlen
, NULL
);
500 debug("section .gnu.linkonce.this_module change oldlen:0x%x to newlen:0x%x\n", oldlen
, newlen
);
503 sec
->sh_size
= newlen
;
508 debug("section .gnu.linkonce.this_module not found\n");
514 Elf32_Rel
*oldRel
, *newRel
;
516 rc
= vtoykmod_find_section32(oldbuf
, ".rel.gnu.linkonce.this_module", &oldoff
, &oldlen
, NULL
);
517 rc
+= vtoykmod_find_section32(newbuf
, ".rel.gnu.linkonce.this_module", &newoff
, &newlen
, NULL
);
520 oldRel
= (Elf32_Rel
*)(oldbuf
+ oldoff
);
521 newRel
= (Elf32_Rel
*)(newbuf
+ newoff
);
523 debug("init_module rel: 0x%x --> 0x%x\n", oldRel
[0].r_offset
, newRel
[0].r_offset
);
524 oldRel
[0].r_offset
= newRel
[0].r_offset
;
526 debug("cleanup_module rel: 0x%x --> 0x%x\n", oldRel
[0].r_offset
, newRel
[0].r_offset
);
527 oldRel
[1].r_offset
= newRel
[1].r_offset
;
531 debug("section .rel.gnu.linkonce.this_module not found\n");
535 vtoykmod_write_file(oldko
, oldbuf
, oldsize
);
543 int vtoykmod_fill_param(char **argv
)
549 unsigned char magic
[16] = { magic_sig
};
551 size
= vtoykmod_read_file(argv
[0], &buf
);
557 for (i
= 0; i
< size
; i
++)
559 if (memcmp(buf
+ i
, magic
, 16) == 0)
561 debug("Find param magic at %d\n", i
);
562 param
= (ko_param
*)(buf
+ i
);
564 param
->struct_size
= (unsigned long)sizeof(ko_param
);
565 param
->pgsize
= strtoul(argv
[1], NULL
, 10);
566 param
->printk_addr
= strtoul(argv
[2], NULL
, 16);
567 param
->ro_addr
= strtoul(argv
[3], NULL
, 16);
568 param
->rw_addr
= strtoul(argv
[4], NULL
, 16);
569 param
->sym_get_addr
= strtoul(argv
[5], NULL
, 16);
570 param
->sym_get_size
= strtoul(argv
[6], NULL
, 10);
571 param
->sym_put_addr
= strtoul(argv
[7], NULL
, 16);
572 param
->sym_put_size
= strtoul(argv
[8], NULL
, 10);
573 param
->reg_kprobe_addr
= strtoul(argv
[9], NULL
, 16);
574 param
->unreg_kprobe_addr
= strtoul(argv
[10], NULL
, 16);
575 param
->kv_major
= strtoul(argv
[11], NULL
, 10);
576 param
->ibt
= strtoul(argv
[12], NULL
, 16);;
577 param
->kv_minor
= strtoul(argv
[13], NULL
, 10);
578 param
->blkdev_get_addr
= strtoul(argv
[14], NULL
, 16);
579 param
->blkdev_put_addr
= strtoul(argv
[15], NULL
, 16);
581 debug("pgsize=%lu (%s)\n", param
->pgsize
, argv
[1]);
582 debug("printk_addr=0x%lx (%s)\n", param
->printk_addr
, argv
[2]);
583 debug("ro_addr=0x%lx (%s)\n", param
->ro_addr
, argv
[3]);
584 debug("rw_addr=0x%lx (%s)\n", param
->rw_addr
, argv
[4]);
585 debug("sym_get_addr=0x%lx (%s)\n", param
->sym_get_addr
, argv
[5]);
586 debug("sym_get_size=%lu (%s)\n", param
->sym_get_size
, argv
[6]);
587 debug("sym_put_addr=0x%lx (%s)\n", param
->sym_put_addr
, argv
[7]);
588 debug("sym_put_size=%lu (%s)\n", param
->sym_put_size
, argv
[8]);
589 debug("reg_kprobe_addr=0x%lx (%s)\n", param
->reg_kprobe_addr
, argv
[9]);
590 debug("unreg_kprobe_addr=0x%lx (%s)\n", param
->unreg_kprobe_addr
, argv
[10]);
591 debug("kv_major=%lu (%s)\n", param
->kv_major
, argv
[11]);
592 debug("ibt=0x%lx (%s)\n", param
->ibt
, argv
[12]);
593 debug("kv_minor=%lu (%s)\n", param
->kv_minor
, argv
[13]);
594 debug("blkdev_get_addr=0x%lx (%s)\n", param
->blkdev_get_addr
, argv
[14]);
595 debug("blkdev_put_addr=0x%lx (%s)\n", param
->blkdev_put_addr
, argv
[15]);
603 debug("### param magic not found \n");
606 vtoykmod_write_file(argv
[0], buf
, size
);
613 static int vtoykmod_check_ibt(void)
615 uint32_t eax
= 0, ebx
= 0, ecx
= 0, edx
= 0;
617 __cpuid_count(7, 0, eax
, ebx
, ecx
, edx
);
626 static int vtoykmod_check_ibt(void)
632 int vtoykmod_main(int argc
, char **argv
)
638 for (i
= 0; i
< argc
; i
++)
640 if (argv
[i
][0] == '-' && argv
[i
][1] == 'v')
649 printf("==== Dump Argv ====\n");
650 for (i
= 0; i
< argc
; i
++)
652 printf("<%s> ", argv
[i
]);
657 if (argv
[1][0] == '-' && argv
[1][1] == 'f')
659 return vtoykmod_fill_param(argv
+ 2);
661 else if (argv
[1][0] == '-' && argv
[1][1] == 'u')
663 kvMajor
= (int)strtol(argv
[2], NULL
, 10);
664 kvMinor
= (int)strtol(argv
[3], NULL
, 10);
665 return vtoykmod_update(kvMajor
, kvMinor
, argv
[4], argv
[5]);
667 else if (argv
[1][0] == '-' && argv
[1][1] == 'I')
669 return vtoykmod_check_ibt();
676 #ifndef BUILD_VTOY_TOOL
677 int main(int argc
, char **argv
)
679 return vtoykmod_main(argc
, argv
);