diff options
-rw-r--r-- | include/linux/filter.h | 1 | ||||
-rw-r--r-- | kernel/bpf/core.c | 2 | ||||
-rw-r--r-- | kernel/bpf/devmap.c | 33 | ||||
-rw-r--r-- | kernel/bpf/syscall.c | 31 | ||||
-rw-r--r-- | net/core/lwt_bpf.c | 7 | ||||
-rw-r--r-- | net/xdp/xdp_umem.c | 6 | ||||
-rwxr-xr-x | tools/testing/selftests/bpf/test_tc_edt.sh | 2 |
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 | ||
1102 | void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp); | ||
1103 | void bpf_prog_kallsyms_del_all(struct bpf_prog *fp); | 1102 | void 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 | ||
505 | void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp) | 505 | static 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 | ||
722 | static 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 | |||
722 | static int dev_map_notification(struct notifier_block *notifier, | 748 | static 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 | ||
1336 | static 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 | |||
1335 | static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) | 1348 | static 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 | ||
1743 | free_used_maps: | 1751 | free_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; | ||
1749 | free_prog: | 1758 | free_prog: |
1750 | bpf_prog_uncharge_memlock(prog); | 1759 | bpf_prog_uncharge_memlock(prog); |
1751 | free_prog_sec: | 1760 | free_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 |
61 | ip netns exec ${NS_DST} bash -c \ | 61 | ip 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 &" |
63 | declare -i NC_PID=$! | 63 | declare -i NC_PID=$! |
64 | sleep 1 | 64 | sleep 1 |
65 | 65 | ||