@@ -312,6 +312,7 @@ xen/test/livepatch/xen_bye_world.livepatch
xen/test/livepatch/xen_hello_world.livepatch
xen/test/livepatch/xen_nop.livepatch
xen/test/livepatch/xen_replace_world.livepatch
+xen/test/livepatch/xen_no_xen_buildid.livepatch
xen/tools/kconfig/.tmp_gtkcheck
xen/tools/kconfig/.tmp_qtcheck
xen/tools/symbols
@@ -270,6 +270,8 @@ like what the Linux kernel module loader does.
The payload contains at least three sections:
* `.livepatch.funcs` - which is an array of livepatch_func structures.
+ * `.livepatch.xen_depends` - which is an ELF Note that describes what Xen
+ build-id the payload depends on. **MUST** have one.
* `.livepatch.depends` - which is an ELF Note that describes what the payload
depends on. **MUST** have one.
* `.note.gnu.build-id` - the build-id of this payload. **MUST** have one.
@@ -383,16 +385,16 @@ The type definition of the function are as follow:
typedef void (*livepatch_loadcall_t)(void);
typedef void (*livepatch_unloadcall_t)(void);
-### .livepatch.depends and .note.gnu.build-id
+### .livepatch.xen_depends, .livepatch.depends and .note.gnu.build-id
To support dependencies checking and safe loading (to load the
appropiate payload against the right hypervisor) there is a need
to embbed an build-id dependency.
-This is done by the payload containing an section `.livepatch.depends`
-which follows the format of an ELF Note. The contents of this
-(name, and description) are specific to the linker utilized to
-build the hypevisor and payload.
+This is done by the payload containing sections `.livepatch.xen_depends`
+and `.livepatch.depends` which follow the format of an ELF Note.
+The contents of these (name, and description) are specific to the linker
+utilized to build the hypevisor and payload.
If GNU linker is used then the name is `GNU` and the description
is a NT_GNU_BUILD_ID type ID. The description can be an SHA1
@@ -400,6 +402,13 @@ checksum, MD5 checksum or any unique value.
The size of these structures varies with the `--build-id` linker option.
+There are two kinds of build-id dependencies:
+
+ * Xen build-id dependency (.livepatch.xen_depends section)
+ * previous payload build-id dependency (.livepatch.depends section)
+
+See "Live patch interdependencies" for more information.
+
## Hypercalls
We will employ the sub operations of the system management hypercall (sysctl).
@@ -894,13 +903,16 @@ but is more complex to implement.
The second option which requires an build-id of the hypervisor
is implemented in the Xen hypervisor.
-Specifically each payload has two build-id ELF notes:
+Specifically each payload has three build-id ELF notes:
* The build-id of the payload itself (generated via --build-id).
+ * The build-id of the Xen hypervisor it depends on (extracted from the
+ hypervisor during build time).
* The build-id of the payload it depends on (extracted from the
the previous payload or hypervisor during build time).
-This means that the very first payload depends on the hypervisor
-build-id.
+This means that every payload depends on the hypervisor build-id and on
+the build-id of the previous payload in the stack.
+The very first payload depends on the hypervisor build-id only.
# Not Yet Done
@@ -74,6 +74,7 @@ struct payload {
unsigned int nsyms; /* Nr of entries in .strtab and symbols. */
struct livepatch_build_id id; /* ELFNOTE_DESC(.note.gnu.build-id) of the payload. */
struct livepatch_build_id dep; /* ELFNOTE_DESC(.livepatch.depends). */
+ struct livepatch_build_id xen_dep; /* ELFNOTE_DESC(.livepatch.xen_depends). */
livepatch_loadcall_t *const *load_funcs; /* The array of funcs to call after */
livepatch_unloadcall_t *const *unload_funcs;/* load and unload of the payload. */
unsigned int n_load_funcs; /* Nr of the funcs to load and execute. */
@@ -476,11 +477,34 @@ static bool section_ok(const struct livepatch_elf *elf,
return true;
}
+static int check_xen_build_id(const struct payload *payload)
+{
+ const void *id = NULL;
+ unsigned int len = 0;
+ int rc;
+
+ ASSERT(payload->xen_dep.len);
+ ASSERT(payload->xen_dep.p);
+
+ rc = xen_build_id(&id, &len);
+ if ( rc )
+ return rc;
+
+ if ( payload->xen_dep.len != len || memcmp(id, payload->xen_dep.p, len) ) {
+ printk(XENLOG_ERR LIVEPATCH "%s: check against hypervisor build-id failed\n",
+ payload->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int check_special_sections(const struct livepatch_elf *elf)
{
unsigned int i;
static const char *const names[] = { ELF_LIVEPATCH_FUNC,
ELF_LIVEPATCH_DEPENDS,
+ ELF_LIVEPATCH_XEN_DEPENDS,
ELF_BUILD_ID_NOTE};
DECLARE_BITMAP(found, ARRAY_SIZE(names)) = { 0 };
@@ -632,6 +656,22 @@ static int prepare_payload(struct payload *payload,
return -EINVAL;
}
+ sec = livepatch_elf_sec_by_name(elf, ELF_LIVEPATCH_XEN_DEPENDS);
+ if ( sec )
+ {
+ n = sec->load_addr;
+
+ if ( sec->sec->sh_size <= sizeof(*n) )
+ return -EINVAL;
+
+ if ( xen_build_id_check(n, sec->sec->sh_size,
+ &payload->xen_dep.p, &payload->xen_dep.len) )
+ return -EINVAL;
+
+ if ( !payload->xen_dep.len || !payload->xen_dep.p )
+ return -EINVAL;
+ }
+
/* Setup the virtual region with proper data. */
region = &payload->region;
@@ -882,6 +922,10 @@ static int load_payload_data(struct payload *payload, void *raw, size_t len)
if ( rc )
goto out;
+ rc = check_xen_build_id(payload);
+ if ( rc )
+ goto out;
+
rc = build_symbol_table(payload, &elf);
if ( rc )
goto out;
@@ -1655,6 +1699,9 @@ static void livepatch_printall(unsigned char key)
if ( data->dep.len )
printk("depend-on=%*phN\n", data->dep.len, data->dep.p);
+
+ if ( data->xen_dep.len )
+ printk("depend-on-xen=%*phN\n", data->xen_dep.len, data->xen_dep.p);
}
spin_unlock(&payload_lock);
@@ -29,9 +29,10 @@ struct xen_sysctl_livepatch_op;
/* Convenience define for printk. */
#define LIVEPATCH "livepatch: "
/* ELF payload special section names. */
-#define ELF_LIVEPATCH_FUNC ".livepatch.funcs"
-#define ELF_LIVEPATCH_DEPENDS ".livepatch.depends"
-#define ELF_BUILD_ID_NOTE ".note.gnu.build-id"
+#define ELF_LIVEPATCH_FUNC ".livepatch.funcs"
+#define ELF_LIVEPATCH_DEPENDS ".livepatch.depends"
+#define ELF_LIVEPATCH_XEN_DEPENDS ".livepatch.xen_depends"
+#define ELF_BUILD_ID_NOTE ".note.gnu.build-id"
/* Arbitrary limit for payload size and .bss section size. */
#define LIVEPATCH_MAX_SIZE MB(2)
@@ -19,11 +19,13 @@ LIVEPATCH := xen_hello_world.livepatch
LIVEPATCH_BYE := xen_bye_world.livepatch
LIVEPATCH_REPLACE := xen_replace_world.livepatch
LIVEPATCH_NOP := xen_nop.livepatch
+LIVEPATCH_NO_XEN_BUILDID := xen_no_xen_buildid.livepatch
LIVEPATCHES += $(LIVEPATCH)
LIVEPATCHES += $(LIVEPATCH_BYE)
LIVEPATCHES += $(LIVEPATCH_REPLACE)
LIVEPATCHES += $(LIVEPATCH_NOP)
+LIVEPATCHES += $(LIVEPATCH_NO_XEN_BUILDID)
LIVEPATCH_DEBUG_DIR ?= $(DEBUG_DIR)/xen-livepatch
@@ -59,7 +61,7 @@ config.h: xen_hello_world_func.o
xen_hello_world.o: config.h
.PHONY: $(LIVEPATCH)
-$(LIVEPATCH): xen_hello_world_func.o xen_hello_world.o note.o
+$(LIVEPATCH): xen_hello_world_func.o xen_hello_world.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH) $^
#
@@ -78,6 +80,17 @@ note.o:
--rename-section=.data=.livepatch.depends,alloc,load,readonly,data,contents -S $@.bin $@
rm -f $@.bin
+#
+# Append .livepatch.xen_depends section
+# with Xen build-id derived from xen-syms.
+#
+.PHONY: xen_note.o
+xen_note.o:
+ $(OBJCOPY) -O binary --only-section=.note.gnu.build-id $(BASEDIR)/xen-syms $@.bin
+ $(OBJCOPY) $(OBJCOPY_MAGIC) \
+ --rename-section=.data=.livepatch.xen_depends,alloc,load,readonly,data,contents -S $@.bin $@
+ rm -f $@.bin
+
#
# Extract the build-id of the xen_hello_world.livepatch
# (which xen_bye_world will depend on).
@@ -92,20 +105,28 @@ hello_world_note.o: $(LIVEPATCH)
xen_bye_world.o: config.h
.PHONY: $(LIVEPATCH_BYE)
-$(LIVEPATCH_BYE): xen_bye_world_func.o xen_bye_world.o hello_world_note.o
+$(LIVEPATCH_BYE): xen_bye_world_func.o xen_bye_world.o hello_world_note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_BYE) $^
xen_replace_world.o: config.h
.PHONY: $(LIVEPATCH_REPLACE)
-$(LIVEPATCH_REPLACE): xen_replace_world_func.o xen_replace_world.o note.o
+$(LIVEPATCH_REPLACE): xen_replace_world_func.o xen_replace_world.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_REPLACE) $^
xen_nop.o: config.h
.PHONY: $(LIVEPATCH_NOP)
-$(LIVEPATCH_NOP): xen_nop.o note.o
+$(LIVEPATCH_NOP): xen_nop.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_NOP) $^
+# This one always fails upon upload, because it deliberately
+# does not have a .livepatch.xen_depends (xen_note.o) section.
+xen_no_xen_buildid.o: config.h
+
+.PHONY: $(LIVEPATCH_NO_XEN_BUILDID)
+$(LIVEPATCH_NO_XEN_BUILDID): xen_nop.o note.o
+ $(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_NO_XEN_BUILDID) $^
+
.PHONY: livepatch
-livepatch: $(LIVEPATCH) $(LIVEPATCH_BYE) $(LIVEPATCH_REPLACE) $(LIVEPATCH_NOP)
+livepatch: $(LIVEPATCH) $(LIVEPATCH_BYE) $(LIVEPATCH_REPLACE) $(LIVEPATCH_NOP) $(LIVEPATCH_NO_XEN_BUILDID)