aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-10-26 21:30:55 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-26 21:30:55 -0400
commit1a51a47491a5a23f0625b03ad6dc84cf39bf6a82 (patch)
treed2089bedb4a4ff10a9f03c197a6e78966dfbb7a4
parent45f338069941f799ecc22e5a51b423da0b32459d (diff)
parent2afd23f78f39da84937006ecd24aa664a4ab052b (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Daniel Borkmann says: ==================== pull-request: bpf 2019-10-27 The following pull-request contains BPF updates for your *net* tree. We've added 7 non-merge commits during the last 11 day(s) which contain a total of 7 files changed, 66 insertions(+), 16 deletions(-). The main changes are: 1) Fix two use-after-free bugs in relation to RCU in jited symbol exposure to kallsyms, from Daniel Borkmann. 2) Fix NULL pointer dereference in AF_XDP rx-only sockets, from Magnus Karlsson. 3) Fix hang in netdev unregister for hash based devmap as well as another overflow bug on 32 bit archs in memlock cost calculation, from Toke Høiland-Jørgensen. 4) Fix wrong memory access in LWT BPF programs on reroute due to invalid dst. Also fix BPF selftests to use more compatible nc options, from Jiri Benc. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-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