Skip to content

Commit 24d71b9

Browse files
ecsvsimonwunderlich
authored andcommitted
batman-adv: Add inconsistent claim netlink dump detection
The netlink dump functionality transfers a large number of entries from the kernel to userspace. It is rather likely that the transfer has to interrupted and later continued. During that time, it can happen that either new entries are added or removed. The userspace could than either receive some entries multiple times or miss entries. Commit 670dc28 ("netlink: advertise incomplete dumps") introduced a mechanism to inform userspace about this problem. Userspace can then decide whether it is necessary or not to retry dumping the information again. The netlink dump functions have to be switched to exclusive locks to avoid changes while the current message is prepared. The already existing generation sequence counter from the hash helper can be used for this simple hash. Reported-by: Matthias Schiffer <[email protected]> Signed-off-by: Sven Eckelmann <[email protected]> Signed-off-by: Simon Wunderlich <[email protected]>
1 parent b00d0e6 commit 24d71b9

File tree

1 file changed

+23
-18
lines changed

1 file changed

+23
-18
lines changed

net/batman-adv/bridge_loop_avoidance.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,14 +2094,15 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
20942094
* to a netlink socket
20952095
* @msg: buffer for the message
20962096
* @portid: netlink port
2097-
* @seq: Sequence number of netlink message
2097+
* @cb: Control block containing additional options
20982098
* @primary_if: primary interface
20992099
* @claim: entry to dump
21002100
*
21012101
* Return: 0 or error code.
21022102
*/
21032103
static int
2104-
batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
2104+
batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
2105+
struct netlink_callback *cb,
21052106
struct batadv_hard_iface *primary_if,
21062107
struct batadv_bla_claim *claim)
21072108
{
@@ -2111,13 +2112,16 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
21112112
void *hdr;
21122113
int ret = -EINVAL;
21132114

2114-
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
2115-
NLM_F_MULTI, BATADV_CMD_GET_BLA_CLAIM);
2115+
hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
2116+
&batadv_netlink_family, NLM_F_MULTI,
2117+
BATADV_CMD_GET_BLA_CLAIM);
21162118
if (!hdr) {
21172119
ret = -ENOBUFS;
21182120
goto out;
21192121
}
21202122

2123+
genl_dump_check_consistent(cb, hdr);
2124+
21212125
is_own = batadv_compare_eth(claim->backbone_gw->orig,
21222126
primary_addr);
21232127

@@ -2153,28 +2157,33 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
21532157
* to a netlink socket
21542158
* @msg: buffer for the message
21552159
* @portid: netlink port
2156-
* @seq: Sequence number of netlink message
2160+
* @cb: Control block containing additional options
21572161
* @primary_if: primary interface
2158-
* @head: bucket to dump
2162+
* @hash: hash to dump
2163+
* @bucket: bucket index to dump
21592164
* @idx_skip: How many entries to skip
21602165
*
21612166
* Return: always 0.
21622167
*/
21632168
static int
2164-
batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
2169+
batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid,
2170+
struct netlink_callback *cb,
21652171
struct batadv_hard_iface *primary_if,
2166-
struct hlist_head *head, int *idx_skip)
2172+
struct batadv_hashtable *hash, unsigned int bucket,
2173+
int *idx_skip)
21672174
{
21682175
struct batadv_bla_claim *claim;
21692176
int idx = 0;
21702177
int ret = 0;
21712178

2172-
rcu_read_lock();
2173-
hlist_for_each_entry_rcu(claim, head, hash_entry) {
2179+
spin_lock_bh(&hash->list_locks[bucket]);
2180+
cb->seq = atomic_read(&hash->generation) << 1 | 1;
2181+
2182+
hlist_for_each_entry(claim, &hash->table[bucket], hash_entry) {
21742183
if (idx++ < *idx_skip)
21752184
continue;
21762185

2177-
ret = batadv_bla_claim_dump_entry(msg, portid, seq,
2186+
ret = batadv_bla_claim_dump_entry(msg, portid, cb,
21782187
primary_if, claim);
21792188
if (ret) {
21802189
*idx_skip = idx - 1;
@@ -2184,7 +2193,7 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
21842193

21852194
*idx_skip = 0;
21862195
unlock:
2187-
rcu_read_unlock();
2196+
spin_unlock_bh(&hash->list_locks[bucket]);
21882197
return ret;
21892198
}
21902199

@@ -2204,7 +2213,6 @@ int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
22042213
struct batadv_hashtable *hash;
22052214
struct batadv_priv *bat_priv;
22062215
int bucket = cb->args[0];
2207-
struct hlist_head *head;
22082216
int idx = cb->args[1];
22092217
int ifindex;
22102218
int ret = 0;
@@ -2230,11 +2238,8 @@ int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
22302238
}
22312239

22322240
while (bucket < hash->size) {
2233-
head = &hash->table[bucket];
2234-
2235-
if (batadv_bla_claim_dump_bucket(msg, portid,
2236-
cb->nlh->nlmsg_seq,
2237-
primary_if, head, &idx))
2241+
if (batadv_bla_claim_dump_bucket(msg, portid, cb, primary_if,
2242+
hash, bucket, &idx))
22382243
break;
22392244
bucket++;
22402245
}

0 commit comments

Comments
 (0)