rue/net: avoid wrong memory access to struct net_device

It assigns the net_device pointer of network interface to
sock->in_dev in cls_tc_rx_hook() in the receiving process.
The use of a sock->in_dev pointer can potentially lead to
wrong memory access if the memory of struct net_device is
freed after network interface is unregistered, which may
cause kernel crash.

The above use after free issue causes a crash as follows:

BUG: unable to handle page fault for address: ffffffed698999c8
CPU: 50 PID: 1290732 Comm: kubelet Kdump: loaded
Tainted: G O K 5.4.119-1-tlinux4-0009.1 #1
RIP: 0010:cls_cgroup_tx_accept+0x5e/0x120
Call Trace:
 <IRQ>
 cls_tc_tx_hook+0x10d/0x1a0
 nf_hook_slow+0x43/0xc0
 __ip_local_out+0xcb/0x130
 ? ip_forward_options+0x190/0x190
 ip_local_out+0x1c/0x40
 __ip_queue_xmit+0x162/0x3d0
 ? rx_cgroup_throttle.isra.4+0x2b0/0x2b0
 ip_queue_xmit+0x10/0x20
 __tcp_transmit_skb+0x57f/0xbe0
 __tcp_retransmit_skb+0x1b0/0x8a0
 tcp_retransmit_skb+0x19/0xd0
 tcp_retransmit_timer+0x367/0xa80
 ? kvm_clock_get_cycles+0x11/0x20
 ? ktime_get+0x34/0x90
 tcp_write_timer_handler+0x93/0x1f0
 tcp_write_timer+0x7c/0x80
 ? tcp_write_timer_handler+0x1f0/0x1f0
 call_timer_fn+0x35/0x130
 run_timer_softirq+0x1a8/0x420
 ? ktime_get+0x34/0x90
 ? clockevents_program_event+0x85/0xe0
 __do_softirq+0x8c/0x2d7
 ? hrtimer_interrupt+0x12a/0x210
 irq_exit+0xa3/0xb0
 smp_apic_timer_interrupt+0x77/0x130
 apic_timer_interrupt+0xf/0x20
 </IRQ>

We introduce indev_ifindex as a new struct filed to record
the ifindex of net_device, and then indev_ifindex can be
used for obtaining an index to avoid direct memory access
to struct members of in_dev pointer.

Fixes: f8829546f3b3 ("rue/net: init netcls traffic controller")
Signed-off-by: Honglin Li <honglinli@tencent.com>
Reviewed-by: Ze Gao <zegao@tencent.com>
This commit is contained in:
Honglin Li 2024-07-26 14:36:02 +08:00 committed by Haisu Wang
parent 68a7910a16
commit 26941c0f5e
5 changed files with 13 additions and 7 deletions

View File

@ -1595,8 +1595,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
}
skb->dev = bond->dev;
if (skb->in_dev == orig_dev)
skb->in_dev = skb->dev;
if (skb->in_dev == (u64)orig_dev) {
skb->in_dev = (u64)skb->dev;
skb->indev_ifindex = skb->dev->ifindex;
}
if (BOND_MODE(bond) == BOND_MODE_ALB &&
netif_is_bridge_port(bond->dev) &&

View File

@ -854,7 +854,8 @@ struct sk_buff {
*/
unsigned long dev_scratch;
};
struct net_device *in_dev;
u64 in_dev;
int indev_ifindex;
};
struct rb_node rbnode; /* used in netem, ip4 defrag, and tcp stack */
struct list_head list;

View File

@ -555,8 +555,9 @@ struct sock {
struct rcu_head sk_rcu;
netns_tracker ns_tracker;
struct hlist_node sk_bind2_node;
struct net_device *in_dev;
pid_t pid;
pid_t pid;
u64 in_dev;
int indev_ifindex;
/*VPC INFO*/
struct tvpc_info sk_tvpc_info;

View File

@ -5357,8 +5357,9 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
trace_netif_receive_skb(skb);
orig_dev = skb->dev;
if (orig_dev->dev.parent && !skb->in_dev) {
skb->in_dev = orig_dev;
if (orig_dev->dev.parent && skb->in_dev != (u64)orig_dev) {
skb->in_dev = (u64)orig_dev;
skb->indev_ifindex = orig_dev->ifindex;
skb->physical_flag = NETDEV_PHYSICAL_MAGIC;
}

View File

@ -1375,6 +1375,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
/* We do not copy old->sk */
new->dev = old->dev;
new->in_dev = old->in_dev;
new->indev_ifindex = old->indev_ifindex;
new->physical_flag = old->physical_flag;
memcpy(new->cb, old->cb, sizeof(old->cb));
skb_dst_copy(new, old);