Skip to content

Commit 3a86156

Browse files
mincrmatt12axboe
authored andcommitted
bcache: fix variable length array abuse in btree_iter
btree_iter is used in two ways: either allocated on the stack with a fixed size MAX_BSETS, or from a mempool with a dynamic size based on the specific cache set. Previously, the struct had a fixed-length array of size MAX_BSETS which was indexed out-of-bounds for the dynamically-sized iterators, which causes UBSAN to complain. This patch uses the same approach as in bcachefs's sort_iter and splits the iterator into a btree_iter with a flexible array member and a btree_iter_stack which embeds a btree_iter as well as a fixed-length data array. Cc: stable@vger.kernel.org Closes: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2039368 Signed-off-by: Matthew Mirvish <matthew@mm12.xyz> Signed-off-by: Coly Li <colyli@suse.de> Link: https://lore.kernel.org/r/20240509011117.2697-3-colyli@suse.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 2abd9a1 commit 3a86156

6 files changed

Lines changed: 70 additions & 59 deletions

File tree

drivers/md/bcache/bset.c

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void bch_dump_bucket(struct btree_keys *b)
5454
int __bch_count_data(struct btree_keys *b)
5555
{
5656
unsigned int ret = 0;
57-
struct btree_iter iter;
57+
struct btree_iter_stack iter;
5858
struct bkey *k;
5959

6060
if (b->ops->is_extents)
@@ -67,7 +67,7 @@ void __bch_check_keys(struct btree_keys *b, const char *fmt, ...)
6767
{
6868
va_list args;
6969
struct bkey *k, *p = NULL;
70-
struct btree_iter iter;
70+
struct btree_iter_stack iter;
7171
const char *err;
7272

7373
for_each_key(b, k, &iter) {
@@ -879,7 +879,7 @@ unsigned int bch_btree_insert_key(struct btree_keys *b, struct bkey *k,
879879
unsigned int status = BTREE_INSERT_STATUS_NO_INSERT;
880880
struct bset *i = bset_tree_last(b)->data;
881881
struct bkey *m, *prev = NULL;
882-
struct btree_iter iter;
882+
struct btree_iter_stack iter;
883883
struct bkey preceding_key_on_stack = ZERO_KEY;
884884
struct bkey *preceding_key_p = &preceding_key_on_stack;
885885

@@ -895,9 +895,9 @@ unsigned int bch_btree_insert_key(struct btree_keys *b, struct bkey *k,
895895
else
896896
preceding_key(k, &preceding_key_p);
897897

898-
m = bch_btree_iter_init(b, &iter, preceding_key_p);
898+
m = bch_btree_iter_stack_init(b, &iter, preceding_key_p);
899899

900-
if (b->ops->insert_fixup(b, k, &iter, replace_key))
900+
if (b->ops->insert_fixup(b, k, &iter.iter, replace_key))
901901
return status;
902902

903903
status = BTREE_INSERT_STATUS_INSERT;
@@ -1100,33 +1100,33 @@ void bch_btree_iter_push(struct btree_iter *iter, struct bkey *k,
11001100
btree_iter_cmp));
11011101
}
11021102

1103-
static struct bkey *__bch_btree_iter_init(struct btree_keys *b,
1104-
struct btree_iter *iter,
1105-
struct bkey *search,
1106-
struct bset_tree *start)
1103+
static struct bkey *__bch_btree_iter_stack_init(struct btree_keys *b,
1104+
struct btree_iter_stack *iter,
1105+
struct bkey *search,
1106+
struct bset_tree *start)
11071107
{
11081108
struct bkey *ret = NULL;
11091109

1110-
iter->size = ARRAY_SIZE(iter->data);
1111-
iter->used = 0;
1110+
iter->iter.size = ARRAY_SIZE(iter->stack_data);
1111+
iter->iter.used = 0;
11121112

11131113
#ifdef CONFIG_BCACHE_DEBUG
1114-
iter->b = b;
1114+
iter->iter.b = b;
11151115
#endif
11161116

11171117
for (; start <= bset_tree_last(b); start++) {
11181118
ret = bch_bset_search(b, start, search);
1119-
bch_btree_iter_push(iter, ret, bset_bkey_last(start->data));
1119+
bch_btree_iter_push(&iter->iter, ret, bset_bkey_last(start->data));
11201120
}
11211121

11221122
return ret;
11231123
}
11241124

1125-
struct bkey *bch_btree_iter_init(struct btree_keys *b,
1126-
struct btree_iter *iter,
1125+
struct bkey *bch_btree_iter_stack_init(struct btree_keys *b,
1126+
struct btree_iter_stack *iter,
11271127
struct bkey *search)
11281128
{
1129-
return __bch_btree_iter_init(b, iter, search, b->set);
1129+
return __bch_btree_iter_stack_init(b, iter, search, b->set);
11301130
}
11311131

11321132
static inline struct bkey *__bch_btree_iter_next(struct btree_iter *iter,
@@ -1293,10 +1293,10 @@ void bch_btree_sort_partial(struct btree_keys *b, unsigned int start,
12931293
struct bset_sort_state *state)
12941294
{
12951295
size_t order = b->page_order, keys = 0;
1296-
struct btree_iter iter;
1296+
struct btree_iter_stack iter;
12971297
int oldsize = bch_count_data(b);
12981298

1299-
__bch_btree_iter_init(b, &iter, NULL, &b->set[start]);
1299+
__bch_btree_iter_stack_init(b, &iter, NULL, &b->set[start]);
13001300

13011301
if (start) {
13021302
unsigned int i;
@@ -1307,7 +1307,7 @@ void bch_btree_sort_partial(struct btree_keys *b, unsigned int start,
13071307
order = get_order(__set_bytes(b->set->data, keys));
13081308
}
13091309

1310-
__btree_sort(b, &iter, start, order, false, state);
1310+
__btree_sort(b, &iter.iter, start, order, false, state);
13111311

13121312
EBUG_ON(oldsize >= 0 && bch_count_data(b) != oldsize);
13131313
}
@@ -1323,11 +1323,11 @@ void bch_btree_sort_into(struct btree_keys *b, struct btree_keys *new,
13231323
struct bset_sort_state *state)
13241324
{
13251325
uint64_t start_time = local_clock();
1326-
struct btree_iter iter;
1326+
struct btree_iter_stack iter;
13271327

1328-
bch_btree_iter_init(b, &iter, NULL);
1328+
bch_btree_iter_stack_init(b, &iter, NULL);
13291329

1330-
btree_mergesort(b, new->set->data, &iter, false, true);
1330+
btree_mergesort(b, new->set->data, &iter.iter, false, true);
13311331

13321332
bch_time_stats_update(&state->time, start_time);
13331333

drivers/md/bcache/bset.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,14 @@ struct btree_iter {
321321
#endif
322322
struct btree_iter_set {
323323
struct bkey *k, *end;
324-
} data[MAX_BSETS];
324+
} data[];
325+
};
326+
327+
/* Fixed-size btree_iter that can be allocated on the stack */
328+
329+
struct btree_iter_stack {
330+
struct btree_iter iter;
331+
struct btree_iter_set stack_data[MAX_BSETS];
325332
};
326333

327334
typedef bool (*ptr_filter_fn)(struct btree_keys *b, const struct bkey *k);
@@ -333,9 +340,9 @@ struct bkey *bch_btree_iter_next_filter(struct btree_iter *iter,
333340

334341
void bch_btree_iter_push(struct btree_iter *iter, struct bkey *k,
335342
struct bkey *end);
336-
struct bkey *bch_btree_iter_init(struct btree_keys *b,
337-
struct btree_iter *iter,
338-
struct bkey *search);
343+
struct bkey *bch_btree_iter_stack_init(struct btree_keys *b,
344+
struct btree_iter_stack *iter,
345+
struct bkey *search);
339346

340347
struct bkey *__bch_bset_search(struct btree_keys *b, struct bset_tree *t,
341348
const struct bkey *search);
@@ -350,13 +357,14 @@ static inline struct bkey *bch_bset_search(struct btree_keys *b,
350357
return search ? __bch_bset_search(b, t, search) : t->data->start;
351358
}
352359

353-
#define for_each_key_filter(b, k, iter, filter) \
354-
for (bch_btree_iter_init((b), (iter), NULL); \
355-
((k) = bch_btree_iter_next_filter((iter), (b), filter));)
360+
#define for_each_key_filter(b, k, stack_iter, filter) \
361+
for (bch_btree_iter_stack_init((b), (stack_iter), NULL); \
362+
((k) = bch_btree_iter_next_filter(&((stack_iter)->iter), (b), \
363+
filter));)
356364

357-
#define for_each_key(b, k, iter) \
358-
for (bch_btree_iter_init((b), (iter), NULL); \
359-
((k) = bch_btree_iter_next(iter));)
365+
#define for_each_key(b, k, stack_iter) \
366+
for (bch_btree_iter_stack_init((b), (stack_iter), NULL); \
367+
((k) = bch_btree_iter_next(&((stack_iter)->iter)));)
360368

361369
/* Sorting */
362370

drivers/md/bcache/btree.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,7 @@ static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc)
13091309
uint8_t stale = 0;
13101310
unsigned int keys = 0, good_keys = 0;
13111311
struct bkey *k;
1312-
struct btree_iter iter;
1312+
struct btree_iter_stack iter;
13131313
struct bset_tree *t;
13141314

13151315
gc->nodes++;
@@ -1570,7 +1570,7 @@ static int btree_gc_rewrite_node(struct btree *b, struct btree_op *op,
15701570
static unsigned int btree_gc_count_keys(struct btree *b)
15711571
{
15721572
struct bkey *k;
1573-
struct btree_iter iter;
1573+
struct btree_iter_stack iter;
15741574
unsigned int ret = 0;
15751575

15761576
for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
@@ -1611,17 +1611,18 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
16111611
int ret = 0;
16121612
bool should_rewrite;
16131613
struct bkey *k;
1614-
struct btree_iter iter;
1614+
struct btree_iter_stack iter;
16151615
struct gc_merge_info r[GC_MERGE_NODES];
16161616
struct gc_merge_info *i, *last = r + ARRAY_SIZE(r) - 1;
16171617

1618-
bch_btree_iter_init(&b->keys, &iter, &b->c->gc_done);
1618+
bch_btree_iter_stack_init(&b->keys, &iter, &b->c->gc_done);
16191619

16201620
for (i = r; i < r + ARRAY_SIZE(r); i++)
16211621
i->b = ERR_PTR(-EINTR);
16221622

16231623
while (1) {
1624-
k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
1624+
k = bch_btree_iter_next_filter(&iter.iter, &b->keys,
1625+
bch_ptr_bad);
16251626
if (k) {
16261627
r->b = bch_btree_node_get(b->c, op, k, b->level - 1,
16271628
true, b);
@@ -1911,18 +1912,18 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
19111912
{
19121913
int ret = 0;
19131914
struct bkey *k, *p = NULL;
1914-
struct btree_iter iter;
1915+
struct btree_iter_stack iter;
19151916

19161917
for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid)
19171918
bch_initial_mark_key(b->c, b->level, k);
19181919

19191920
bch_initial_mark_key(b->c, b->level + 1, &b->key);
19201921

19211922
if (b->level) {
1922-
bch_btree_iter_init(&b->keys, &iter, NULL);
1923+
bch_btree_iter_stack_init(&b->keys, &iter, NULL);
19231924

19241925
do {
1925-
k = bch_btree_iter_next_filter(&iter, &b->keys,
1926+
k = bch_btree_iter_next_filter(&iter.iter, &b->keys,
19261927
bch_ptr_bad);
19271928
if (k) {
19281929
btree_node_prefetch(b, k);
@@ -1950,7 +1951,7 @@ static int bch_btree_check_thread(void *arg)
19501951
struct btree_check_info *info = arg;
19511952
struct btree_check_state *check_state = info->state;
19521953
struct cache_set *c = check_state->c;
1953-
struct btree_iter iter;
1954+
struct btree_iter_stack iter;
19541955
struct bkey *k, *p;
19551956
int cur_idx, prev_idx, skip_nr;
19561957

@@ -1959,8 +1960,8 @@ static int bch_btree_check_thread(void *arg)
19591960
ret = 0;
19601961

19611962
/* root node keys are checked before thread created */
1962-
bch_btree_iter_init(&c->root->keys, &iter, NULL);
1963-
k = bch_btree_iter_next_filter(&iter, &c->root->keys, bch_ptr_bad);
1963+
bch_btree_iter_stack_init(&c->root->keys, &iter, NULL);
1964+
k = bch_btree_iter_next_filter(&iter.iter, &c->root->keys, bch_ptr_bad);
19641965
BUG_ON(!k);
19651966

19661967
p = k;
@@ -1978,7 +1979,7 @@ static int bch_btree_check_thread(void *arg)
19781979
skip_nr = cur_idx - prev_idx;
19791980

19801981
while (skip_nr) {
1981-
k = bch_btree_iter_next_filter(&iter,
1982+
k = bch_btree_iter_next_filter(&iter.iter,
19821983
&c->root->keys,
19831984
bch_ptr_bad);
19841985
if (k)
@@ -2051,7 +2052,7 @@ int bch_btree_check(struct cache_set *c)
20512052
int ret = 0;
20522053
int i;
20532054
struct bkey *k = NULL;
2054-
struct btree_iter iter;
2055+
struct btree_iter_stack iter;
20552056
struct btree_check_state check_state;
20562057

20572058
/* check and mark root node keys */
@@ -2547,11 +2548,11 @@ static int bch_btree_map_nodes_recurse(struct btree *b, struct btree_op *op,
25472548

25482549
if (b->level) {
25492550
struct bkey *k;
2550-
struct btree_iter iter;
2551+
struct btree_iter_stack iter;
25512552

2552-
bch_btree_iter_init(&b->keys, &iter, from);
2553+
bch_btree_iter_stack_init(&b->keys, &iter, from);
25532554

2554-
while ((k = bch_btree_iter_next_filter(&iter, &b->keys,
2555+
while ((k = bch_btree_iter_next_filter(&iter.iter, &b->keys,
25552556
bch_ptr_bad))) {
25562557
ret = bcache_btree(map_nodes_recurse, k, b,
25572558
op, from, fn, flags);
@@ -2580,11 +2581,12 @@ int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
25802581
{
25812582
int ret = MAP_CONTINUE;
25822583
struct bkey *k;
2583-
struct btree_iter iter;
2584+
struct btree_iter_stack iter;
25842585

2585-
bch_btree_iter_init(&b->keys, &iter, from);
2586+
bch_btree_iter_stack_init(&b->keys, &iter, from);
25862587

2587-
while ((k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad))) {
2588+
while ((k = bch_btree_iter_next_filter(&iter.iter, &b->keys,
2589+
bch_ptr_bad))) {
25882590
ret = !b->level
25892591
? fn(op, b, k)
25902592
: bcache_btree(map_keys_recurse, k,

drivers/md/bcache/super.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,8 +1914,9 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
19141914
INIT_LIST_HEAD(&c->btree_cache_freed);
19151915
INIT_LIST_HEAD(&c->data_buckets);
19161916

1917-
iter_size = ((meta_bucket_pages(sb) * PAGE_SECTORS) / sb->block_size + 1) *
1918-
sizeof(struct btree_iter_set);
1917+
iter_size = sizeof(struct btree_iter) +
1918+
((meta_bucket_pages(sb) * PAGE_SECTORS) / sb->block_size) *
1919+
sizeof(struct btree_iter_set);
19191920

19201921
c->devices = kcalloc(c->nr_uuids, sizeof(void *), GFP_KERNEL);
19211922
if (!c->devices)

drivers/md/bcache/sysfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ static unsigned int bch_root_usage(struct cache_set *c)
660660
unsigned int bytes = 0;
661661
struct bkey *k;
662662
struct btree *b;
663-
struct btree_iter iter;
663+
struct btree_iter_stack iter;
664664

665665
goto lock_root;
666666

drivers/md/bcache/writeback.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -908,15 +908,15 @@ static int bch_dirty_init_thread(void *arg)
908908
struct dirty_init_thrd_info *info = arg;
909909
struct bch_dirty_init_state *state = info->state;
910910
struct cache_set *c = state->c;
911-
struct btree_iter iter;
911+
struct btree_iter_stack iter;
912912
struct bkey *k, *p;
913913
int cur_idx, prev_idx, skip_nr;
914914

915915
k = p = NULL;
916916
prev_idx = 0;
917917

918-
bch_btree_iter_init(&c->root->keys, &iter, NULL);
919-
k = bch_btree_iter_next_filter(&iter, &c->root->keys, bch_ptr_bad);
918+
bch_btree_iter_stack_init(&c->root->keys, &iter, NULL);
919+
k = bch_btree_iter_next_filter(&iter.iter, &c->root->keys, bch_ptr_bad);
920920
BUG_ON(!k);
921921

922922
p = k;
@@ -930,7 +930,7 @@ static int bch_dirty_init_thread(void *arg)
930930
skip_nr = cur_idx - prev_idx;
931931

932932
while (skip_nr) {
933-
k = bch_btree_iter_next_filter(&iter,
933+
k = bch_btree_iter_next_filter(&iter.iter,
934934
&c->root->keys,
935935
bch_ptr_bad);
936936
if (k)
@@ -979,7 +979,7 @@ void bch_sectors_dirty_init(struct bcache_device *d)
979979
int i;
980980
struct btree *b = NULL;
981981
struct bkey *k = NULL;
982-
struct btree_iter iter;
982+
struct btree_iter_stack iter;
983983
struct sectors_dirty_init op;
984984
struct cache_set *c = d->c;
985985
struct bch_dirty_init_state state;

0 commit comments

Comments
 (0)