diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/datagram.c | 3 | ||||
| -rw-r--r-- | net/core/dev.c | 2 | ||||
| -rw-r--r-- | net/core/dev.h | 1 | ||||
| -rw-r--r-- | net/core/drop_monitor.c | 18 | ||||
| -rw-r--r-- | net/core/filter.c | 21 | ||||
| -rw-r--r-- | net/core/gro.c | 4 | ||||
| -rw-r--r-- | net/core/lwt_bpf.c | 4 | ||||
| -rw-r--r-- | net/core/net-sysfs.c | 14 | ||||
| -rw-r--r-- | net/core/net-sysfs.h | 1 | ||||
| -rw-r--r-- | net/core/netdev_work.c | 16 | ||||
| -rw-r--r-- | net/core/pktgen.c | 4 | ||||
| -rw-r--r-- | net/core/skbuff.c | 18 | ||||
| -rw-r--r-- | net/core/sock.c | 11 | ||||
| -rw-r--r-- | net/core/xdp.c | 2 |
14 files changed, 82 insertions, 37 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index c285c6465923..173b5d97bd40 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -712,6 +712,9 @@ zerocopy_fill_skb_from_devmem(struct sk_buff *skb, struct iov_iter *from, size_t virt_addr, size, off; struct net_iov *niov; + if (i && skb_frags_readable(skb)) + return -EFAULT; + /* Devmem filling works by taking an IOVEC from the user where the * iov_addrs are interpreted as an offset in bytes into the dma-buf to * send from. We do not support other iter types. diff --git a/net/core/dev.c b/net/core/dev.c index 5933c5dab09e..af260ff5462a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -11494,6 +11494,7 @@ int register_netdevice(struct net_device *dev) * Prevent userspace races by waiting until the network * device is fully setup before sending notifications. */ + netdev_uevent_add(dev); if (!(dev->rtnl_link_ops && dev->rtnl_link_initializing)) rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL, 0, NULL); @@ -12435,6 +12436,7 @@ void unregister_netdevice_many_notify(struct list_head *head, dev_tcx_uninstall(dev); dev_xdp_uninstall(dev); dev_memory_provider_uninstall(dev); + netdev_work_cancel_all(dev); netdev_unlock_ops(dev); bpf_dev_bound_netdev_unregister(dev); diff --git a/net/core/dev.h b/net/core/dev.h index 5d0b0305d3ba..b757faead4d1 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -179,6 +179,7 @@ enum netdev_work_core { void __netdev_work_core_sched(struct net_device *dev, unsigned long event); unsigned long __netdev_work_core_cancel(struct net_device *dev, unsigned long mask); +void netdev_work_cancel_all(struct net_device *dev); void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, unsigned int gchanges, u32 portid, diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 2bf3cab5e557..abaf108ac4db 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -530,10 +530,10 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore, return; unlock_free: - spin_unlock_irqrestore(&data->drop_queue.lock, flags); u64_stats_update_begin(&data->stats.syncp); u64_stats_inc(&data->stats.dropped); u64_stats_update_end(&data->stats.syncp); + spin_unlock_irqrestore(&data->drop_queue.lock, flags); consume_skb(nskb); } @@ -566,13 +566,13 @@ static size_t net_dm_packet_report_size(size_t payload_len) /* NET_DM_ATTR_ORIGIN */ nla_total_size(sizeof(u16)) + /* NET_DM_ATTR_PC */ - nla_total_size(sizeof(u64)) + + nla_total_size_64bit(sizeof(u64)) + /* NET_DM_ATTR_SYMBOL */ nla_total_size(NET_DM_MAX_SYMBOL_LEN + 1) + /* NET_DM_ATTR_IN_PORT */ net_dm_in_port_size() + /* NET_DM_ATTR_TIMESTAMP */ - nla_total_size(sizeof(u64)) + + nla_total_size_64bit(sizeof(u64)) + /* NET_DM_ATTR_ORIG_LEN */ nla_total_size(sizeof(u32)) + /* NET_DM_ATTR_PROTO */ @@ -671,9 +671,7 @@ static int net_dm_packet_report_fill(struct sk_buff *msg, struct sk_buff *skb, if (nla_put_u16(msg, NET_DM_ATTR_PROTO, be16_to_cpu(skb->protocol))) goto nla_put_failure; - attr = skb_put(msg, nla_total_size(payload_len)); - attr->nla_type = NET_DM_ATTR_PAYLOAD; - attr->nla_len = nla_attr_size(payload_len); + attr = __nla_reserve(msg, NET_DM_ATTR_PAYLOAD, payload_len); if (skb_copy_bits(skb, 0, nla_data(attr), payload_len)) goto nla_put_failure; @@ -768,7 +766,7 @@ net_dm_hw_packet_report_size(size_t payload_len, /* NET_DM_ATTR_FLOW_ACTION_COOKIE */ net_dm_flow_action_cookie_size(hw_metadata) + /* NET_DM_ATTR_TIMESTAMP */ - nla_total_size(sizeof(u64)) + + nla_total_size_64bit(sizeof(u64)) + /* NET_DM_ATTR_ORIG_LEN */ nla_total_size(sizeof(u32)) + /* NET_DM_ATTR_PROTO */ @@ -831,9 +829,7 @@ static int net_dm_hw_packet_report_fill(struct sk_buff *msg, if (nla_put_u16(msg, NET_DM_ATTR_PROTO, be16_to_cpu(skb->protocol))) goto nla_put_failure; - attr = skb_put(msg, nla_total_size(payload_len)); - attr->nla_type = NET_DM_ATTR_PAYLOAD; - attr->nla_len = nla_attr_size(payload_len); + attr = __nla_reserve(msg, NET_DM_ATTR_PAYLOAD, payload_len); if (skb_copy_bits(skb, 0, nla_data(attr), payload_len)) goto nla_put_failure; @@ -1001,10 +997,10 @@ net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink, return; unlock_free: - spin_unlock_irqrestore(&hw_data->drop_queue.lock, flags); u64_stats_update_begin(&hw_data->stats.syncp); u64_stats_inc(&hw_data->stats.dropped); u64_stats_update_end(&hw_data->stats.syncp); + spin_unlock_irqrestore(&hw_data->drop_queue.lock, flags); net_dm_hw_metadata_free(n_hw_metadata); free: consume_skb(nskb); diff --git a/net/core/filter.c b/net/core/filter.c index b446aa8be5c3..16845987b244 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2552,11 +2552,13 @@ out_drop: BPF_CALL_2(bpf_redirect, u32, ifindex, u64, flags) { - struct bpf_redirect_info *ri = bpf_net_ctx_get_ri(); + struct bpf_redirect_info *ri; - if (unlikely(flags & (~(BPF_F_INGRESS) | BPF_F_REDIRECT_INTERNAL))) + if (unlikely(!bpf_net_ctx_get() || + (flags & (~(BPF_F_INGRESS) | BPF_F_REDIRECT_INTERNAL)))) return TC_ACT_SHOT; + ri = bpf_net_ctx_get_ri(); ri->flags = flags; ri->tgt_index = ifindex; @@ -2573,11 +2575,12 @@ static const struct bpf_func_proto bpf_redirect_proto = { BPF_CALL_2(bpf_redirect_peer, u32, ifindex, u64, flags) { - struct bpf_redirect_info *ri = bpf_net_ctx_get_ri(); + struct bpf_redirect_info *ri; - if (unlikely(flags)) + if (unlikely(!bpf_net_ctx_get() || flags)) return TC_ACT_SHOT; + ri = bpf_net_ctx_get_ri(); ri->flags = BPF_F_PEER; ri->tgt_index = ifindex; @@ -2595,11 +2598,13 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = { BPF_CALL_4(bpf_redirect_neigh, u32, ifindex, struct bpf_redir_neigh *, params, int, plen, u64, flags) { - struct bpf_redirect_info *ri = bpf_net_ctx_get_ri(); + struct bpf_redirect_info *ri; - if (unlikely((plen && plen < sizeof(*params)) || flags)) + if (unlikely((plen && plen < sizeof(*params)) || + !bpf_net_ctx_get() || flags)) return TC_ACT_SHOT; + ri = bpf_net_ctx_get_ri(); ri->flags = BPF_F_NEIGH | (plen ? BPF_F_NEXTHOP : 0); ri->tgt_index = ifindex; @@ -7679,7 +7684,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len return -EINVAL; /* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */ - if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies)) @@ -7752,7 +7757,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len, if (unlikely(!sk || th_len < sizeof(*th) || th_len != th->doff * 4)) return -EINVAL; - if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies)) diff --git a/net/core/gro.c b/net/core/gro.c index 35f2f708f010..29b4d02bf519 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -229,7 +229,9 @@ done: int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) { - if (unlikely(p->len + skb->len >= 65536)) + /* make sure to check flush flag and to not merge */ + if (unlikely(p->len + skb->len >= 65536 || + NAPI_GRO_CB(skb)->flush)) return -E2BIG; if (!pskb_may_pull(skb, skb_gro_offset(skb))) { diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index bf588f508b79..652952d416f2 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c @@ -255,8 +255,10 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) * if there is enough header space in skb. */ err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); - if (unlikely(err)) + if (unlikely(err)) { + dst_release(dst); goto err; + } skb_dst_drop(skb); skb_dst_set(skb, dst); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 0e71c9ed41e8..25546deacec8 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -2334,6 +2334,9 @@ int netdev_register_kobject(struct net_device *ndev) *groups++ = &wireless_group; #endif /* CONFIG_SYSFS */ + /* Hold back the KOBJ_ADD uevent until the device is listed. */ + dev_set_uevent_suppress(dev, 1); + error = device_add(dev); if (error) return error; @@ -2349,6 +2352,17 @@ int netdev_register_kobject(struct net_device *ndev) return error; } +/* Announce a fully registered device to userspace. This pairs with the uevent + * suppression from netdev_register_kobject(). + */ +void netdev_uevent_add(struct net_device *ndev) +{ + struct device *dev = &ndev->dev; + + dev_set_uevent_suppress(dev, 0); + kobject_uevent(&dev->kobj, KOBJ_ADD); +} + /* Change owner for sysfs entries when moving network devices across network * namespaces owned by different user namespaces. */ diff --git a/net/core/net-sysfs.h b/net/core/net-sysfs.h index 38e2e3ffd0bd..2f41a4dee866 100644 --- a/net/core/net-sysfs.h +++ b/net/core/net-sysfs.h @@ -4,6 +4,7 @@ int __init netdev_kobject_init(void); int netdev_register_kobject(struct net_device *); +void netdev_uevent_add(struct net_device *dev); void netdev_unregister_kobject(struct net_device *); int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num); int netdev_queue_update_kobjects(struct net_device *net, diff --git a/net/core/netdev_work.c b/net/core/netdev_work.c index 3109fae132ad..e721a06d58df 100644 --- a/net/core/netdev_work.c +++ b/net/core/netdev_work.c @@ -31,6 +31,10 @@ static void netdev_work_enqueue(struct net_device *dev, unsigned long events, return; spin_lock_bh(&netdev_work_lock); + if (!dev_isalive(dev)) { + spin_unlock_bh(&netdev_work_lock); + return; + } if (list_empty(&dev->work_node)) { list_add_tail(&dev->work_node, &netdev_work_list); netdev_hold(dev, &dev->work_tracker, GFP_ATOMIC); @@ -61,6 +65,18 @@ netdev_work_dequeue(struct net_device *dev, unsigned long *pending, return events; } +void netdev_work_cancel_all(struct net_device *dev) +{ + spin_lock_bh(&netdev_work_lock); + dev->work_pending = 0; + dev->work_core_pending = 0; + if (!list_empty(&dev->work_node)) { + list_del_init(&dev->work_node); + netdev_put(dev, &dev->work_tracker); + } + spin_unlock_bh(&netdev_work_lock); +} + void netdev_work_sched(struct net_device *dev, unsigned long events) { netdev_work_enqueue(dev, events, 0); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8e185b318288..ee64f3012321 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3972,6 +3972,7 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t, struct pktgen_dev *p; if_lock(t); + proc_remove(pkt_dev->entry); list_for_each_safe(q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list); if (p == pkt_dev) @@ -4001,9 +4002,6 @@ static int pktgen_remove_device(struct pktgen_thread *t, * list to determine if interface already exist, avoid race * with proc_create_data() */ - proc_remove(pkt_dev->entry); - - /* And update the thread if_list */ _rem_dev_from_if_list(t, pkt_dev); #ifdef CONFIG_XFRM diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 18dabb4e9cfa..ba3dbac80fb4 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -927,6 +927,18 @@ static void skb_clone_fraglist(struct sk_buff *skb) skb_get(list); } +/** + * skb_pp_cow_data() - copy skb data into page-pool backed storage + * @pool: page pool to allocate from + * @pskb: pointer to skb pointer, replaced with the copied skb on success + * @headroom: headroom to reserve in the copied skb + * + * skb_copy_bits() handles both frags[] and frag_list input. If the copied + * skb remains non-linear, it uses frags[], which is the representation used + * by XDP multi-buffer. + * + * Return: 0 on success or a negative errno on failure. + */ int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, unsigned int headroom) { @@ -936,12 +948,6 @@ int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb, int err, i, head_off; void *data; - /* XDP does not support fraglist so we need to linearize - * the skb. - */ - if (skb_has_frag_list(skb)) - return -EOPNOTSUPP; - max_head_size = SKB_WITH_OVERHEAD(PAGE_SIZE - headroom); if (skb->len > max_head_size + MAX_SKB_FRAGS * PAGE_SIZE) return -ENOMEM; diff --git a/net/core/sock.c b/net/core/sock.c index 498a57f34f5b..1ad41904db25 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -779,7 +779,6 @@ bool sk_mc_loop(const struct sock *sk) return inet6_test_bit(MC6_LOOP, sk); #endif } - WARN_ON_ONCE(1); return true; } EXPORT_SYMBOL(sk_mc_loop); @@ -2547,6 +2546,11 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority, cgroup_sk_clone(&newsk->sk_cgrp_data); + RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL); + + if (sock_needs_netstamp(sk) && newsk->sk_flags & SK_FLAGS_TIMESTAMP) + net_enable_timestamp(); + rcu_read_lock(); filter = rcu_dereference(sk->sk_filter); if (filter != NULL) @@ -2569,8 +2573,6 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority, goto free; } - RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL); - if (bpf_sk_storage_clone(sk, newsk)) goto free; @@ -2598,9 +2600,6 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority, if (newsk->sk_prot->sockets_allocated) sk_sockets_allocated_inc(newsk); - - if (sock_needs_netstamp(sk) && newsk->sk_flags & SK_FLAGS_TIMESTAMP) - net_enable_timestamp(); out: return newsk; free: diff --git a/net/core/xdp.c b/net/core/xdp.c index 9890a30584ba..0194e69da339 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -871,7 +871,7 @@ struct xdp_frame *xdpf_clone(struct xdp_frame *xdpf) headroom = xdpf->headroom + sizeof(*xdpf); totalsize = headroom + xdpf->len; - if (unlikely(totalsize > PAGE_SIZE)) + if (unlikely(totalsize > SKB_WITH_OVERHEAD(PAGE_SIZE))) return NULL; page = dev_alloc_page(); if (!page) |
