Skip to content

Commit 8b5cb7e

Browse files
pskrgagjmberg-intel
authored andcommitted
mac80211: mesh: embedd mesh_paths and mpp_paths into ieee80211_if_mesh
Syzbot hit NULL deref in rhashtable_free_and_destroy(). The problem was in mesh_paths and mpp_paths being NULL. mesh_pathtbl_init() could fail in case of memory allocation failure, but nobody cared, since ieee80211_mesh_init_sdata() returns void. It led to leaving 2 pointers as NULL. Syzbot has found null deref on exit path, but it could happen anywhere else, because code assumes these pointers are valid. Since all ieee80211_*_setup_sdata functions are void and do not fail, let's embedd mesh_paths and mpp_paths into parent struct to avoid adding error handling on higher levels and follow the pattern of others setup_sdata functions Fixes: 60854fd ("mac80211: mesh: convert path table to rhashtable") Reported-and-tested-by: [email protected] Signed-off-by: Pavel Skripkin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Johannes Berg <[email protected]>
1 parent 68a18ad commit 8b5cb7e

File tree

3 files changed

+54
-81
lines changed

3 files changed

+54
-81
lines changed

net/mac80211/ieee80211_i.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,26 @@ struct mesh_csa_settings {
647647
struct cfg80211_csa_settings settings;
648648
};
649649

650+
/**
651+
* struct mesh_table
652+
*
653+
* @known_gates: list of known mesh gates and their mpaths by the station. The
654+
* gate's mpath may or may not be resolved and active.
655+
* @gates_lock: protects updates to known_gates
656+
* @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr
657+
* @walk_head: linked list containing all mesh_path objects
658+
* @walk_lock: lock protecting walk_head
659+
* @entries: number of entries in the table
660+
*/
661+
struct mesh_table {
662+
struct hlist_head known_gates;
663+
spinlock_t gates_lock;
664+
struct rhashtable rhead;
665+
struct hlist_head walk_head;
666+
spinlock_t walk_lock;
667+
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
668+
};
669+
650670
struct ieee80211_if_mesh {
651671
struct timer_list housekeeping_timer;
652672
struct timer_list mesh_path_timer;
@@ -721,8 +741,8 @@ struct ieee80211_if_mesh {
721741
/* offset from skb->data while building IE */
722742
int meshconf_offset;
723743

724-
struct mesh_table *mesh_paths;
725-
struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
744+
struct mesh_table mesh_paths;
745+
struct mesh_table mpp_paths; /* Store paths for MPP&MAP */
726746
int mesh_paths_generation;
727747
int mpp_paths_generation;
728748
};

net/mac80211/mesh.h

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -127,26 +127,6 @@ struct mesh_path {
127127
u32 path_change_count;
128128
};
129129

130-
/**
131-
* struct mesh_table
132-
*
133-
* @known_gates: list of known mesh gates and their mpaths by the station. The
134-
* gate's mpath may or may not be resolved and active.
135-
* @gates_lock: protects updates to known_gates
136-
* @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr
137-
* @walk_head: linked list containing all mesh_path objects
138-
* @walk_lock: lock protecting walk_head
139-
* @entries: number of entries in the table
140-
*/
141-
struct mesh_table {
142-
struct hlist_head known_gates;
143-
spinlock_t gates_lock;
144-
struct rhashtable rhead;
145-
struct hlist_head walk_head;
146-
spinlock_t walk_lock;
147-
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
148-
};
149-
150130
/* Recent multicast cache */
151131
/* RMC_BUCKETS must be a power of 2, maximum 256 */
152132
#define RMC_BUCKETS 256
@@ -308,7 +288,7 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
308288
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
309289
void mesh_path_flush_pending(struct mesh_path *mpath);
310290
void mesh_path_tx_pending(struct mesh_path *mpath);
311-
int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata);
291+
void mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata);
312292
void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata);
313293
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr);
314294
void mesh_path_timer(struct timer_list *t);

net/mac80211/mesh_pathtbl.c

Lines changed: 31 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -47,32 +47,24 @@ static void mesh_path_rht_free(void *ptr, void *tblptr)
4747
mesh_path_free_rcu(tbl, mpath);
4848
}
4949

50-
static struct mesh_table *mesh_table_alloc(void)
50+
static void mesh_table_init(struct mesh_table *tbl)
5151
{
52-
struct mesh_table *newtbl;
52+
INIT_HLIST_HEAD(&tbl->known_gates);
53+
INIT_HLIST_HEAD(&tbl->walk_head);
54+
atomic_set(&tbl->entries, 0);
55+
spin_lock_init(&tbl->gates_lock);
56+
spin_lock_init(&tbl->walk_lock);
5357

54-
newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
55-
if (!newtbl)
56-
return NULL;
57-
58-
INIT_HLIST_HEAD(&newtbl->known_gates);
59-
INIT_HLIST_HEAD(&newtbl->walk_head);
60-
atomic_set(&newtbl->entries, 0);
61-
spin_lock_init(&newtbl->gates_lock);
62-
spin_lock_init(&newtbl->walk_lock);
63-
if (rhashtable_init(&newtbl->rhead, &mesh_rht_params)) {
64-
kfree(newtbl);
65-
return NULL;
66-
}
67-
68-
return newtbl;
58+
/* rhashtable_init() may fail only in case of wrong
59+
* mesh_rht_params
60+
*/
61+
WARN_ON(rhashtable_init(&tbl->rhead, &mesh_rht_params));
6962
}
7063

7164
static void mesh_table_free(struct mesh_table *tbl)
7265
{
7366
rhashtable_free_and_destroy(&tbl->rhead,
7467
mesh_path_rht_free, tbl);
75-
kfree(tbl);
7668
}
7769

7870
/**
@@ -238,13 +230,13 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
238230
struct mesh_path *
239231
mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
240232
{
241-
return mpath_lookup(sdata->u.mesh.mesh_paths, dst, sdata);
233+
return mpath_lookup(&sdata->u.mesh.mesh_paths, dst, sdata);
242234
}
243235

244236
struct mesh_path *
245237
mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
246238
{
247-
return mpath_lookup(sdata->u.mesh.mpp_paths, dst, sdata);
239+
return mpath_lookup(&sdata->u.mesh.mpp_paths, dst, sdata);
248240
}
249241

250242
static struct mesh_path *
@@ -281,7 +273,7 @@ __mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx)
281273
struct mesh_path *
282274
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
283275
{
284-
return __mesh_path_lookup_by_idx(sdata->u.mesh.mesh_paths, idx);
276+
return __mesh_path_lookup_by_idx(&sdata->u.mesh.mesh_paths, idx);
285277
}
286278

287279
/**
@@ -296,7 +288,7 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
296288
struct mesh_path *
297289
mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
298290
{
299-
return __mesh_path_lookup_by_idx(sdata->u.mesh.mpp_paths, idx);
291+
return __mesh_path_lookup_by_idx(&sdata->u.mesh.mpp_paths, idx);
300292
}
301293

302294
/**
@@ -309,7 +301,7 @@ int mesh_path_add_gate(struct mesh_path *mpath)
309301
int err;
310302

311303
rcu_read_lock();
312-
tbl = mpath->sdata->u.mesh.mesh_paths;
304+
tbl = &mpath->sdata->u.mesh.mesh_paths;
313305

314306
spin_lock_bh(&mpath->state_lock);
315307
if (mpath->is_gate) {
@@ -418,7 +410,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
418410
if (!new_mpath)
419411
return ERR_PTR(-ENOMEM);
420412

421-
tbl = sdata->u.mesh.mesh_paths;
413+
tbl = &sdata->u.mesh.mesh_paths;
422414
spin_lock_bh(&tbl->walk_lock);
423415
mpath = rhashtable_lookup_get_insert_fast(&tbl->rhead,
424416
&new_mpath->rhash,
@@ -460,7 +452,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
460452
return -ENOMEM;
461453

462454
memcpy(new_mpath->mpp, mpp, ETH_ALEN);
463-
tbl = sdata->u.mesh.mpp_paths;
455+
tbl = &sdata->u.mesh.mpp_paths;
464456

465457
spin_lock_bh(&tbl->walk_lock);
466458
ret = rhashtable_lookup_insert_fast(&tbl->rhead,
@@ -489,7 +481,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
489481
void mesh_plink_broken(struct sta_info *sta)
490482
{
491483
struct ieee80211_sub_if_data *sdata = sta->sdata;
492-
struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
484+
struct mesh_table *tbl = &sdata->u.mesh.mesh_paths;
493485
static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
494486
struct mesh_path *mpath;
495487

@@ -548,7 +540,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
548540
void mesh_path_flush_by_nexthop(struct sta_info *sta)
549541
{
550542
struct ieee80211_sub_if_data *sdata = sta->sdata;
551-
struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
543+
struct mesh_table *tbl = &sdata->u.mesh.mesh_paths;
552544
struct mesh_path *mpath;
553545
struct hlist_node *n;
554546

@@ -563,7 +555,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
563555
static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
564556
const u8 *proxy)
565557
{
566-
struct mesh_table *tbl = sdata->u.mesh.mpp_paths;
558+
struct mesh_table *tbl = &sdata->u.mesh.mpp_paths;
567559
struct mesh_path *mpath;
568560
struct hlist_node *n;
569561

@@ -597,8 +589,8 @@ static void table_flush_by_iface(struct mesh_table *tbl)
597589
*/
598590
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
599591
{
600-
table_flush_by_iface(sdata->u.mesh.mesh_paths);
601-
table_flush_by_iface(sdata->u.mesh.mpp_paths);
592+
table_flush_by_iface(&sdata->u.mesh.mesh_paths);
593+
table_flush_by_iface(&sdata->u.mesh.mpp_paths);
602594
}
603595

604596
/**
@@ -644,7 +636,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
644636
/* flush relevant mpp entries first */
645637
mpp_flush_by_proxy(sdata, addr);
646638

647-
err = table_path_del(sdata->u.mesh.mesh_paths, sdata, addr);
639+
err = table_path_del(&sdata->u.mesh.mesh_paths, sdata, addr);
648640
sdata->u.mesh.mesh_paths_generation++;
649641
return err;
650642
}
@@ -682,7 +674,7 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
682674
struct mesh_path *gate;
683675
bool copy = false;
684676

685-
tbl = sdata->u.mesh.mesh_paths;
677+
tbl = &sdata->u.mesh.mesh_paths;
686678

687679
rcu_read_lock();
688680
hlist_for_each_entry_rcu(gate, &tbl->known_gates, gate_list) {
@@ -762,29 +754,10 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
762754
mesh_path_tx_pending(mpath);
763755
}
764756

765-
int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
757+
void mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
766758
{
767-
struct mesh_table *tbl_path, *tbl_mpp;
768-
int ret;
769-
770-
tbl_path = mesh_table_alloc();
771-
if (!tbl_path)
772-
return -ENOMEM;
773-
774-
tbl_mpp = mesh_table_alloc();
775-
if (!tbl_mpp) {
776-
ret = -ENOMEM;
777-
goto free_path;
778-
}
779-
780-
sdata->u.mesh.mesh_paths = tbl_path;
781-
sdata->u.mesh.mpp_paths = tbl_mpp;
782-
783-
return 0;
784-
785-
free_path:
786-
mesh_table_free(tbl_path);
787-
return ret;
759+
mesh_table_init(&sdata->u.mesh.mesh_paths);
760+
mesh_table_init(&sdata->u.mesh.mpp_paths);
788761
}
789762

790763
static
@@ -806,12 +779,12 @@ void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata,
806779

807780
void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
808781
{
809-
mesh_path_tbl_expire(sdata, sdata->u.mesh.mesh_paths);
810-
mesh_path_tbl_expire(sdata, sdata->u.mesh.mpp_paths);
782+
mesh_path_tbl_expire(sdata, &sdata->u.mesh.mesh_paths);
783+
mesh_path_tbl_expire(sdata, &sdata->u.mesh.mpp_paths);
811784
}
812785

813786
void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata)
814787
{
815-
mesh_table_free(sdata->u.mesh.mesh_paths);
816-
mesh_table_free(sdata->u.mesh.mpp_paths);
788+
mesh_table_free(&sdata->u.mesh.mesh_paths);
789+
mesh_table_free(&sdata->u.mesh.mpp_paths);
817790
}

0 commit comments

Comments
 (0)