]>
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/>.
28 #define _ull unsigned long long
30 #define magic_sig 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF
32 #define EI_NIDENT (16)
34 #define EI_MAG0 0 /* e_ident[] indexes */
44 #define ELFMAG0 0x7f /* EI_MAG */
48 #define ELFMAG "\177ELF"
51 #define ELFCLASSNONE 0 /* EI_CLASS */
56 #define ELFDATANONE 0 /* e_ident[EI_DATA] */
60 #define EV_NONE 0 /* e_version, EI_VERSION */
64 #define ELFOSABI_NONE 0
65 #define ELFOSABI_LINUX 3
74 unsigned char e_ident
[EI_NIDENT
]; /* Magic number and other info */
75 uint16_t e_type
; /* Object file type */
76 uint16_t e_machine
; /* Architecture */
77 uint32_t e_version
; /* Object file version */
78 uint32_t e_entry
; /* Entry point virtual address */
79 uint32_t e_phoff
; /* Program header table file offset */
80 uint32_t e_shoff
; /* Section header table file offset */
81 uint32_t e_flags
; /* Processor-specific flags */
82 uint16_t e_ehsize
; /* ELF header size in bytes */
83 uint16_t e_phentsize
; /* Program header table entry size */
84 uint16_t e_phnum
; /* Program header table entry count */
85 uint16_t e_shentsize
; /* Section header table entry size */
86 uint16_t e_shnum
; /* Section header table entry count */
87 uint16_t e_shstrndx
; /* Section header string table index */
92 unsigned char e_ident
[EI_NIDENT
]; /* Magic number and other info */
93 uint16_t e_type
; /* Object file type */
94 uint16_t e_machine
; /* Architecture */
95 uint32_t e_version
; /* Object file version */
96 uint64_t e_entry
; /* Entry point virtual address */
97 uint64_t e_phoff
; /* Program header table file offset */
98 uint64_t e_shoff
; /* Section header table file offset */
99 uint32_t e_flags
; /* Processor-specific flags */
100 uint16_t e_ehsize
; /* ELF header size in bytes */
101 uint16_t e_phentsize
; /* Program header table entry size */
102 uint16_t e_phnum
; /* Program header table entry count */
103 uint16_t e_shentsize
; /* Section header table entry size */
104 uint16_t e_shnum
; /* Section header table entry count */
105 uint16_t e_shstrndx
; /* Section header string table index */
110 uint32_t sh_name
; /* Section name (string tbl index) */
111 uint32_t sh_type
; /* Section type */
112 uint32_t sh_flags
; /* Section flags */
113 uint32_t sh_addr
; /* Section virtual addr at execution */
114 uint32_t sh_offset
; /* Section file offset */
115 uint32_t sh_size
; /* Section size in bytes */
116 uint32_t sh_link
; /* Link to another section */
117 uint32_t sh_info
; /* Additional section information */
118 uint32_t sh_addralign
; /* Section alignment */
119 uint32_t sh_entsize
; /* Entry size if section holds table */
124 uint32_t sh_name
; /* Section name (string tbl index) */
125 uint32_t sh_type
; /* Section type */
126 uint64_t sh_flags
; /* Section flags */
127 uint64_t sh_addr
; /* Section virtual addr at execution */
128 uint64_t sh_offset
; /* Section file offset */
129 uint64_t sh_size
; /* Section size in bytes */
130 uint32_t sh_link
; /* Link to another section */
131 uint32_t sh_info
; /* Additional section information */
132 uint64_t sh_addralign
; /* Section alignment */
133 uint64_t sh_entsize
; /* Entry size if section holds table */
136 typedef struct elf32_rel
{
141 typedef struct elf64_rel
{
142 uint64_t r_offset
; /* Location at which to apply the action */
143 uint64_t r_info
; /* index and type of relocation */
146 typedef struct elf32_rela
{
152 typedef struct elf64_rela
{
153 uint64_t r_offset
; /* Location at which to apply the action */
154 uint64_t r_info
; /* index and type of relocation */
155 int64_t r_addend
; /* Constant addend used to compute value */
159 struct modversion_info
{
161 char name
[64 - sizeof(unsigned long)];
165 typedef struct ko_param
167 unsigned char magic
[16];
168 unsigned long struct_size
;
169 unsigned long pgsize
;
170 unsigned long printk_addr
;
171 unsigned long ro_addr
;
172 unsigned long rw_addr
;
173 unsigned long reg_kprobe_addr
;
174 unsigned long unreg_kprobe_addr
;
175 unsigned long sym_get_addr
;
176 unsigned long sym_get_size
;
177 unsigned long sym_put_addr
;
178 unsigned long sym_put_size
;
179 unsigned long kv_major
;
180 unsigned long padding
[2];
185 static int verbose
= 0;
186 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
188 static int vtoykmod_write_file(char *name
, void *buf
, int size
)
192 fp
= fopen(name
, "wb+");
198 fwrite(buf
, 1, size
, fp
);
204 static int vtoykmod_read_file(char *name
, char **buf
)
210 fp
= fopen(name
, "rb");
213 debug("failed to open %s %d\n", name
, errno
);
217 fseek(fp
, 0, SEEK_END
);
218 size
= (int)ftell(fp
);
219 fseek(fp
, 0, SEEK_SET
);
221 databuf
= malloc(size
);
224 debug("failed to open malloc %d\n", size
);
228 fread(databuf
, 1, size
, fp
);
235 static int vtoykmod_find_section64(char *buf
, char *section
, int *offset
, int *len
)
241 Elf64_Ehdr
*elf
= NULL
;
242 Elf64_Shdr
*sec
= NULL
;
244 cmplen
= (int)strlen(section
);
246 elf
= (Elf64_Ehdr
*)buf
;
247 sec
= (Elf64_Shdr
*)(buf
+ elf
->e_shoff
);
248 strtbl
= buf
+ sec
[elf
->e_shstrndx
].sh_offset
;
250 for (i
= 0; i
< elf
->e_shnum
; i
++)
252 name
= strtbl
+ sec
[i
].sh_name
;
253 if (name
&& strncmp(name
, section
, cmplen
) == 0)
255 *offset
= (int)(sec
[i
].sh_offset
);
256 *len
= (int)(sec
[i
].sh_size
);
264 static int vtoykmod_find_section32(char *buf
, char *section
, int *offset
, int *len
)
270 Elf32_Ehdr
*elf
= NULL
;
271 Elf32_Shdr
*sec
= NULL
;
273 cmplen
= (int)strlen(section
);
275 elf
= (Elf32_Ehdr
*)buf
;
276 sec
= (Elf32_Shdr
*)(buf
+ elf
->e_shoff
);
277 strtbl
= buf
+ sec
[elf
->e_shstrndx
].sh_offset
;
279 for (i
= 0; i
< elf
->e_shnum
; i
++)
281 name
= strtbl
+ sec
[i
].sh_name
;
282 if (name
&& strncmp(name
, section
, cmplen
) == 0)
284 *offset
= (int)(sec
[i
].sh_offset
);
285 *len
= (int)(sec
[i
].sh_size
);
293 static int vtoykmod_update_modcrc(char *oldmodver
, int oldcnt
, char *newmodver
, int newcnt
)
296 struct modversion_info
*pold
, *pnew
;
298 pold
= (struct modversion_info
*)oldmodver
;
299 pnew
= (struct modversion_info
*)newmodver
;
301 for (i
= 0; i
< oldcnt
; i
++)
303 for (j
= 0; j
< newcnt
; j
++)
305 if (strcmp(pold
[i
].name
, pnew
[j
].name
) == 0)
307 debug("CRC 0x%08lx --> 0x%08lx %s\n", pold
[i
].crc
, pnew
[i
].crc
, pold
[i
].name
);
308 pold
[i
].crc
= pnew
[j
].crc
;
317 static int vtoykmod_update_vermagic(char *oldbuf
, int oldsize
, char *newbuf
, int newsize
, int *modver
)
325 for (i
= 0; i
< oldsize
- 9; i
++)
327 if (strncmp(oldbuf
+ i
, "vermagic=", 9) == 0)
329 oldver
= oldbuf
+ i
+ 9;
330 debug("Find old vermagic at %d <%s>\n", i
, oldver
);
335 for (i
= 0; i
< newsize
- 9; i
++)
337 if (strncmp(newbuf
+ i
, "vermagic=", 9) == 0)
339 newver
= newbuf
+ i
+ 9;
340 debug("Find new vermagic at %d <%s>\n", i
, newver
);
345 if (oldver
&& newver
)
347 memcpy(oldver
, newver
, strlen(newver
) + 1);
348 //if (strstr(newver, "modversions"))
357 int vtoykmod_update(char *oldko
, char *newko
)
363 int oldsize
, newsize
;
364 char *newbuf
, *oldbuf
;
366 oldsize
= vtoykmod_read_file(oldko
, &oldbuf
);
367 newsize
= vtoykmod_read_file(newko
, &newbuf
);
368 if (oldsize
< 0 || newsize
< 0)
373 /* 1: update vermagic */
374 vtoykmod_update_vermagic(oldbuf
, oldsize
, newbuf
, newsize
, &modver
);
376 /* 2: update modversion crc */
379 if (oldbuf
[EI_CLASS
] == ELFCLASS64
)
381 rc
= vtoykmod_find_section64(oldbuf
, "__versions", &oldoff
, &oldlen
);
382 rc
+= vtoykmod_find_section64(newbuf
, "__versions", &newoff
, &newlen
);
386 rc
= vtoykmod_find_section32(oldbuf
, "__versions", &oldoff
, &oldlen
);
387 rc
+= vtoykmod_find_section32(newbuf
, "__versions", &newoff
, &newlen
);
392 vtoykmod_update_modcrc(oldbuf
+ oldoff
, oldlen
/ 64, newbuf
+ newoff
, newlen
/ 64);
397 debug("no need to proc modversions\n");
400 /* 3: update relocate address */
401 if (oldbuf
[EI_CLASS
] == ELFCLASS64
)
403 Elf64_Rela
*oldRela
, *newRela
;
405 rc
= vtoykmod_find_section64(oldbuf
, ".rela.gnu.linkonce.this_module", &oldoff
, &oldlen
);
406 rc
+= vtoykmod_find_section64(newbuf
, ".rela.gnu.linkonce.this_module", &newoff
, &newlen
);
409 oldRela
= (Elf64_Rela
*)(oldbuf
+ oldoff
);
410 newRela
= (Elf64_Rela
*)(newbuf
+ newoff
);
412 debug("init_module rela: 0x%llx --> 0x%llx\n", (_ull
)(oldRela
[0].r_offset
), (_ull
)(newRela
[0].r_offset
));
413 oldRela
[0].r_offset
= newRela
[0].r_offset
;
414 oldRela
[0].r_addend
= newRela
[0].r_addend
;
416 debug("cleanup_module rela: 0x%llx --> 0x%llx\n", (_ull
)(oldRela
[1].r_offset
), (_ull
)(newRela
[1].r_offset
));
417 oldRela
[1].r_offset
= newRela
[1].r_offset
;
418 oldRela
[1].r_addend
= newRela
[1].r_addend
;
422 debug("section .rela.gnu.linkonce.this_module not found\n");
427 Elf32_Rel
*oldRel
, *newRel
;
429 rc
= vtoykmod_find_section32(oldbuf
, ".rel.gnu.linkonce.this_module", &oldoff
, &oldlen
);
430 rc
+= vtoykmod_find_section32(newbuf
, ".rel.gnu.linkonce.this_module", &newoff
, &newlen
);
433 oldRel
= (Elf32_Rel
*)(oldbuf
+ oldoff
);
434 newRel
= (Elf32_Rel
*)(newbuf
+ newoff
);
436 debug("init_module rel: 0x%x --> 0x%x\n", oldRel
[0].r_offset
, newRel
[0].r_offset
);
437 oldRel
[0].r_offset
= newRel
[0].r_offset
;
439 debug("cleanup_module rel: 0x%x --> 0x%x\n", oldRel
[0].r_offset
, newRel
[0].r_offset
);
440 oldRel
[1].r_offset
= newRel
[1].r_offset
;
444 debug("section .rel.gnu.linkonce.this_module not found\n");
448 vtoykmod_write_file(oldko
, oldbuf
, oldsize
);
456 int vtoykmod_fill_param(char **argv
)
462 unsigned char magic
[16] = { magic_sig
};
464 size
= vtoykmod_read_file(argv
[0], &buf
);
470 for (i
= 0; i
< size
; i
++)
472 if (memcmp(buf
+ i
, magic
, 16) == 0)
474 debug("Find param magic at %d\n", i
);
475 param
= (ko_param
*)(buf
+ i
);
477 param
->struct_size
= (unsigned long)sizeof(ko_param
);
478 param
->pgsize
= strtoul(argv
[1], NULL
, 10);
479 param
->printk_addr
= strtoul(argv
[2], NULL
, 16);
480 param
->ro_addr
= strtoul(argv
[3], NULL
, 16);
481 param
->rw_addr
= strtoul(argv
[4], NULL
, 16);
482 param
->sym_get_addr
= strtoul(argv
[5], NULL
, 16);
483 param
->sym_get_size
= strtoul(argv
[6], NULL
, 10);
484 param
->sym_put_addr
= strtoul(argv
[7], NULL
, 16);
485 param
->sym_put_size
= strtoul(argv
[8], NULL
, 10);
486 param
->reg_kprobe_addr
= strtoul(argv
[9], NULL
, 16);
487 param
->unreg_kprobe_addr
= strtoul(argv
[10], NULL
, 16);
488 param
->kv_major
= (unsigned long)(argv
[11][0] - '0');
490 debug("pgsize=%lu (%s)\n", param
->pgsize
, argv
[1]);
491 debug("printk_addr=0x%lx (%s)\n", param
->printk_addr
, argv
[2]);
492 debug("ro_addr=0x%lx (%s)\n", param
->ro_addr
, argv
[3]);
493 debug("rw_addr=0x%lx (%s)\n", param
->rw_addr
, argv
[4]);
494 debug("sym_get_addr=0x%lx (%s)\n", param
->sym_get_addr
, argv
[5]);
495 debug("sym_get_size=%lu (%s)\n", param
->sym_get_size
, argv
[6]);
496 debug("sym_put_addr=0x%lx (%s)\n", param
->sym_put_addr
, argv
[7]);
497 debug("sym_put_size=%lu (%s)\n", param
->sym_put_size
, argv
[8]);
498 debug("reg_kprobe_addr=0x%lx (%s)\n", param
->reg_kprobe_addr
, argv
[9]);
499 debug("unreg_kprobe_addr=0x%lx (%s)\n", param
->unreg_kprobe_addr
, argv
[10]);
500 debug("kv_major=%lu (%s)\n", param
->kv_major
, argv
[11]);
508 debug("### param magic not found \n");
511 vtoykmod_write_file(argv
[0], buf
, size
);
517 int vtoykmod_main(int argc
, char **argv
)
521 for (i
= 0; i
< argc
; i
++)
523 if (argv
[i
][0] == '-' && argv
[i
][1] == 'v')
530 if (argv
[1][0] == '-' && argv
[1][1] == 'f')
532 return vtoykmod_fill_param(argv
+ 2);
534 else if (argv
[1][0] == '-' && argv
[1][1] == 'u')
536 return vtoykmod_update(argv
[2], argv
[3]);
543 #ifndef BUILD_VTOY_TOOL
544 int main(int argc
, char **argv
)
546 return vtoykmod_main(argc
, argv
);