Skip to content

Commit 6d436d6

Browse files
committed
net: openvswitch: fix upcall counter access before allocation
jira LE-1907 Rebuild_History Non-Buildable kernel-5.14.0-284.30.1.el9_2 commit-author Eelco Chaudron <[email protected]> commit de9df6c Currently, the per cpu upcall counters are allocated after the vport is created and inserted into the system. This could lead to the datapath accessing the counters before they are allocated resulting in a kernel Oops. Here is an example: PID: 59693 TASK: ffff0005f4f51500 CPU: 0 COMMAND: "ovs-vswitchd" #0 [ffff80000a39b5b0] __switch_to at ffffb70f0629f2f4 #1 [ffff80000a39b5d0] __schedule at ffffb70f0629f5cc #2 [ffff80000a39b650] preempt_schedule_common at ffffb70f0629fa60 #3 [ffff80000a39b670] dynamic_might_resched at ffffb70f0629fb58 ctrliq#4 [ffff80000a39b680] mutex_lock_killable at ffffb70f062a1388 ctrliq#5 [ffff80000a39b6a0] pcpu_alloc at ffffb70f0594460c ctrliq#6 [ffff80000a39b750] __alloc_percpu_gfp at ffffb70f05944e68 ctrliq#7 [ffff80000a39b760] ovs_vport_cmd_new at ffffb70ee6961b90 [openvswitch] ... PID: 58682 TASK: ffff0005b2f0bf00 CPU: 0 COMMAND: "kworker/0:3" #0 [ffff80000a5d2f40] machine_kexec at ffffb70f056a0758 #1 [ffff80000a5d2f70] __crash_kexec at ffffb70f057e2994 #2 [ffff80000a5d3100] crash_kexec at ffffb70f057e2ad8 #3 [ffff80000a5d3120] die at ffffb70f0628234c ctrliq#4 [ffff80000a5d31e0] die_kernel_fault at ffffb70f062828a8 ctrliq#5 [ffff80000a5d3210] __do_kernel_fault at ffffb70f056a31f4 ctrliq#6 [ffff80000a5d3240] do_bad_area at ffffb70f056a32a4 ctrliq#7 [ffff80000a5d3260] do_translation_fault at ffffb70f062a9710 ctrliq#8 [ffff80000a5d3270] do_mem_abort at ffffb70f056a2f74 ctrliq#9 [ffff80000a5d32a0] el1_abort at ffffb70f06297dac ctrliq#10 [ffff80000a5d32d0] el1h_64_sync_handler at ffffb70f06299b24 ctrliq#11 [ffff80000a5d3410] el1h_64_sync at ffffb70f056812dc ctrliq#12 [ffff80000a5d3430] ovs_dp_upcall at ffffb70ee6963c84 [openvswitch] ctrliq#13 [ffff80000a5d3470] ovs_dp_process_packet at ffffb70ee6963fdc [openvswitch] ctrliq#14 [ffff80000a5d34f0] ovs_vport_receive at ffffb70ee6972c78 [openvswitch] ctrliq#15 [ffff80000a5d36f0] netdev_port_receive at ffffb70ee6973948 [openvswitch] ctrliq#16 [ffff80000a5d3720] netdev_frame_hook at ffffb70ee6973a28 [openvswitch] ctrliq#17 [ffff80000a5d3730] __netif_receive_skb_core.constprop.0 at ffffb70f06079f90 We moved the per cpu upcall counter allocation to the existing vport alloc and free functions to solve this. Fixes: 95637d9 ("net: openvswitch: release vport resources on failure") Fixes: 1933ea3 ("net: openvswitch: Add support to count upcall packets") Signed-off-by: Eelco Chaudron <[email protected]> Reviewed-by: Simon Horman <[email protected]> Acked-by: Aaron Conole <[email protected]> Signed-off-by: David S. Miller <[email protected]> (cherry picked from commit de9df6c) Signed-off-by: Jonathan Maple <[email protected]>
1 parent fee6fe6 commit 6d436d6

File tree

2 files changed

+16
-21
lines changed

2 files changed

+16
-21
lines changed

net/openvswitch/datapath.c

-19
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,6 @@ void ovs_dp_detach_port(struct vport *p)
236236
/* First drop references to device. */
237237
hlist_del_rcu(&p->dp_hash_node);
238238

239-
/* Free percpu memory */
240-
free_percpu(p->upcall_stats);
241-
242239
/* Then destroy it. */
243240
ovs_vport_del(p);
244241
}
@@ -1856,12 +1853,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
18561853
goto err_destroy_portids;
18571854
}
18581855

1859-
vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
1860-
if (!vport->upcall_stats) {
1861-
err = -ENOMEM;
1862-
goto err_destroy_vport;
1863-
}
1864-
18651856
err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
18661857
info->snd_seq, 0, OVS_DP_CMD_NEW);
18671858
BUG_ON(err < 0);
@@ -1874,8 +1865,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
18741865
ovs_notify(&dp_datapath_genl_family, reply, info);
18751866
return 0;
18761867

1877-
err_destroy_vport:
1878-
ovs_dp_detach_port(vport);
18791868
err_destroy_portids:
18801869
kfree(rcu_dereference_raw(dp->upcall_portids));
18811870
err_unlock_and_destroy_meters:
@@ -2319,12 +2308,6 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
23192308
goto exit_unlock_free;
23202309
}
23212310

2322-
vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
2323-
if (!vport->upcall_stats) {
2324-
err = -ENOMEM;
2325-
goto exit_unlock_free_vport;
2326-
}
2327-
23282311
err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
23292312
info->snd_portid, info->snd_seq, 0,
23302313
OVS_VPORT_CMD_NEW, GFP_KERNEL);
@@ -2342,8 +2325,6 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
23422325
ovs_notify(&dp_vport_genl_family, reply, info);
23432326
return 0;
23442327

2345-
exit_unlock_free_vport:
2346-
ovs_dp_detach_port(vport);
23472328
exit_unlock_free:
23482329
ovs_unlock();
23492330
kfree_skb(reply);

net/openvswitch/vport.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
124124
{
125125
struct vport *vport;
126126
size_t alloc_size;
127+
int err;
127128

128129
alloc_size = sizeof(struct vport);
129130
if (priv_size) {
@@ -135,17 +136,29 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
135136
if (!vport)
136137
return ERR_PTR(-ENOMEM);
137138

139+
vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
140+
if (!vport->upcall_stats) {
141+
err = -ENOMEM;
142+
goto err_kfree_vport;
143+
}
144+
138145
vport->dp = parms->dp;
139146
vport->port_no = parms->port_no;
140147
vport->ops = ops;
141148
INIT_HLIST_NODE(&vport->dp_hash_node);
142149

143150
if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) {
144-
kfree(vport);
145-
return ERR_PTR(-EINVAL);
151+
err = -EINVAL;
152+
goto err_free_percpu;
146153
}
147154

148155
return vport;
156+
157+
err_free_percpu:
158+
free_percpu(vport->upcall_stats);
159+
err_kfree_vport:
160+
kfree(vport);
161+
return ERR_PTR(err);
149162
}
150163
EXPORT_SYMBOL_GPL(ovs_vport_alloc);
151164

@@ -165,6 +178,7 @@ void ovs_vport_free(struct vport *vport)
165178
* it is safe to use raw dereference.
166179
*/
167180
kfree(rcu_dereference_raw(vport->upcall_portids));
181+
free_percpu(vport->upcall_stats);
168182
kfree(vport);
169183
}
170184
EXPORT_SYMBOL_GPL(ovs_vport_free);

0 commit comments

Comments
 (0)