diff mbox series

[6/9] create-diff-object: detect changes in .altinstr_replacement and .fixup sections

Message ID 20240429145654.71669-7-roger.pau@citrix.com (mailing list archive)
State New, archived
Headers show
Series livepatch-build-tools: some bug fixes and improvements | expand

Commit Message

Roger Pau Monné April 29, 2024, 2:56 p.m. UTC
The current logic to detect changes in special sections elements will only
include group elements that reference function symbols that need including
(either because they have changed or are new).

This works fine in order to detect when a special section element needs
including because of the function is points has changed or is newly introduced,
but doesn't detect changes to the replacement code in .altinstr_replacement or
.fixup sections, as the relocations in that case are against STT_SECTION
symbols.

Fix this by also including the special section group if the symbol the
relocations points to is of type section.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
 create-diff-object.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/create-diff-object.c b/create-diff-object.c
index 7674d972e301..f4e4da063d0a 100644
--- a/create-diff-object.c
+++ b/create-diff-object.c
@@ -1158,11 +1158,21 @@  static int should_keep_rela_group(struct section *sec, int start, int size)
 	struct rela *rela;
 	int found = 0;
 
-	/* check if any relas in the group reference any changed functions */
+	/*
+	 * Check if any relas in the group reference any changed functions.
+	 *
+	 * Relocations in the .altinstructions and .ex_table special sections
+	 * can also reference changed section symbols, since the replacement
+	 * text in both cases resides on a section that has no function symbols
+	 * (.altinstr_replacement and .fixup respectively).  Account for that
+	 * and also check whether the referenced symbols are section ones in
+	 * order to decide whether the relocation group needs including.
+	 */
 	list_for_each_entry(rela, &sec->relas, list) {
 		if (rela->offset >= start &&
 		    rela->offset < start + size &&
-		    rela->sym->type == STT_FUNC &&
+		    (rela->sym->type == STT_FUNC ||
+		     rela->sym->type == STT_SECTION) &&
 		    rela->sym->sec->include) {
 			found = 1;
 			log_debug("new/changed symbol %s found in special section %s\n",
@@ -1338,6 +1348,21 @@  static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
 
 				rela->sym->include = 1;
 
+				/*
+				 * Changes that cause only the
+				 * .altinstr_replacement or .fixup sections to
+				 * be modified need the target function of the
+				 * replacement to also be marked as CHANGED,
+				 * otherwise livepatch won't replace the
+				 * function, and the new replacement code won't
+				 * take effect.
+				 */
+				if (rela->sym->type == STT_FUNC &&
+				    rela->sym->status == SAME) {
+					rela->sym->status = CHANGED;
+					kpatch_include_symbol(rela->sym, 0);
+				}
+
 				if (!strcmp(special->name, ".fixup"))
 					kpatch_update_ex_table_addend(kelf, special,
 								      src_offset,