Skip to content

Commit 40400fd

Browse files
Guillaume Naultgregkh
authored andcommitted
netns: fix GFP flags in rtnl_net_notifyid()
[ Upstream commit d4e4fdf ] 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 1d72dbb commit 40400fd

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
@@ -322,7 +322,7 @@ static inline struct net *read_pnet(const possible_net_t *pnet)
322322
#define __net_initconst __initconst
323323
#endif
324324

325-
int peernet2id_alloc(struct net *net, struct net *peer);
325+
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp);
326326
int peernet2id(struct net *net, struct net *peer);
327327
bool peernet_has_id(struct net *net, struct net *peer);
328328
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
@@ -9211,7 +9211,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
92119211
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
92129212
rcu_barrier();
92139213

9214-
new_nsid = peernet2id_alloc(dev_net(dev), net);
9214+
new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);
92159215
/* If there is an ifindex conflict assign a new one */
92169216
if (__dev_get_by_index(net, dev->ifindex))
92179217
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
@@ -226,11 +226,11 @@ static int __peernet2id(struct net *net, struct net *peer)
226226
return __peernet2id_alloc(net, peer, &no);
227227
}
228228

229-
static void rtnl_net_notifyid(struct net *net, int cmd, int id);
229+
static void rtnl_net_notifyid(struct net *net, int cmd, int id, gfp_t gfp);
230230
/* This function returns the id of a peer netns. If no id is assigned, one will
231231
* be allocated and returned.
232232
*/
233-
int peernet2id_alloc(struct net *net, struct net *peer)
233+
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
234234
{
235235
bool alloc = false, alive = false;
236236
int id;
@@ -249,7 +249,7 @@ int peernet2id_alloc(struct net *net, struct net *peer)
249249
id = __peernet2id_alloc(net, peer, &alloc);
250250
spin_unlock_bh(&net->nsid_lock);
251251
if (alloc && id >= 0)
252-
rtnl_net_notifyid(net, RTM_NEWNSID, id);
252+
rtnl_net_notifyid(net, RTM_NEWNSID, id, gfp);
253253
if (alive)
254254
put_net(peer);
255255
return id;
@@ -495,7 +495,8 @@ static void unhash_nsid(struct net *net, struct net *last)
495495
idr_remove(&tmp->netns_ids, id);
496496
spin_unlock_bh(&tmp->nsid_lock);
497497
if (id >= 0)
498-
rtnl_net_notifyid(tmp, RTM_DELNSID, id);
498+
rtnl_net_notifyid(tmp, RTM_DELNSID, id,
499+
GFP_KERNEL);
499500
if (tmp == last)
500501
break;
501502
}
@@ -720,7 +721,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
720721
err = alloc_netid(net, peer, nsid);
721722
spin_unlock_bh(&net->nsid_lock);
722723
if (err >= 0) {
723-
rtnl_net_notifyid(net, RTM_NEWNSID, err);
724+
rtnl_net_notifyid(net, RTM_NEWNSID, err, GFP_KERNEL);
724725
err = 0;
725726
} else if (err == -ENOSPC && nsid >= 0) {
726727
err = -EEXIST;
@@ -862,20 +863,20 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
862863
return skb->len;
863864
}
864865

865-
static void rtnl_net_notifyid(struct net *net, int cmd, int id)
866+
static void rtnl_net_notifyid(struct net *net, int cmd, int id, gfp_t gfp)
866867
{
867868
struct sk_buff *msg;
868869
int err = -ENOMEM;
869870

870-
msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
871+
msg = nlmsg_new(rtnl_net_get_size(), gfp);
871872
if (!msg)
872873
goto out;
873874

874875
err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id);
875876
if (err < 0)
876877
goto err_out;
877878

878-
rtnl_notify(msg, net, 0, RTNLGRP_NSID, NULL, 0);
879+
rtnl_notify(msg, net, 0, RTNLGRP_NSID, NULL, gfp);
879880
return;
880881

881882
err_out:

net/core/rtnetlink.c

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

15201520
static int rtnl_fill_link_netnsid(struct sk_buff *skb,
15211521
const struct net_device *dev,
1522-
struct net *src_net)
1522+
struct net *src_net, gfp_t gfp)
15231523
{
15241524
bool put_iflink = false;
15251525

15261526
if (dev->rtnl_link_ops && dev->rtnl_link_ops->get_link_net) {
15271527
struct net *link_net = dev->rtnl_link_ops->get_link_net(dev);
15281528

15291529
if (!net_eq(dev_net(dev), link_net)) {
1530-
int id = peernet2id_alloc(src_net, link_net);
1530+
int id = peernet2id_alloc(src_net, link_net, gfp);
15311531

15321532
if (nla_put_s32(skb, IFLA_LINK_NETNSID, id))
15331533
return -EMSGSIZE;
@@ -1585,7 +1585,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
15851585
int type, u32 pid, u32 seq, u32 change,
15861586
unsigned int flags, u32 ext_filter_mask,
15871587
u32 event, int *new_nsid, int new_ifindex,
1588-
int tgt_netnsid)
1588+
int tgt_netnsid, gfp_t gfp)
15891589
{
15901590
struct ifinfomsg *ifm;
15911591
struct nlmsghdr *nlh;
@@ -1677,7 +1677,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
16771677
goto nla_put_failure;
16781678
}
16791679

1680-
if (rtnl_fill_link_netnsid(skb, dev, src_net))
1680+
if (rtnl_fill_link_netnsid(skb, dev, src_net, gfp))
16811681
goto nla_put_failure;
16821682

16831683
if (new_nsid &&
@@ -1933,7 +1933,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
19331933
cb->nlh->nlmsg_seq, 0,
19341934
flags,
19351935
ext_filter_mask, 0, NULL, 0,
1936-
netnsid);
1936+
netnsid, GFP_KERNEL);
19371937

19381938
if (err < 0) {
19391939
if (likely(skb->len))
@@ -3215,7 +3215,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
32153215
err = rtnl_fill_ifinfo(nskb, dev, net,
32163216
RTM_NEWLINK, NETLINK_CB(skb).portid,
32173217
nlh->nlmsg_seq, 0, 0, ext_filter_mask,
3218-
0, NULL, 0, netnsid);
3218+
0, NULL, 0, netnsid, GFP_KERNEL);
32193219
if (err < 0) {
32203220
/* -EMSGSIZE implies BUG in if_nlmsg_size */
32213221
WARN_ON(err == -EMSGSIZE);
@@ -3325,7 +3325,7 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
33253325

33263326
err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
33273327
type, 0, 0, change, 0, 0, event,
3328-
new_nsid, new_ifindex, -1);
3328+
new_nsid, new_ifindex, -1, flags);
33293329
if (err < 0) {
33303330
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
33313331
WARN_ON(err == -EMSGSIZE);

net/openvswitch/datapath.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,7 +1843,7 @@ static struct genl_family dp_datapath_genl_family __ro_after_init = {
18431843
/* Called with ovs_mutex or RCU read lock. */
18441844
static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
18451845
struct net *net, u32 portid, u32 seq,
1846-
u32 flags, u8 cmd)
1846+
u32 flags, u8 cmd, gfp_t gfp)
18471847
{
18481848
struct ovs_header *ovs_header;
18491849
struct ovs_vport_stats vport_stats;
@@ -1864,7 +1864,7 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
18641864
goto nla_put_failure;
18651865

18661866
if (!net_eq(net, dev_net(vport->dev))) {
1867-
int id = peernet2id_alloc(net, dev_net(vport->dev));
1867+
int id = peernet2id_alloc(net, dev_net(vport->dev), gfp);
18681868

18691869
if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
18701870
goto nla_put_failure;
@@ -1905,11 +1905,12 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
19051905
struct sk_buff *skb;
19061906
int retval;
19071907

1908-
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1908+
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
19091909
if (!skb)
19101910
return ERR_PTR(-ENOMEM);
19111911

1912-
retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd);
1912+
retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd,
1913+
GFP_KERNEL);
19131914
BUG_ON(retval < 0);
19141915

19151916
return skb;
@@ -2042,7 +2043,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
20422043

20432044
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
20442045
info->snd_portid, info->snd_seq, 0,
2045-
OVS_VPORT_CMD_NEW);
2046+
OVS_VPORT_CMD_NEW, GFP_KERNEL);
20462047

20472048
if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
20482049
update_headroom(dp);
@@ -2101,7 +2102,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
21012102

21022103
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
21032104
info->snd_portid, info->snd_seq, 0,
2104-
OVS_VPORT_CMD_NEW);
2105+
OVS_VPORT_CMD_NEW, GFP_ATOMIC);
21052106
BUG_ON(err < 0);
21062107

21072108
ovs_unlock();
@@ -2140,7 +2141,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
21402141

21412142
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
21422143
info->snd_portid, info->snd_seq, 0,
2143-
OVS_VPORT_CMD_DEL);
2144+
OVS_VPORT_CMD_DEL, GFP_KERNEL);
21442145
BUG_ON(err < 0);
21452146

21462147
/* the vport deletion may trigger dp headroom update */
@@ -2182,7 +2183,7 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
21822183
goto exit_unlock_free;
21832184
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
21842185
info->snd_portid, info->snd_seq, 0,
2185-
OVS_VPORT_CMD_NEW);
2186+
OVS_VPORT_CMD_NEW, GFP_ATOMIC);
21862187
BUG_ON(err < 0);
21872188
rcu_read_unlock();
21882189

@@ -2218,7 +2219,8 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
22182219
NETLINK_CB(cb->skb).portid,
22192220
cb->nlh->nlmsg_seq,
22202221
NLM_F_MULTI,
2221-
OVS_VPORT_CMD_NEW) < 0)
2222+
OVS_VPORT_CMD_NEW,
2223+
GFP_ATOMIC) < 0)
22222224
goto out;
22232225

22242226
j++;

0 commit comments

Comments
 (0)