Skip to content

Commit d4e4fdf

Browse files
Guillaume Naultdavem330
authored andcommitted
netns: fix GFP flags in rtnl_net_notifyid()
In rtnl_net_notifyid(), we certainly can't pass a null GFP flag to rtnl_notify(). A GFP_KERNEL flag would be fine in most circumstances, but there are a few paths calling rtnl_net_notifyid() from atomic context or from RCU critical sections. The later also precludes the use of gfp_any() as it wouldn't detect the RCU case. Also, the nlmsg_new() call is wrong too, as it uses GFP_KERNEL unconditionally. Therefore, we need to pass the GFP flags as parameter and propagate it through function calls until the proper flags can be determined. In most cases, GFP_KERNEL is fine. The exceptions are: * openvswitch: ovs_vport_cmd_get() and ovs_vport_cmd_dump() indirectly call rtnl_net_notifyid() from RCU critical section, * rtnetlink: rtmsg_ifinfo_build_skb() already receives GFP flags as parameter. Also, in ovs_vport_cmd_build_info(), let's change the GFP flags used by nlmsg_new(). The function is allowed to sleep, so better make the flags consistent with the ones used in the following ovs_vport_cmd_fill_info() call. Found by code inspection. Fixes: 9a96345 ("netns: notify netns id events") Signed-off-by: Guillaume Nault <[email protected]> Acked-by: Nicolas Dichtel <[email protected]> Acked-by: Pravin B Shelar <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 16d6528 commit d4e4fdf

File tree

5 files changed

+29
-26
lines changed

5 files changed

+29
-26
lines changed

include/net/net_namespace.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ static inline struct net *read_pnet(const possible_net_t *pnet)
342342
#define __net_initconst __initconst
343343
#endif
344344

345-
int peernet2id_alloc(struct net *net, struct net *peer);
345+
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp);
346346
int peernet2id(struct net *net, struct net *peer);
347347
bool peernet_has_id(struct net *net, struct net *peer);
348348
struct net *get_net_ns_by_id(struct net *net, int id);

net/core/dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9770,7 +9770,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
97709770
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
97719771
rcu_barrier();
97729772

9773-
new_nsid = peernet2id_alloc(dev_net(dev), net);
9773+
new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);
97749774
/* If there is an ifindex conflict assign a new one */
97759775
if (__dev_get_by_index(net, dev->ifindex))
97769776
new_ifindex = dev_new_index(net);

net/core/net_namespace.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,11 @@ static int __peernet2id(struct net *net, struct net *peer)
246246
}
247247

248248
static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
249-
struct nlmsghdr *nlh);
249+
struct nlmsghdr *nlh, gfp_t gfp);
250250
/* This function returns the id of a peer netns. If no id is assigned, one will
251251
* be allocated and returned.
252252
*/
253-
int peernet2id_alloc(struct net *net, struct net *peer)
253+
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
254254
{
255255
bool alloc = false, alive = false;
256256
int id;
@@ -269,7 +269,7 @@ int peernet2id_alloc(struct net *net, struct net *peer)
269269
id = __peernet2id_alloc(net, peer, &alloc);
270270
spin_unlock_bh(&net->nsid_lock);
271271
if (alloc && id >= 0)
272-
rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL);
272+
rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp);
273273
if (alive)
274274
put_net(peer);
275275
return id;
@@ -534,7 +534,8 @@ static void unhash_nsid(struct net *net, struct net *last)
534534
idr_remove(&tmp->netns_ids, id);
535535
spin_unlock_bh(&tmp->nsid_lock);
536536
if (id >= 0)
537-
rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL);
537+
rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL,
538+
GFP_KERNEL);
538539
if (tmp == last)
539540
break;
540541
}
@@ -767,7 +768,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
767768
spin_unlock_bh(&net->nsid_lock);
768769
if (err >= 0) {
769770
rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid,
770-
nlh);
771+
nlh, GFP_KERNEL);
771772
err = 0;
772773
} else if (err == -ENOSPC && nsid >= 0) {
773774
err = -EEXIST;
@@ -1055,7 +1056,7 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
10551056
}
10561057

10571058
static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
1058-
struct nlmsghdr *nlh)
1059+
struct nlmsghdr *nlh, gfp_t gfp)
10591060
{
10601061
struct net_fill_args fillargs = {
10611062
.portid = portid,
@@ -1066,15 +1067,15 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
10661067
struct sk_buff *msg;
10671068
int err = -ENOMEM;
10681069

1069-
msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
1070+
msg = nlmsg_new(rtnl_net_get_size(), gfp);
10701071
if (!msg)
10711072
goto out;
10721073

10731074
err = rtnl_net_fill(msg, &fillargs);
10741075
if (err < 0)
10751076
goto err_out;
10761077

1077-
rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, 0);
1078+
rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, gfp);
10781079
return;
10791080

10801081
err_out:

net/core/rtnetlink.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,15 +1523,15 @@ static noinline_for_stack int nla_put_ifalias(struct sk_buff *skb,
15231523

15241524
static int rtnl_fill_link_netnsid(struct sk_buff *skb,
15251525
const struct net_device *dev,
1526-
struct net *src_net)
1526+
struct net *src_net, gfp_t gfp)
15271527
{
15281528
bool put_iflink = false;
15291529

15301530
if (dev->rtnl_link_ops && dev->rtnl_link_ops->get_link_net) {
15311531
struct net *link_net = dev->rtnl_link_ops->get_link_net(dev);
15321532

15331533
if (!net_eq(dev_net(dev), link_net)) {
1534-
int id = peernet2id_alloc(src_net, link_net);
1534+
int id = peernet2id_alloc(src_net, link_net, gfp);
15351535

15361536
if (nla_put_s32(skb, IFLA_LINK_NETNSID, id))
15371537
return -EMSGSIZE;
@@ -1589,7 +1589,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
15891589
int type, u32 pid, u32 seq, u32 change,
15901590
unsigned int flags, u32 ext_filter_mask,
15911591
u32 event, int *new_nsid, int new_ifindex,
1592-
int tgt_netnsid)
1592+
int tgt_netnsid, gfp_t gfp)
15931593
{
15941594
struct ifinfomsg *ifm;
15951595
struct nlmsghdr *nlh;
@@ -1681,7 +1681,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
16811681
goto nla_put_failure;
16821682
}
16831683

1684-
if (rtnl_fill_link_netnsid(skb, dev, src_net))
1684+
if (rtnl_fill_link_netnsid(skb, dev, src_net, gfp))
16851685
goto nla_put_failure;
16861686

16871687
if (new_nsid &&
@@ -2001,7 +2001,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
20012001
NETLINK_CB(cb->skb).portid,
20022002
nlh->nlmsg_seq, 0, flags,
20032003
ext_filter_mask, 0, NULL, 0,
2004-
netnsid);
2004+
netnsid, GFP_KERNEL);
20052005

20062006
if (err < 0) {
20072007
if (likely(skb->len))
@@ -3360,7 +3360,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
33603360
err = rtnl_fill_ifinfo(nskb, dev, net,
33613361
RTM_NEWLINK, NETLINK_CB(skb).portid,
33623362
nlh->nlmsg_seq, 0, 0, ext_filter_mask,
3363-
0, NULL, 0, netnsid);
3363+
0, NULL, 0, netnsid, GFP_KERNEL);
33643364
if (err < 0) {
33653365
/* -EMSGSIZE implies BUG in if_nlmsg_size */
33663366
WARN_ON(err == -EMSGSIZE);
@@ -3472,7 +3472,7 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
34723472

34733473
err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
34743474
type, 0, 0, change, 0, 0, event,
3475-
new_nsid, new_ifindex, -1);
3475+
new_nsid, new_ifindex, -1, flags);
34763476
if (err < 0) {
34773477
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
34783478
WARN_ON(err == -EMSGSIZE);

net/openvswitch/datapath.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,7 +1881,7 @@ static struct genl_family dp_datapath_genl_family __ro_after_init = {
18811881
/* Called with ovs_mutex or RCU read lock. */
18821882
static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
18831883
struct net *net, u32 portid, u32 seq,
1884-
u32 flags, u8 cmd)
1884+
u32 flags, u8 cmd, gfp_t gfp)
18851885
{
18861886
struct ovs_header *ovs_header;
18871887
struct ovs_vport_stats vport_stats;
@@ -1902,7 +1902,7 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
19021902
goto nla_put_failure;
19031903

19041904
if (!net_eq(net, dev_net(vport->dev))) {
1905-
int id = peernet2id_alloc(net, dev_net(vport->dev));
1905+
int id = peernet2id_alloc(net, dev_net(vport->dev), gfp);
19061906

19071907
if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
19081908
goto nla_put_failure;
@@ -1943,11 +1943,12 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
19431943
struct sk_buff *skb;
19441944
int retval;
19451945

1946-
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1946+
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
19471947
if (!skb)
19481948
return ERR_PTR(-ENOMEM);
19491949

1950-
retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd);
1950+
retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd,
1951+
GFP_KERNEL);
19511952
BUG_ON(retval < 0);
19521953

19531954
return skb;
@@ -2089,7 +2090,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
20892090

20902091
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
20912092
info->snd_portid, info->snd_seq, 0,
2092-
OVS_VPORT_CMD_NEW);
2093+
OVS_VPORT_CMD_NEW, GFP_KERNEL);
20932094

20942095
new_headroom = netdev_get_fwd_headroom(vport->dev);
20952096

@@ -2150,7 +2151,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
21502151

21512152
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
21522153
info->snd_portid, info->snd_seq, 0,
2153-
OVS_VPORT_CMD_SET);
2154+
OVS_VPORT_CMD_SET, GFP_KERNEL);
21542155
BUG_ON(err < 0);
21552156

21562157
ovs_unlock();
@@ -2190,7 +2191,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
21902191

21912192
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
21922193
info->snd_portid, info->snd_seq, 0,
2193-
OVS_VPORT_CMD_DEL);
2194+
OVS_VPORT_CMD_DEL, GFP_KERNEL);
21942195
BUG_ON(err < 0);
21952196

21962197
/* the vport deletion may trigger dp headroom update */
@@ -2237,7 +2238,7 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
22372238
goto exit_unlock_free;
22382239
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
22392240
info->snd_portid, info->snd_seq, 0,
2240-
OVS_VPORT_CMD_GET);
2241+
OVS_VPORT_CMD_GET, GFP_ATOMIC);
22412242
BUG_ON(err < 0);
22422243
rcu_read_unlock();
22432244

@@ -2273,7 +2274,8 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
22732274
NETLINK_CB(cb->skb).portid,
22742275
cb->nlh->nlmsg_seq,
22752276
NLM_F_MULTI,
2276-
OVS_VPORT_CMD_GET) < 0)
2277+
OVS_VPORT_CMD_GET,
2278+
GFP_ATOMIC) < 0)
22772279
goto out;
22782280

22792281
j++;

0 commit comments

Comments
 (0)