Precede each serialized File-Lifecycle-Bound (FLB) entry in the preserved FLB array with struct kho_ser_hdr via DECLARE_KHO_SER so future FLB metadata features can append fields to struct luo_flb_ser without breaking compatibility between adjacent kernels. Compute LUO_FLB_MAX and outgoing entry offsets using kho_ser_size(luo_flb_ser), and initialize each entry feature header in luo_flb_serialize(). On the incoming path in luo_flb_retrieve_one(), validate each entry feature header with kho_ser_validate() and advance between entries using fhdr->size so entries written with a different feature layout are traversed accurately. Signed-off-by: Tarun Sahu --- include/linux/kho/abi/luo.h | 6 ++---- kernel/liveupdate/luo_flb.c | 39 +++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h index 4913707ba0d3..1b660d41bb90 100644 --- a/include/linux/kho/abi/luo.h +++ b/include/linux/kho/abi/luo.h @@ -181,7 +181,7 @@ DECLARE_KHO_SER(luo_flb_header_ser, 16, 0, 0); * passed to the new kernel. Each entry allows the LUO core to restore one * global, shared object. * - * If this structure is modified, `LUO_ABI_COMPATIBLE` must be updated. + * Preceded by &struct kho_ser_hdr. */ struct luo_flb_ser { char name[LIVEUPDATE_FLB_COMPAT_LENGTH]; @@ -189,9 +189,7 @@ struct luo_flb_ser { u64 count; }; -static_assert(sizeof(struct luo_flb_ser) == 64); -static_assert(!IS_ENABLED(CONFIG_64BIT) || - __alignof__(struct luo_flb_ser) == 8); +DECLARE_KHO_SER(luo_flb_ser, 64, 0, 0); /* Kernel Live Update Test ABI */ #ifdef CONFIG_LIVEUPDATE_TEST diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c index a8dcdb8456fd..d38c223741ff 100644 --- a/kernel/liveupdate/luo_flb.c +++ b/kernel/liveupdate/luo_flb.c @@ -53,11 +53,11 @@ #define LUO_FLB_PGCNT 1ul #define LUO_FLB_MAX (((LUO_FLB_PGCNT << PAGE_SHIFT) - \ - kho_ser_size(luo_flb_header_ser)) / sizeof(struct luo_flb_ser)) + kho_ser_size(luo_flb_header_ser)) / kho_ser_size(luo_flb_ser)) struct luo_flb_header { struct luo_flb_header_ser *header_ser; - struct luo_flb_ser *ser; + DECLARE_KHO_SER_HDR(luo_flb_ser, *fhdr); bool active; }; @@ -159,6 +159,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb) { struct luo_flb_private *private = luo_flb_get_private(flb); struct luo_flb_header *fh = &luo_flb_global.incoming; + DECLARE_KHO_SER_HDR(luo_flb_ser, *fhdr) = fh->fhdr; struct liveupdate_flb_op_args args = {0}; bool found = false; int err; @@ -177,10 +178,18 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb) if (!fh->active) return -ENODATA; - for (int i = 0; i < fh->header_ser->count; i++) { - if (!strcmp(fh->ser[i].name, flb->compatible)) { - private->incoming.data = fh->ser[i].data; - refcount_set(&private->incoming.count, fh->ser[i].count); + for (u64 i = 0; i < fh->header_ser->count; + i++, fhdr = (void *)fhdr + fhdr->size) { + struct luo_flb_ser *ser; + + err = kho_ser_validate(fhdr, luo_flb_ser); + if (err) + return err; + + ser = kho_ser_payload(fhdr, luo_flb_ser); + if (!strcmp(ser->name, flb->compatible)) { + private->incoming.data = ser->data; + refcount_set(&private->incoming.count, ser->count); found = true; break; } @@ -573,7 +582,7 @@ int __init luo_flb_setup_outgoing(u64 *flbs_pa) header_ser->pgcnt = LUO_FLB_PGCNT; luo_flb_global.outgoing.header_ser = header_ser; - luo_flb_global.outgoing.ser = (void *)fhdr + kho_ser_size(luo_flb_header_ser); + luo_flb_global.outgoing.fhdr = (void *)fhdr + kho_ser_size(luo_flb_header_ser); luo_flb_global.outgoing.active = true; return 0; @@ -594,7 +603,7 @@ int __init luo_flb_setup_incoming(u64 flbs_pa) luo_flb_global.incoming.header_ser = kho_ser_payload(fhdr, luo_flb_header_ser); - luo_flb_global.incoming.ser = (void *)fhdr + fhdr->size; + luo_flb_global.incoming.fhdr = (void *)fhdr + fhdr->size; luo_flb_global.incoming.active = true; return 0; @@ -626,10 +635,16 @@ void luo_flb_serialize(void) long count = refcount_read(&private->outgoing.count); if (count > 0) { - strscpy(fh->ser[i].name, gflb->compatible, - sizeof(fh->ser[i].name)); - fh->ser[i].data = private->outgoing.data; - fh->ser[i].count = count; + DECLARE_KHO_SER_HDR(luo_flb_ser, *fhdr) = + (void *)fh->fhdr + i * kho_ser_size(luo_flb_ser); + struct luo_flb_ser *ser; + + kho_ser_init(fhdr, luo_flb_ser); + ser = kho_ser_payload(fhdr, luo_flb_ser); + strscpy(ser->name, gflb->compatible, + sizeof(ser->name)); + ser->data = private->outgoing.data; + ser->count = count; i++; } } -- 2.56.0.506.g506a7eabc5-goog