aboutsummaryrefslogtreecommitdiff
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/datagram.c3
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/dev.h1
-rw-r--r--net/core/drop_monitor.c18
-rw-r--r--net/core/filter.c21
-rw-r--r--net/core/gro.c4
-rw-r--r--net/core/lwt_bpf.c4
-rw-r--r--net/core/net-sysfs.c14
-rw-r--r--net/core/net-sysfs.h1
-rw-r--r--net/core/netdev_work.c16
-rw-r--r--net/core/pktgen.c4
-rw-r--r--net/core/skbuff.c18
-rw-r--r--net/core/sock.c11
-rw-r--r--net/core/xdp.c2
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)