Skip to content

Commit e420251

Browse files
Florian Westphaldavem330
authored andcommitted
rtnetlink: get reference on module before invoking handlers
Add yet another rtnl_register function. It will be used by modules that can be removed. The passed module struct is used to prevent module unload while a netlink dump is in progress or when a DOIT_UNLOCKED doit callback is called. Cc: Peter Zijlstra <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent addf9b9 commit e420251

File tree

2 files changed

+80
-35
lines changed

2 files changed

+80
-35
lines changed

include/net/rtnetlink.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ int __rtnl_register(int protocol, int msgtype,
1717
rtnl_doit_func, rtnl_dumpit_func, unsigned int flags);
1818
void rtnl_register(int protocol, int msgtype,
1919
rtnl_doit_func, rtnl_dumpit_func, unsigned int flags);
20+
int rtnl_register_module(struct module *owner, int protocol, int msgtype,
21+
rtnl_doit_func, rtnl_dumpit_func, unsigned int flags);
2022
int rtnl_unregister(int protocol, int msgtype);
2123
void rtnl_unregister_all(int protocol);
2224

net/core/rtnetlink.c

Lines changed: 78 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
struct rtnl_link {
6363
rtnl_doit_func doit;
6464
rtnl_dumpit_func dumpit;
65+
struct module *owner;
6566
unsigned int flags;
6667
struct rcu_head rcu;
6768
};
@@ -129,7 +130,6 @@ EXPORT_SYMBOL(lockdep_rtnl_is_held);
129130
#endif /* #ifdef CONFIG_PROVE_LOCKING */
130131

131132
static struct rtnl_link __rcu **rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];
132-
static refcount_t rtnl_msg_handlers_ref[RTNL_FAMILY_MAX + 1];
133133

134134
static inline int rtm_msgindex(int msgtype)
135135
{
@@ -159,27 +159,10 @@ static struct rtnl_link *rtnl_get_link(int protocol, int msgtype)
159159
return tab[msgtype];
160160
}
161161

162-
/**
163-
* __rtnl_register - Register a rtnetlink message type
164-
* @protocol: Protocol family or PF_UNSPEC
165-
* @msgtype: rtnetlink message type
166-
* @doit: Function pointer called for each request message
167-
* @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
168-
* @flags: rtnl_link_flags to modifiy behaviour of doit/dumpit functions
169-
*
170-
* Registers the specified function pointers (at least one of them has
171-
* to be non-NULL) to be called whenever a request message for the
172-
* specified protocol family and message type is received.
173-
*
174-
* The special protocol family PF_UNSPEC may be used to define fallback
175-
* function pointers for the case when no entry for the specific protocol
176-
* family exists.
177-
*
178-
* Returns 0 on success or a negative error code.
179-
*/
180-
int __rtnl_register(int protocol, int msgtype,
181-
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
182-
unsigned int flags)
162+
static int rtnl_register_internal(struct module *owner,
163+
int protocol, int msgtype,
164+
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
165+
unsigned int flags)
183166
{
184167
struct rtnl_link **tab, *link, *old;
185168
int msgindex;
@@ -210,6 +193,9 @@ int __rtnl_register(int protocol, int msgtype,
210193
goto unlock;
211194
}
212195

196+
WARN_ON(link->owner && link->owner != owner);
197+
link->owner = owner;
198+
213199
WARN_ON(doit && link->doit && link->doit != doit);
214200
if (doit)
215201
link->doit = doit;
@@ -228,6 +214,54 @@ int __rtnl_register(int protocol, int msgtype,
228214
rtnl_unlock();
229215
return ret;
230216
}
217+
218+
/**
219+
* rtnl_register_module - Register a rtnetlink message type
220+
*
221+
* @owner: module registering the hook (THIS_MODULE)
222+
* @protocol: Protocol family or PF_UNSPEC
223+
* @msgtype: rtnetlink message type
224+
* @doit: Function pointer called for each request message
225+
* @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
226+
* @flags: rtnl_link_flags to modifiy behaviour of doit/dumpit functions
227+
*
228+
* Like rtnl_register, but for use by removable modules.
229+
*/
230+
int rtnl_register_module(struct module *owner,
231+
int protocol, int msgtype,
232+
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
233+
unsigned int flags)
234+
{
235+
return rtnl_register_internal(owner, protocol, msgtype,
236+
doit, dumpit, flags);
237+
}
238+
EXPORT_SYMBOL_GPL(rtnl_register_module);
239+
240+
/**
241+
* __rtnl_register - Register a rtnetlink message type
242+
* @protocol: Protocol family or PF_UNSPEC
243+
* @msgtype: rtnetlink message type
244+
* @doit: Function pointer called for each request message
245+
* @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
246+
* @flags: rtnl_link_flags to modifiy behaviour of doit/dumpit functions
247+
*
248+
* Registers the specified function pointers (at least one of them has
249+
* to be non-NULL) to be called whenever a request message for the
250+
* specified protocol family and message type is received.
251+
*
252+
* The special protocol family PF_UNSPEC may be used to define fallback
253+
* function pointers for the case when no entry for the specific protocol
254+
* family exists.
255+
*
256+
* Returns 0 on success or a negative error code.
257+
*/
258+
int __rtnl_register(int protocol, int msgtype,
259+
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
260+
unsigned int flags)
261+
{
262+
return rtnl_register_internal(NULL, protocol, msgtype,
263+
doit, dumpit, flags);
264+
}
231265
EXPORT_SYMBOL_GPL(__rtnl_register);
232266

233267
/**
@@ -311,8 +345,6 @@ void rtnl_unregister_all(int protocol)
311345

312346
synchronize_net();
313347

314-
while (refcount_read(&rtnl_msg_handlers_ref[protocol]) > 1)
315-
schedule();
316348
kfree(tab);
317349
}
318350
EXPORT_SYMBOL_GPL(rtnl_unregister_all);
@@ -4372,6 +4404,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
43724404
{
43734405
struct net *net = sock_net(skb->sk);
43744406
struct rtnl_link *link;
4407+
struct module *owner;
43754408
int err = -EOPNOTSUPP;
43764409
rtnl_doit_func doit;
43774410
unsigned int flags;
@@ -4408,24 +4441,32 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
44084441
if (!link || !link->dumpit)
44094442
goto err_unlock;
44104443
}
4444+
owner = link->owner;
44114445
dumpit = link->dumpit;
44124446

4413-
refcount_inc(&rtnl_msg_handlers_ref[family]);
4414-
44154447
if (type == RTM_GETLINK - RTM_BASE)
44164448
min_dump_alloc = rtnl_calcit(skb, nlh);
44174449

4450+
err = 0;
4451+
/* need to do this before rcu_read_unlock() */
4452+
if (!try_module_get(owner))
4453+
err = -EPROTONOSUPPORT;
4454+
44184455
rcu_read_unlock();
44194456

44204457
rtnl = net->rtnl;
4421-
{
4458+
if (err == 0) {
44224459
struct netlink_dump_control c = {
44234460
.dump = dumpit,
44244461
.min_dump_alloc = min_dump_alloc,
4462+
.module = owner,
44254463
};
44264464
err = netlink_dump_start(rtnl, skb, nlh, &c);
4465+
/* netlink_dump_start() will keep a reference on
4466+
* module if dump is still in progress.
4467+
*/
4468+
module_put(owner);
44274469
}
4428-
refcount_dec(&rtnl_msg_handlers_ref[family]);
44294470
return err;
44304471
}
44314472

@@ -4437,14 +4478,19 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
44374478
goto out_unlock;
44384479
}
44394480

4481+
owner = link->owner;
4482+
if (!try_module_get(owner)) {
4483+
err = -EPROTONOSUPPORT;
4484+
goto out_unlock;
4485+
}
4486+
44404487
flags = link->flags;
44414488
if (flags & RTNL_FLAG_DOIT_UNLOCKED) {
4442-
refcount_inc(&rtnl_msg_handlers_ref[family]);
44434489
doit = link->doit;
44444490
rcu_read_unlock();
44454491
if (doit)
44464492
err = doit(skb, nlh, extack);
4447-
refcount_dec(&rtnl_msg_handlers_ref[family]);
4493+
module_put(owner);
44484494
return err;
44494495
}
44504496
rcu_read_unlock();
@@ -4455,6 +4501,8 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
44554501
err = link->doit(skb, nlh, extack);
44564502
rtnl_unlock();
44574503

4504+
module_put(owner);
4505+
44584506
return err;
44594507

44604508
out_unlock:
@@ -4546,11 +4594,6 @@ static struct pernet_operations rtnetlink_net_ops = {
45464594

45474595
void __init rtnetlink_init(void)
45484596
{
4549-
int i;
4550-
4551-
for (i = 0; i < ARRAY_SIZE(rtnl_msg_handlers_ref); i++)
4552-
refcount_set(&rtnl_msg_handlers_ref[i], 1);
4553-
45544597
if (register_pernet_subsys(&rtnetlink_net_ops))
45554598
panic("rtnetlink_init: cannot initialize rtnetlink\n");
45564599

0 commit comments

Comments
 (0)