Skip to content

Commit d8e47bd

Browse files
dmatlackrppt
authored andcommitted
liveupdate: Reference count incoming FLB data
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: cab056f ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state") Signed-off-by: David Matlack <dmatlack@google.com> Reviewed-by: Samiullah Khawaja <skhawaja@google.com> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com> Link: https://lore.kernel.org/r/20260423174032.3140399-3-dmatlack@google.com Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
1 parent d2850ff commit d8e47bd

3 files changed

Lines changed: 26 additions & 15 deletions

File tree

include/linux/liveupdate.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
240240
struct liveupdate_flb *flb);
241241

242242
int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp);
243+
void liveupdate_flb_put_incoming(struct liveupdate_flb *flb);
244+
243245
int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
244246

245247
#else /* CONFIG_LIVEUPDATE */
@@ -280,6 +282,10 @@ static inline int liveupdate_flb_get_incoming(struct liveupdate_flb *flb,
280282
return -EOPNOTSUPP;
281283
}
282284

285+
static inline void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
286+
{
287+
}
288+
283289
static inline int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb,
284290
void **objp)
285291
{

kernel/liveupdate/luo_flb.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
165165
bool found = false;
166166
int err;
167167

168-
guard(mutex)(&private->incoming.lock);
168+
lockdep_assert_held(&private->incoming.lock);
169169

170170
if (private->incoming.finished)
171171
return -ENODATA;
@@ -206,12 +206,14 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
206206
return 0;
207207
}
208208

209-
static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
209+
void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
210210
{
211211
struct luo_flb_private *private = luo_flb_get_private(flb);
212+
struct liveupdate_flb_op_args args = {0};
212213

213-
if (refcount_dec_and_test(&private->incoming.count)) {
214-
struct liveupdate_flb_op_args args = {0};
214+
scoped_guard(mutex, &private->incoming.lock) {
215+
if (!refcount_dec_and_test(&private->incoming.count))
216+
return;
215217

216218
if (!private->incoming.retrieved) {
217219
int err = luo_flb_retrieve_one(flb);
@@ -220,16 +222,14 @@ static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
220222
return;
221223
}
222224

223-
scoped_guard(mutex, &private->incoming.lock) {
224-
args.flb = flb;
225-
args.obj = private->incoming.obj;
226-
flb->ops->finish(&args);
225+
args.flb = flb;
226+
args.obj = private->incoming.obj;
227+
flb->ops->finish(&args);
227228

228-
private->incoming.data = 0;
229-
private->incoming.obj = NULL;
230-
private->incoming.finished = true;
231-
module_put(flb->ops->owner);
232-
}
229+
private->incoming.data = 0;
230+
private->incoming.obj = NULL;
231+
private->incoming.finished = true;
232+
module_put(flb->ops->owner);
233233
}
234234
}
235235

@@ -312,7 +312,7 @@ void luo_flb_file_finish(struct liveupdate_file_handler *fh)
312312

313313
guard(rwsem_read)(&luo_register_rwlock);
314314
list_for_each_entry_reverse(iter, flb_list, list)
315-
luo_flb_file_finish_one(iter->flb);
315+
liveupdate_flb_put_incoming(iter->flb);
316316
}
317317

318318
static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
@@ -509,14 +509,16 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
509509
if (!liveupdate_enabled())
510510
return -EOPNOTSUPP;
511511

512+
guard(mutex)(&private->incoming.lock);
513+
512514
if (!private->incoming.obj) {
513515
int err = luo_flb_retrieve_one(flb);
514516

515517
if (err)
516518
return err;
517519
}
518520

519-
guard(mutex)(&private->incoming.lock);
521+
refcount_inc(&private->incoming.count);
520522
*objp = private->incoming.obj;
521523

522524
return 0;

lib/tests/liveupdate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ static void liveupdate_test_init(void)
105105
pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
106106
flb->compatible, ERR_PTR(err));
107107
}
108+
109+
if (!err)
110+
liveupdate_flb_put_incoming(flb);
108111
}
109112
initialized = true;
110113
}

0 commit comments

Comments
 (0)