mirror of
https://github.com/dynup/kpatch
synced 2025-03-02 00:40:54 +00:00
create-diff-object: handle missing padding at end of special section
The paravirt_patch_site struct has 12 bytes of data and 4 bytes of padding, for a total of 16 bytes. However, when laying out the structs in the .parainstructions section, the vmlinux script only aligns before each struct's data, not after. So the last entry doesn't have the 4-byte padding, which breaks kpatch_regenerate_special_section()'s assumption of a 16-byte struct, resulting in a memcpy past the end of the section. Fixes #747. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
This commit is contained in:
parent
0b8a53163d
commit
c2dc3836e8
@ -1793,7 +1793,7 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
|
||||
{
|
||||
struct rela *rela, *safe;
|
||||
char *src, *dest;
|
||||
int group_size, src_offset, dest_offset, include, align, aligned_size;
|
||||
int group_size, src_offset, dest_offset, include;
|
||||
|
||||
LIST_HEAD(newrelas);
|
||||
|
||||
@ -1817,6 +1817,18 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
|
||||
for ( ; src_offset < sec->base->sh.sh_size; src_offset += group_size) {
|
||||
|
||||
group_size = special->group_size(kelf, src_offset);
|
||||
|
||||
/*
|
||||
* In some cases the struct has padding at the end to ensure
|
||||
* that all structs after it are properly aligned. But the
|
||||
* last struct in the section may not be padded. In that case,
|
||||
* shrink the group_size such that it still (hopefully)
|
||||
* contains the data but doesn't go past the end of the
|
||||
* section.
|
||||
*/
|
||||
if (src_offset + group_size > sec->base->sh.sh_size)
|
||||
group_size = sec->base->sh.sh_size - src_offset;
|
||||
|
||||
include = should_keep_rela_group(sec, src_offset, group_size);
|
||||
|
||||
if (!include)
|
||||
@ -1853,12 +1865,6 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
|
||||
dest_offset += group_size;
|
||||
}
|
||||
|
||||
/* verify that group_size is a divisor of aligned section size */
|
||||
align = sec->base->sh.sh_addralign;
|
||||
aligned_size = ((sec->base->sh.sh_size + align - 1) / align) * align;
|
||||
if (src_offset != aligned_size)
|
||||
ERROR("group size mismatch for section %s\n", sec->base->name);
|
||||
|
||||
if (!dest_offset) {
|
||||
/* no changed or global functions referenced */
|
||||
sec->status = sec->base->status = SAME;
|
||||
|
Loading…
Reference in New Issue
Block a user