aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/filter.h1
-rw-r--r--kernel/bpf/core.c2
-rw-r--r--kernel/bpf/devmap.c33
-rw-r--r--kernel/bpf/syscall.c31
-rw-r--r--net/core/lwt_bpf.c7
-rw-r--r--net/xdp/xdp_umem.c6
-rwxr-xr-xtools/testing/selftests/bpf/test_tc_edt.sh2
7 files changed, 66 insertions, 16 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 2ce57645f3cd..0367a75f873b 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1099,7 +1099,6 @@ static inline void bpf_get_prog_name(const struct bpf_prog *prog, char *sym)
1099 1099
1100#endif /* CONFIG_BPF_JIT */ 1100#endif /* CONFIG_BPF_JIT */
1101 1101
1102void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp);
1103void bpf_prog_kallsyms_del_all(struct bpf_prog *fp); 1102void bpf_prog_kallsyms_del_all(struct bpf_prog *fp);
1104 1103
1105#define BPF_ANC BIT(15) 1104#define BPF_ANC BIT(15)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 66088a9e9b9e..ef0e1e3e66f4 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -502,7 +502,7 @@ int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt)
502 return WARN_ON_ONCE(bpf_adj_branches(prog, off, off + cnt, off, false)); 502 return WARN_ON_ONCE(bpf_adj_branches(prog, off, off + cnt, off, false));
503} 503}
504 504
505void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp) 505static void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp)
506{ 506{
507 int i; 507 int i;
508 508
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index d27f3b60ff6d..3867864cdc2f 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -128,7 +128,7 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr)
128 128
129 if (!dtab->n_buckets) /* Overflow check */ 129 if (!dtab->n_buckets) /* Overflow check */
130 return -EINVAL; 130 return -EINVAL;
131 cost += sizeof(struct hlist_head) * dtab->n_buckets; 131 cost += (u64) sizeof(struct hlist_head) * dtab->n_buckets;
132 } 132 }
133 133
134 /* if map size is larger than memlock limit, reject it */ 134 /* if map size is larger than memlock limit, reject it */
@@ -719,6 +719,32 @@ const struct bpf_map_ops dev_map_hash_ops = {
719 .map_check_btf = map_check_no_btf, 719 .map_check_btf = map_check_no_btf,
720}; 720};
721 721
722static void dev_map_hash_remove_netdev(struct bpf_dtab *dtab,
723 struct net_device *netdev)
724{
725 unsigned long flags;
726 u32 i;
727
728 spin_lock_irqsave(&dtab->index_lock, flags);
729 for (i = 0; i < dtab->n_buckets; i++) {
730 struct bpf_dtab_netdev *dev;
731 struct hlist_head *head;
732 struct hlist_node *next;
733
734 head = dev_map_index_hash(dtab, i);
735
736 hlist_for_each_entry_safe(dev, next, head, index_hlist) {
737 if (netdev != dev->dev)
738 continue;
739
740 dtab->items--;
741 hlist_del_rcu(&dev->index_hlist);
742 call_rcu(&dev->rcu, __dev_map_entry_free);
743 }
744 }
745 spin_unlock_irqrestore(&dtab->index_lock, flags);
746}
747
722static int dev_map_notification(struct notifier_block *notifier, 748static int dev_map_notification(struct notifier_block *notifier,
723 ulong event, void *ptr) 749 ulong event, void *ptr)
724{ 750{
@@ -735,6 +761,11 @@ static int dev_map_notification(struct notifier_block *notifier,
735 */ 761 */
736 rcu_read_lock(); 762 rcu_read_lock();
737 list_for_each_entry_rcu(dtab, &dev_map_list, list) { 763 list_for_each_entry_rcu(dtab, &dev_map_list, list) {
764 if (dtab->map.map_type == BPF_MAP_TYPE_DEVMAP_HASH) {
765 dev_map_hash_remove_netdev(dtab, netdev);
766 continue;
767 }
768
738 for (i = 0; i < dtab->map.max_entries; i++) { 769 for (i = 0; i < dtab->map.max_entries; i++) {
739 struct bpf_dtab_netdev *dev, *odev; 770 struct bpf_dtab_netdev *dev, *odev;
740 771
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 82eabd4e38ad..0937719b87e2 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1326,24 +1326,32 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
1326{ 1326{
1327 struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 1327 struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
1328 1328
1329 kvfree(aux->func_info);
1329 free_used_maps(aux); 1330 free_used_maps(aux);
1330 bpf_prog_uncharge_memlock(aux->prog); 1331 bpf_prog_uncharge_memlock(aux->prog);
1331 security_bpf_prog_free(aux); 1332 security_bpf_prog_free(aux);
1332 bpf_prog_free(aux->prog); 1333 bpf_prog_free(aux->prog);
1333} 1334}
1334 1335
1336static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
1337{
1338 bpf_prog_kallsyms_del_all(prog);
1339 btf_put(prog->aux->btf);
1340 bpf_prog_free_linfo(prog);
1341
1342 if (deferred)
1343 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
1344 else
1345 __bpf_prog_put_rcu(&prog->aux->rcu);
1346}
1347
1335static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 1348static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
1336{ 1349{
1337 if (atomic_dec_and_test(&prog->aux->refcnt)) { 1350 if (atomic_dec_and_test(&prog->aux->refcnt)) {
1338 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0); 1351 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
1339 /* bpf_prog_free_id() must be called first */ 1352 /* bpf_prog_free_id() must be called first */
1340 bpf_prog_free_id(prog, do_idr_lock); 1353 bpf_prog_free_id(prog, do_idr_lock);
1341 bpf_prog_kallsyms_del_all(prog); 1354 __bpf_prog_put_noref(prog, true);
1342 btf_put(prog->aux->btf);
1343 kvfree(prog->aux->func_info);
1344 bpf_prog_free_linfo(prog);
1345
1346 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
1347 } 1355 }
1348} 1356}
1349 1357
@@ -1741,11 +1749,12 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
1741 return err; 1749 return err;
1742 1750
1743free_used_maps: 1751free_used_maps:
1744 bpf_prog_free_linfo(prog); 1752 /* In case we have subprogs, we need to wait for a grace
1745 kvfree(prog->aux->func_info); 1753 * period before we can tear down JIT memory since symbols
1746 btf_put(prog->aux->btf); 1754 * are already exposed under kallsyms.
1747 bpf_prog_kallsyms_del_subprogs(prog); 1755 */
1748 free_used_maps(prog->aux); 1756 __bpf_prog_put_noref(prog, prog->aux->func_cnt);
1757 return err;
1749free_prog: 1758free_prog:
1750 bpf_prog_uncharge_memlock(prog); 1759 bpf_prog_uncharge_memlock(prog);
1751free_prog_sec: 1760free_prog_sec:
diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
index f93785e5833c..74cfb8b5ab33 100644
--- a/net/core/lwt_bpf.c
+++ b/net/core/lwt_bpf.c
@@ -88,11 +88,16 @@ static int bpf_lwt_input_reroute(struct sk_buff *skb)
88 int err = -EINVAL; 88 int err = -EINVAL;
89 89
90 if (skb->protocol == htons(ETH_P_IP)) { 90 if (skb->protocol == htons(ETH_P_IP)) {
91 struct net_device *dev = skb_dst(skb)->dev;
91 struct iphdr *iph = ip_hdr(skb); 92 struct iphdr *iph = ip_hdr(skb);
92 93
94 dev_hold(dev);
95 skb_dst_drop(skb);
93 err = ip_route_input_noref(skb, iph->daddr, iph->saddr, 96 err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
94 iph->tos, skb_dst(skb)->dev); 97 iph->tos, dev);
98 dev_put(dev);
95 } else if (skb->protocol == htons(ETH_P_IPV6)) { 99 } else if (skb->protocol == htons(ETH_P_IPV6)) {
100 skb_dst_drop(skb);
96 err = ipv6_stub->ipv6_route_input(skb); 101 err = ipv6_stub->ipv6_route_input(skb);
97 } else { 102 } else {
98 err = -EAFNOSUPPORT; 103 err = -EAFNOSUPPORT;
diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
index 16d5f353163a..3049af269fbf 100644
--- a/net/xdp/xdp_umem.c
+++ b/net/xdp/xdp_umem.c
@@ -27,6 +27,9 @@ void xdp_add_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs)
27{ 27{
28 unsigned long flags; 28 unsigned long flags;
29 29
30 if (!xs->tx)
31 return;
32
30 spin_lock_irqsave(&umem->xsk_list_lock, flags); 33 spin_lock_irqsave(&umem->xsk_list_lock, flags);
31 list_add_rcu(&xs->list, &umem->xsk_list); 34 list_add_rcu(&xs->list, &umem->xsk_list);
32 spin_unlock_irqrestore(&umem->xsk_list_lock, flags); 35 spin_unlock_irqrestore(&umem->xsk_list_lock, flags);
@@ -36,6 +39,9 @@ void xdp_del_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs)
36{ 39{
37 unsigned long flags; 40 unsigned long flags;
38 41
42 if (!xs->tx)
43 return;
44
39 spin_lock_irqsave(&umem->xsk_list_lock, flags); 45 spin_lock_irqsave(&umem->xsk_list_lock, flags);
40 list_del_rcu(&xs->list); 46 list_del_rcu(&xs->list);
41 spin_unlock_irqrestore(&umem->xsk_list_lock, flags); 47 spin_unlock_irqrestore(&umem->xsk_list_lock, flags);
diff --git a/tools/testing/selftests/bpf/test_tc_edt.sh b/tools/testing/selftests/bpf/test_tc_edt.sh
index f38567ef694b..daa7d1b8d309 100755
--- a/tools/testing/selftests/bpf/test_tc_edt.sh
+++ b/tools/testing/selftests/bpf/test_tc_edt.sh
@@ -59,7 +59,7 @@ ip netns exec ${NS_SRC} tc filter add dev veth_src egress \
59 59
60# start the listener 60# start the listener
61ip netns exec ${NS_DST} bash -c \ 61ip netns exec ${NS_DST} bash -c \
62 "nc -4 -l -s ${IP_DST} -p 9000 >/dev/null &" 62 "nc -4 -l -p 9000 >/dev/null &"
63declare -i NC_PID=$! 63declare -i NC_PID=$!
64sleep 1 64sleep 1
65 65