* [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts
2026-04-23 17:40 [PATCH 0/2] liveupdate: FLB refcounting improvements David Matlack
@ 2026-04-23 17:40 ` David Matlack
2026-04-23 18:11 ` Pasha Tatashin
2026-04-23 19:58 ` Samiullah Khawaja
2026-04-23 17:40 ` [PATCH 2/2] liveupdate: Reference count incoming FLB data David Matlack
2026-04-23 18:13 ` [PATCH 0/2] liveupdate: FLB refcounting improvements Pasha Tatashin
2 siblings, 2 replies; 11+ messages in thread
From: David Matlack @ 2026-04-23 17:40 UTC (permalink / raw)
To: linux-kernel
Cc: Andrew Morton, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
Samiullah Khawaja, David Matlack
Use refcount_t instead of a raw integer to keep track of references on
incoming and outgoing FLBs. Using refcount_t provides protection from
overflow, underflow, and other issues.
Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
Signed-off-by: David Matlack <dmatlack@google.com>
---
include/linux/liveupdate.h | 3 ++-
kernel/liveupdate/luo_flb.c | 22 ++++++++++------------
2 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 30c5a39ff9e9..8d3bbc35c828 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -12,6 +12,7 @@
#include <linux/kho/abi/luo.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/refcount.h>
#include <linux/rwsem.h>
#include <linux/types.h>
#include <uapi/linux/liveupdate.h>
@@ -175,7 +176,7 @@ struct liveupdate_flb_ops {
* @retrieved: True once the FLB's retrieve() callback has run.
*/
struct luo_flb_private_state {
- long count;
+ refcount_t count;
u64 data;
void *obj;
struct mutex lock;
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 00f5494812c4..59c5f31ab767 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -111,7 +111,7 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
struct luo_flb_private *private = luo_flb_get_private(flb);
scoped_guard(mutex, &private->outgoing.lock) {
- if (!private->outgoing.count) {
+ if (!refcount_read(&private->outgoing.count)) {
struct liveupdate_flb_op_args args = {0};
int err;
@@ -126,8 +126,10 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
}
private->outgoing.data = args.data;
private->outgoing.obj = args.obj;
+ refcount_set(&private->outgoing.count, 1);
+ } else {
+ refcount_inc(&private->outgoing.count);
}
- private->outgoing.count++;
}
return 0;
@@ -138,8 +140,7 @@ static void luo_flb_file_unpreserve_one(struct liveupdate_flb *flb)
struct luo_flb_private *private = luo_flb_get_private(flb);
scoped_guard(mutex, &private->outgoing.lock) {
- private->outgoing.count--;
- if (!private->outgoing.count) {
+ if (refcount_dec_and_test(&private->outgoing.count)) {
struct liveupdate_flb_op_args args = {0};
args.flb = flb;
@@ -178,7 +179,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
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;
- private->incoming.count = fh->ser[i].count;
+ refcount_set(&private->incoming.count, fh->ser[i].count);
found = true;
break;
}
@@ -208,12 +209,8 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
{
struct luo_flb_private *private = luo_flb_get_private(flb);
- u64 count;
- scoped_guard(mutex, &private->incoming.lock)
- count = --private->incoming.count;
-
- if (!count) {
+ if (refcount_dec_and_test(&private->incoming.count)) {
struct liveupdate_flb_op_args args = {0};
if (!private->incoming.retrieved) {
@@ -652,12 +649,13 @@ void luo_flb_serialize(void)
guard(rwsem_read)(&luo_register_rwlock);
list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) {
struct luo_flb_private *private = luo_flb_get_private(gflb);
+ long count = refcount_read(&private->outgoing.count);
- if (private->outgoing.count > 0) {
+ 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 = private->outgoing.count;
+ fh->ser[i].count = count;
i++;
}
}
--
2.54.0.rc2.544.gc7ae2d5bb8-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts
2026-04-23 17:40 ` [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts David Matlack
@ 2026-04-23 18:11 ` Pasha Tatashin
2026-04-23 18:49 ` David Matlack
2026-04-23 19:58 ` Samiullah Khawaja
1 sibling, 1 reply; 11+ messages in thread
From: Pasha Tatashin @ 2026-04-23 18:11 UTC (permalink / raw)
To: David Matlack
Cc: linux-kernel, Andrew Morton, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Samiullah Khawaja
On 04-23 17:40, David Matlack wrote:
> Use refcount_t instead of a raw integer to keep track of references on
> incoming and outgoing FLBs. Using refcount_t provides protection from
> overflow, underflow, and other issues.
>
> Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> include/linux/liveupdate.h | 3 ++-
> kernel/liveupdate/luo_flb.c | 22 ++++++++++------------
> 2 files changed, 12 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
> index 30c5a39ff9e9..8d3bbc35c828 100644
> --- a/include/linux/liveupdate.h
> +++ b/include/linux/liveupdate.h
> @@ -12,6 +12,7 @@
> #include <linux/kho/abi/luo.h>
> #include <linux/list.h>
> #include <linux/mutex.h>
> +#include <linux/refcount.h>
> #include <linux/rwsem.h>
> #include <linux/types.h>
> #include <uapi/linux/liveupdate.h>
> @@ -175,7 +176,7 @@ struct liveupdate_flb_ops {
> * @retrieved: True once the FLB's retrieve() callback has run.
> */
> struct luo_flb_private_state {
> - long count;
> + refcount_t count;
> u64 data;
> void *obj;
> struct mutex lock;
> diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
> index 00f5494812c4..59c5f31ab767 100644
> --- a/kernel/liveupdate/luo_flb.c
> +++ b/kernel/liveupdate/luo_flb.c
> @@ -111,7 +111,7 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
> struct luo_flb_private *private = luo_flb_get_private(flb);
>
> scoped_guard(mutex, &private->outgoing.lock) {
> - if (!private->outgoing.count) {
> + if (!refcount_read(&private->outgoing.count)) {
> struct liveupdate_flb_op_args args = {0};
> int err;
>
> @@ -126,8 +126,10 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
> }
> private->outgoing.data = args.data;
> private->outgoing.obj = args.obj;
> + refcount_set(&private->outgoing.count, 1);
> + } else {
> + refcount_inc(&private->outgoing.count);
> }
> - private->outgoing.count++;
It should be: refcount_inc(&private->outgoing.count); for both
cases, as it was before.
Additionally, please add refcount_set(&private->outgoing.count, 0) to
luo_flb_get_private, where the rest of the private fields are
initialized.
In general, I prefer to avoid refcount_set() because it breaks
continuity and makes debugging hard. It should only be used only during
initialization, so moving it to where the other fields are initialized
is the correct approach.
> }
>
> return 0;
> @@ -138,8 +140,7 @@ static void luo_flb_file_unpreserve_one(struct liveupdate_flb *flb)
> struct luo_flb_private *private = luo_flb_get_private(flb);
>
> scoped_guard(mutex, &private->outgoing.lock) {
> - private->outgoing.count--;
> - if (!private->outgoing.count) {
> + if (refcount_dec_and_test(&private->outgoing.count)) {
> struct liveupdate_flb_op_args args = {0};
>
> args.flb = flb;
> @@ -178,7 +179,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
> 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;
> - private->incoming.count = fh->ser[i].count;
> + refcount_set(&private->incoming.count, fh->ser[i].count);
> found = true;
> break;
> }
> @@ -208,12 +209,8 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
> static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
> {
> struct luo_flb_private *private = luo_flb_get_private(flb);
> - u64 count;
>
> - scoped_guard(mutex, &private->incoming.lock)
> - count = --private->incoming.count;
> -
> - if (!count) {
> + if (refcount_dec_and_test(&private->incoming.count)) {
> struct liveupdate_flb_op_args args = {0};
>
> if (!private->incoming.retrieved) {
> @@ -652,12 +649,13 @@ void luo_flb_serialize(void)
> guard(rwsem_read)(&luo_register_rwlock);
> list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) {
> struct luo_flb_private *private = luo_flb_get_private(gflb);
> + long count = refcount_read(&private->outgoing.count);
>
> - if (private->outgoing.count > 0) {
> + 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 = private->outgoing.count;
> + fh->ser[i].count = count;
> i++;
> }
> }
> --
> 2.54.0.rc2.544.gc7ae2d5bb8-goog
>
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts
2026-04-23 18:11 ` Pasha Tatashin
@ 2026-04-23 18:49 ` David Matlack
2026-04-23 19:40 ` Pasha Tatashin
0 siblings, 1 reply; 11+ messages in thread
From: David Matlack @ 2026-04-23 18:49 UTC (permalink / raw)
To: Pasha Tatashin
Cc: linux-kernel, Andrew Morton, Mike Rapoport, Pratyush Yadav,
Samiullah Khawaja
On Thu, Apr 23, 2026 at 11:11 AM Pasha Tatashin
<pasha.tatashin@soleen.com> wrote:
> On 04-23 17:40, David Matlack wrote:
> > @@ -126,8 +126,10 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
> > }
> > private->outgoing.data = args.data;
> > private->outgoing.obj = args.obj;
> > + refcount_set(&private->outgoing.count, 1);
> > + } else {
> > + refcount_inc(&private->outgoing.count);
> > }
> > - private->outgoing.count++;
>
> It should be: refcount_inc(&private->outgoing.count); for both
> cases, as it was before.
Calling refcount_inc() when the refcount is 0 triggers the
REFCOUNT_ADD_UAF warning.
> Additionally, please add refcount_set(&private->outgoing.count, 0) to
> luo_flb_get_private, where the rest of the private fields are
> initialized.
Will do.
> In general, I prefer to avoid refcount_set() because it breaks
> continuity and makes debugging hard. It should only be used only during
> initialization, so moving it to where the other fields are initialized
> is the correct approach.
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts
2026-04-23 18:49 ` David Matlack
@ 2026-04-23 19:40 ` Pasha Tatashin
0 siblings, 0 replies; 11+ messages in thread
From: Pasha Tatashin @ 2026-04-23 19:40 UTC (permalink / raw)
To: David Matlack
Cc: Pasha Tatashin, linux-kernel, Andrew Morton, Mike Rapoport,
Pratyush Yadav, Samiullah Khawaja
On 04-23 11:49, David Matlack wrote:
> On Thu, Apr 23, 2026 at 11:11 AM Pasha Tatashin
> <pasha.tatashin@soleen.com> wrote:
> > On 04-23 17:40, David Matlack wrote:
>
> > > @@ -126,8 +126,10 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
> > > }
> > > private->outgoing.data = args.data;
> > > private->outgoing.obj = args.obj;
> > > + refcount_set(&private->outgoing.count, 1);
> > > + } else {
> > > + refcount_inc(&private->outgoing.count);
> > > }
> > > - private->outgoing.count++;
> >
> > It should be: refcount_inc(&private->outgoing.count); for both
> > cases, as it was before.
>
> Calling refcount_inc() when the refcount is 0 triggers the
> REFCOUNT_ADD_UAF warning.
Oh you are right, sigh, in this case what you have is OK.
>
> > Additionally, please add refcount_set(&private->outgoing.count, 0) to
> > luo_flb_get_private, where the rest of the private fields are
> > initialized.
>
> Will do.
No need to do this...
>
> > In general, I prefer to avoid refcount_set() because it breaks
> > continuity and makes debugging hard. It should only be used only during
> > initialization, so moving it to where the other fields are initialized
> > is the correct approach.
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts
2026-04-23 17:40 ` [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts David Matlack
2026-04-23 18:11 ` Pasha Tatashin
@ 2026-04-23 19:58 ` Samiullah Khawaja
1 sibling, 0 replies; 11+ messages in thread
From: Samiullah Khawaja @ 2026-04-23 19:58 UTC (permalink / raw)
To: David Matlack
Cc: linux-kernel, Andrew Morton, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav
On Thu, Apr 23, 2026 at 05:40:28PM +0000, David Matlack wrote:
>Use refcount_t instead of a raw integer to keep track of references on
>incoming and outgoing FLBs. Using refcount_t provides protection from
>overflow, underflow, and other issues.
>
>Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
>Signed-off-by: David Matlack <dmatlack@google.com>
>---
> include/linux/liveupdate.h | 3 ++-
> kernel/liveupdate/luo_flb.c | 22 ++++++++++------------
> 2 files changed, 12 insertions(+), 13 deletions(-)
>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] liveupdate: Reference count incoming FLB data
2026-04-23 17:40 [PATCH 0/2] liveupdate: FLB refcounting improvements David Matlack
2026-04-23 17:40 ` [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts David Matlack
@ 2026-04-23 17:40 ` David Matlack
2026-04-23 18:21 ` Pasha Tatashin
2026-04-23 19:46 ` Samiullah Khawaja
2026-04-23 18:13 ` [PATCH 0/2] liveupdate: FLB refcounting improvements Pasha Tatashin
2 siblings, 2 replies; 11+ messages in thread
From: David Matlack @ 2026-04-23 17:40 UTC (permalink / raw)
To: linux-kernel
Cc: Andrew Morton, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
Samiullah Khawaja, David Matlack
Increment the incoming FLB refcount in liveupdate_flb_get_incoming() so
that the FLB structure cannot be freed while the caller is actively using
it. Add an additional liveupdate_flb_put_incoming() function so the
caller can explicitly indicate when it is done using the FLB data.
During a Live Update, a subsystem might need to hold onto the incoming
File-Lifecycle-Bound (FLB) data for an extended period, such as during
device enumeration. Incrementing the reference count guarantees that the
data remains valid and accessible until the subsystem releases it,
preventing future use-after-free bugs.
Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
Signed-off-by: David Matlack <dmatlack@google.com>
---
include/linux/liveupdate.h | 6 ++++++
kernel/liveupdate/luo_flb.c | 32 +++++++++++++++++---------------
lib/tests/liveupdate.c | 3 +++
3 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 8d3bbc35c828..88722e5caf02 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -240,6 +240,8 @@ void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
struct liveupdate_flb *flb);
int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp);
+void liveupdate_flb_put_incoming(struct liveupdate_flb *flb);
+
int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
#else /* CONFIG_LIVEUPDATE */
@@ -280,6 +282,10 @@ static inline int liveupdate_flb_get_incoming(struct liveupdate_flb *flb,
return -EOPNOTSUPP;
}
+static inline void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
+{
+}
+
static inline int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb,
void **objp)
{
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 59c5f31ab767..8f5c5dd01cd0 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -165,7 +165,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
bool found = false;
int err;
- guard(mutex)(&private->incoming.lock);
+ lockdep_assert_held(&private->incoming.lock);
if (private->incoming.finished)
return -ENODATA;
@@ -206,12 +206,14 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
return 0;
}
-static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
+void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
{
struct luo_flb_private *private = luo_flb_get_private(flb);
+ struct liveupdate_flb_op_args args = {0};
- if (refcount_dec_and_test(&private->incoming.count)) {
- struct liveupdate_flb_op_args args = {0};
+ scoped_guard(mutex, &private->incoming.lock) {
+ if (!refcount_dec_and_test(&private->incoming.count))
+ return;
if (!private->incoming.retrieved) {
int err = luo_flb_retrieve_one(flb);
@@ -220,16 +222,14 @@ static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
return;
}
- scoped_guard(mutex, &private->incoming.lock) {
- args.flb = flb;
- args.obj = private->incoming.obj;
- flb->ops->finish(&args);
+ args.flb = flb;
+ args.obj = private->incoming.obj;
+ flb->ops->finish(&args);
- private->incoming.data = 0;
- private->incoming.obj = NULL;
- private->incoming.finished = true;
- module_put(flb->ops->owner);
- }
+ private->incoming.data = 0;
+ private->incoming.obj = NULL;
+ private->incoming.finished = true;
+ module_put(flb->ops->owner);
}
}
@@ -312,7 +312,7 @@ void luo_flb_file_finish(struct liveupdate_file_handler *fh)
guard(rwsem_read)(&luo_register_rwlock);
list_for_each_entry_reverse(iter, flb_list, list)
- luo_flb_file_finish_one(iter->flb);
+ liveupdate_flb_put_incoming(iter->flb);
}
static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
@@ -509,6 +509,8 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
if (!liveupdate_enabled())
return -EOPNOTSUPP;
+ guard(mutex)(&private->incoming.lock);
+
if (!private->incoming.obj) {
int err = luo_flb_retrieve_one(flb);
@@ -516,7 +518,7 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
return err;
}
- guard(mutex)(&private->incoming.lock);
+ refcount_inc(&private->incoming.count);
*objp = private->incoming.obj;
return 0;
diff --git a/lib/tests/liveupdate.c b/lib/tests/liveupdate.c
index e4b0ecbee32f..4c08a7c6fb78 100644
--- a/lib/tests/liveupdate.c
+++ b/lib/tests/liveupdate.c
@@ -105,6 +105,9 @@ static void liveupdate_test_init(void)
pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
flb->compatible, ERR_PTR(err));
}
+
+ if (!err)
+ liveupdate_flb_put_incoming(flb);
}
initialized = true;
}
--
2.54.0.rc2.544.gc7ae2d5bb8-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 2/2] liveupdate: Reference count incoming FLB data
2026-04-23 17:40 ` [PATCH 2/2] liveupdate: Reference count incoming FLB data David Matlack
@ 2026-04-23 18:21 ` Pasha Tatashin
2026-04-23 19:46 ` Samiullah Khawaja
1 sibling, 0 replies; 11+ messages in thread
From: Pasha Tatashin @ 2026-04-23 18:21 UTC (permalink / raw)
To: David Matlack
Cc: linux-kernel, Andrew Morton, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Samiullah Khawaja
On 04-23 17:40, David Matlack wrote:
> Increment the incoming FLB refcount in liveupdate_flb_get_incoming() so
> that the FLB structure cannot be freed while the caller is actively using
> it. Add an additional liveupdate_flb_put_incoming() function so the
> caller can explicitly indicate when it is done using the FLB data.
>
> During a Live Update, a subsystem might need to hold onto the incoming
> File-Lifecycle-Bound (FLB) data for an extended period, such as during
> device enumeration. Incrementing the reference count guarantees that the
> data remains valid and accessible until the subsystem releases it,
> preventing future use-after-free bugs.
>
> Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
> Signed-off-by: David Matlack <dmatlack@google.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Thanks!
Pasha
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 2/2] liveupdate: Reference count incoming FLB data
2026-04-23 17:40 ` [PATCH 2/2] liveupdate: Reference count incoming FLB data David Matlack
2026-04-23 18:21 ` Pasha Tatashin
@ 2026-04-23 19:46 ` Samiullah Khawaja
1 sibling, 0 replies; 11+ messages in thread
From: Samiullah Khawaja @ 2026-04-23 19:46 UTC (permalink / raw)
To: David Matlack
Cc: linux-kernel, Andrew Morton, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav
On Thu, Apr 23, 2026 at 05:40:29PM +0000, David Matlack wrote:
>Increment the incoming FLB refcount in liveupdate_flb_get_incoming() so
>that the FLB structure cannot be freed while the caller is actively using
>it. Add an additional liveupdate_flb_put_incoming() function so the
>caller can explicitly indicate when it is done using the FLB data.
>
>During a Live Update, a subsystem might need to hold onto the incoming
>File-Lifecycle-Bound (FLB) data for an extended period, such as during
>device enumeration. Incrementing the reference count guarantees that the
>data remains valid and accessible until the subsystem releases it,
>preventing future use-after-free bugs.
>
>Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
>Signed-off-by: David Matlack <dmatlack@google.com>
>---
> include/linux/liveupdate.h | 6 ++++++
> kernel/liveupdate/luo_flb.c | 32 +++++++++++++++++---------------
> lib/tests/liveupdate.c | 3 +++
> 3 files changed, 26 insertions(+), 15 deletions(-)
>
>diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
>index 8d3bbc35c828..88722e5caf02 100644
>--- a/include/linux/liveupdate.h
>+++ b/include/linux/liveupdate.h
>@@ -240,6 +240,8 @@ void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> struct liveupdate_flb *flb);
>
> int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp);
>+void liveupdate_flb_put_incoming(struct liveupdate_flb *flb);
>+
> int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
>
> #else /* CONFIG_LIVEUPDATE */
>@@ -280,6 +282,10 @@ static inline int liveupdate_flb_get_incoming(struct liveupdate_flb *flb,
> return -EOPNOTSUPP;
> }
>
>+static inline void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
>+{
>+}
>+
> static inline int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb,
> void **objp)
> {
>diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
>index 59c5f31ab767..8f5c5dd01cd0 100644
>--- a/kernel/liveupdate/luo_flb.c
>+++ b/kernel/liveupdate/luo_flb.c
>@@ -165,7 +165,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
> bool found = false;
> int err;
>
>- guard(mutex)(&private->incoming.lock);
>+ lockdep_assert_held(&private->incoming.lock);
>
> if (private->incoming.finished)
> return -ENODATA;
>@@ -206,12 +206,14 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
> return 0;
> }
>
>-static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
>+void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
> {
> struct luo_flb_private *private = luo_flb_get_private(flb);
>+ struct liveupdate_flb_op_args args = {0};
>
>- if (refcount_dec_and_test(&private->incoming.count)) {
>- struct liveupdate_flb_op_args args = {0};
>+ scoped_guard(mutex, &private->incoming.lock) {
>+ if (!refcount_dec_and_test(&private->incoming.count))
>+ return;
>
> if (!private->incoming.retrieved) {
> int err = luo_flb_retrieve_one(flb);
>@@ -220,16 +222,14 @@ static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
> return;
> }
>
>- scoped_guard(mutex, &private->incoming.lock) {
>- args.flb = flb;
>- args.obj = private->incoming.obj;
>- flb->ops->finish(&args);
>+ args.flb = flb;
>+ args.obj = private->incoming.obj;
>+ flb->ops->finish(&args);
>
>- private->incoming.data = 0;
>- private->incoming.obj = NULL;
>- private->incoming.finished = true;
>- module_put(flb->ops->owner);
>- }
>+ private->incoming.data = 0;
>+ private->incoming.obj = NULL;
>+ private->incoming.finished = true;
>+ module_put(flb->ops->owner);
> }
> }
>
>@@ -312,7 +312,7 @@ void luo_flb_file_finish(struct liveupdate_file_handler *fh)
>
> guard(rwsem_read)(&luo_register_rwlock);
> list_for_each_entry_reverse(iter, flb_list, list)
>- luo_flb_file_finish_one(iter->flb);
>+ liveupdate_flb_put_incoming(iter->flb);
> }
>
> static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
>@@ -509,6 +509,8 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
> if (!liveupdate_enabled())
> return -EOPNOTSUPP;
>
>+ guard(mutex)(&private->incoming.lock);
>+
> if (!private->incoming.obj) {
> int err = luo_flb_retrieve_one(flb);
>
>@@ -516,7 +518,7 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
> return err;
> }
>
>- guard(mutex)(&private->incoming.lock);
>+ refcount_inc(&private->incoming.count);
> *objp = private->incoming.obj;
>
> return 0;
>diff --git a/lib/tests/liveupdate.c b/lib/tests/liveupdate.c
>index e4b0ecbee32f..4c08a7c6fb78 100644
>--- a/lib/tests/liveupdate.c
>+++ b/lib/tests/liveupdate.c
>@@ -105,6 +105,9 @@ static void liveupdate_test_init(void)
> pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
> flb->compatible, ERR_PTR(err));
> }
>+
>+ if (!err)
>+ liveupdate_flb_put_incoming(flb);
> }
> initialized = true;
> }
>--
>2.54.0.rc2.544.gc7ae2d5bb8-goog
>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/2] liveupdate: FLB refcounting improvements
2026-04-23 17:40 [PATCH 0/2] liveupdate: FLB refcounting improvements David Matlack
2026-04-23 17:40 ` [PATCH 1/2] liveupdate: Use refcount_t for FLB reference counts David Matlack
2026-04-23 17:40 ` [PATCH 2/2] liveupdate: Reference count incoming FLB data David Matlack
@ 2026-04-23 18:13 ` Pasha Tatashin
2026-04-23 18:40 ` David Matlack
2 siblings, 1 reply; 11+ messages in thread
From: Pasha Tatashin @ 2026-04-23 18:13 UTC (permalink / raw)
To: David Matlack
Cc: linux-kernel, Andrew Morton, Mike Rapoport, Pasha Tatashin,
Pratyush Yadav, Samiullah Khawaja, kexec
Please include kexec@lists.infradead.org so the patches are tested by
Sashiko, and added to patchwork that we are using to maintaine live
update work.
Pasha
On 04-23 17:40, David Matlack wrote:
> This series can be found on GitHub:
>
> https://github.com/dmatlack/linux/tree/liveupdate/flb/refcount/v1
>
> This series has 2 patches to improve how FLB refcounting works in
> preparation for using FLB in the PCI core. The first patch converts the
> existing refcounting to use refcount_t, and the second patch allows
> users of the incoming FLB to hold references to the FLB to avoid it
> getting freed.
>
> Users of the outgoing FLB don't need to take an extra reference yet
> since it's always done in the context of a preserve/unpreserve file
> callback, which are already synchronized with outgoing FLB creation
> and destruction.
>
> This series has been tested against the existing Live Update selftests
> (liveupdate, luo_kexec_simple, and luo_multi_session) on an Intel EMR
> host.
>
>
> David Matlack (2):
> liveupdate: Use refcount_t for FLB reference counts
> liveupdate: Reference count incoming FLB data
>
> include/linux/liveupdate.h | 9 ++++++-
> kernel/liveupdate/luo_flb.c | 52 ++++++++++++++++++-------------------
> lib/tests/liveupdate.c | 3 +++
> 3 files changed, 37 insertions(+), 27 deletions(-)
>
>
> base-commit: 2a4c0c11c0193889446cdb6f1540cc2b9aff97dd
> --
> 2.54.0.rc2.544.gc7ae2d5bb8-goog
>
^ permalink raw reply [flat|nested] 11+ messages in thread