From 60046aef369c93272dba360b87353feefca34cd6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Jul 2017 10:33:58 +0200 Subject: [PATCH] 4.9-stable patches added patches: bpf-prevent-leaking-pointer-via-xadd-on-unpriviledged.patch liquidio-fix-bug-in-soft-reset-failure-detection.patch net-handle-napi_gro_free_stolen_head-case-also-in-napi_frags_finish.patch net-mlx5-cancel-delayed-recovery-work-when-unloading-the-driver.patch rocker-move-dereference-before-free.patch --- ...ng-pointer-via-xadd-on-unpriviledged.patch | 80 +++++++++++++++ ...-bug-in-soft-reset-failure-detection.patch | 51 ++++++++++ ..._head-case-also-in-napi_frags_finish.patch | 85 ++++++++++++++++ ...overy-work-when-unloading-the-driver.patch | 97 +++++++++++++++++++ .../rocker-move-dereference-before-free.patch | 33 +++++++ queue-4.9/series | 5 + 6 files changed, 351 insertions(+) create mode 100644 queue-4.9/bpf-prevent-leaking-pointer-via-xadd-on-unpriviledged.patch create mode 100644 queue-4.9/liquidio-fix-bug-in-soft-reset-failure-detection.patch create mode 100644 queue-4.9/net-handle-napi_gro_free_stolen_head-case-also-in-napi_frags_finish.patch create mode 100644 queue-4.9/net-mlx5-cancel-delayed-recovery-work-when-unloading-the-driver.patch create mode 100644 queue-4.9/rocker-move-dereference-before-free.patch diff --git a/queue-4.9/bpf-prevent-leaking-pointer-via-xadd-on-unpriviledged.patch b/queue-4.9/bpf-prevent-leaking-pointer-via-xadd-on-unpriviledged.patch new file mode 100644 index 00000000000..1147178d496 --- /dev/null +++ b/queue-4.9/bpf-prevent-leaking-pointer-via-xadd-on-unpriviledged.patch @@ -0,0 +1,80 @@ +From 6bdf6abc56b53103324dfd270a86580306e1a232 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 29 Jun 2017 03:04:59 +0200 +Subject: bpf: prevent leaking pointer via xadd on unpriviledged + +From: Daniel Borkmann + +commit 6bdf6abc56b53103324dfd270a86580306e1a232 upstream. + +Leaking kernel addresses on unpriviledged is generally disallowed, +for example, verifier rejects the following: + + 0: (b7) r0 = 0 + 1: (18) r2 = 0xffff897e82304400 + 3: (7b) *(u64 *)(r1 +48) = r2 + R2 leaks addr into ctx + +Doing pointer arithmetic on them is also forbidden, so that they +don't turn into unknown value and then get leaked out. However, +there's xadd as a special case, where we don't check the src reg +for being a pointer register, e.g. the following will pass: + + 0: (b7) r0 = 0 + 1: (7b) *(u64 *)(r1 +48) = r0 + 2: (18) r2 = 0xffff897e82304400 ; map + 4: (db) lock *(u64 *)(r1 +48) += r2 + 5: (95) exit + +We could store the pointer into skb->cb, loose the type context, +and then read it out from there again to leak it eventually out +of a map value. Or more easily in a different variant, too: + + 0: (bf) r6 = r1 + 1: (7a) *(u64 *)(r10 -8) = 0 + 2: (bf) r2 = r10 + 3: (07) r2 += -8 + 4: (18) r1 = 0x0 + 6: (85) call bpf_map_lookup_elem#1 + 7: (15) if r0 == 0x0 goto pc+3 + R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R6=ctx R10=fp + 8: (b7) r3 = 0 + 9: (7b) *(u64 *)(r0 +0) = r3 + 10: (db) lock *(u64 *)(r0 +0) += r6 + 11: (b7) r0 = 0 + 12: (95) exit + + from 7 to 11: R0=inv,min_value=0,max_value=0 R6=ctx R10=fp + 11: (b7) r0 = 0 + 12: (95) exit + +Prevent this by checking xadd src reg for pointer types. Also +add a couple of test cases related to this. + +Fixes: 1be7f75d1668 ("bpf: enable non-root eBPF programs") +Fixes: 17a5267067f3 ("bpf: verifier (add verifier core)") +Signed-off-by: Daniel Borkmann +Acked-by: Alexei Starovoitov +Acked-by: Martin KaFai Lau +Acked-by: Edward Cree +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/bpf/verifier.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -885,6 +885,11 @@ static int check_xadd(struct bpf_verifie + if (err) + return err; + ++ if (is_pointer_value(env, insn->src_reg)) { ++ verbose("R%d leaks addr into mem\n", insn->src_reg); ++ return -EACCES; ++ } ++ + /* check whether atomic_add can read the memory */ + err = check_mem_access(env, insn->dst_reg, insn->off, + BPF_SIZE(insn->code), BPF_READ, -1); diff --git a/queue-4.9/liquidio-fix-bug-in-soft-reset-failure-detection.patch b/queue-4.9/liquidio-fix-bug-in-soft-reset-failure-detection.patch new file mode 100644 index 00000000000..10e00501054 --- /dev/null +++ b/queue-4.9/liquidio-fix-bug-in-soft-reset-failure-detection.patch @@ -0,0 +1,51 @@ +From 05a6b4cae8c0cc1680c9dd33a97a49a13c0f01bc Mon Sep 17 00:00:00 2001 +From: Derek Chickles +Date: Wed, 5 Jul 2017 11:59:27 -0700 +Subject: liquidio: fix bug in soft reset failure detection + +From: Derek Chickles + +commit 05a6b4cae8c0cc1680c9dd33a97a49a13c0f01bc upstream. + +The code that detects a failed soft reset of Octeon is comparing the wrong +value against the reset value of the Octeon SLI_SCRATCH_1 register, +resulting in an inability to detect a soft reset failure. Fix it by using +the correct value in the comparison, which is any non-zero value. + +Fixes: f21fb3ed364b ("Add support of Cavium Liquidio ethernet adapters") +Fixes: c0eab5b3580a ("liquidio: CN23XX firmware download") +Signed-off-by: Derek Chickles +Signed-off-by: Satanand Burla +Signed-off-by: Raghu Vatsavayi +Signed-off-by: Felix Manlunas +Reviewed-by: Leon Romanovsky +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c | 2 +- + drivers/net/ethernet/cavium/liquidio/cn66xx_device.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c ++++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +@@ -230,7 +230,7 @@ static int cn23xx_pf_soft_reset(struct o + /* Wait for 100ms as Octeon resets. */ + mdelay(100); + +- if (octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1) == 0x1234ULL) { ++ if (octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1)) { + dev_err(&oct->pci_dev->dev, "OCTEON[%d]: Soft reset failed\n", + oct->octeon_id); + return 1; +--- a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c ++++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c +@@ -48,7 +48,7 @@ int lio_cn6xxx_soft_reset(struct octeon_ + /* Wait for 10ms as Octeon resets. */ + mdelay(100); + +- if (octeon_read_csr64(oct, CN6XXX_SLI_SCRATCH1) == 0x1234ULL) { ++ if (octeon_read_csr64(oct, CN6XXX_SLI_SCRATCH1)) { + dev_err(&oct->pci_dev->dev, "Soft reset failed\n"); + return 1; + } diff --git a/queue-4.9/net-handle-napi_gro_free_stolen_head-case-also-in-napi_frags_finish.patch b/queue-4.9/net-handle-napi_gro_free_stolen_head-case-also-in-napi_frags_finish.patch new file mode 100644 index 00000000000..34835e86195 --- /dev/null +++ b/queue-4.9/net-handle-napi_gro_free_stolen_head-case-also-in-napi_frags_finish.patch @@ -0,0 +1,85 @@ +From e44699d2c28067f69698ccb68dd3ddeacfebc434 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= +Date: Thu, 29 Jun 2017 11:13:36 +0200 +Subject: net: handle NAPI_GRO_FREE_STOLEN_HEAD case also in napi_frags_finish() + +From: Michal Kubeček + +commit e44699d2c28067f69698ccb68dd3ddeacfebc434 upstream. + +Recently I started seeing warnings about pages with refcount -1. The +problem was traced to packets being reused after their head was merged into +a GRO packet by skb_gro_receive(). While bisecting the issue pointed to +commit c21b48cc1bbf ("net: adjust skb->truesize in ___pskb_trim()") and +I have never seen it on a kernel with it reverted, I believe the real +problem appeared earlier when the option to merge head frag in GRO was +implemented. + +Handling NAPI_GRO_FREE_STOLEN_HEAD state was only added to GRO_MERGED_FREE +branch of napi_skb_finish() so that if the driver uses napi_gro_frags() +and head is merged (which in my case happens after the skb_condense() +call added by the commit mentioned above), the skb is reused including the +head that has been merged. As a result, we release the page reference +twice and eventually end up with negative page refcount. + +To fix the problem, handle NAPI_GRO_FREE_STOLEN_HEAD in napi_frags_finish() +the same way it's done in napi_skb_finish(). + +Fixes: d7e8883cfcf4 ("net: make GRO aware of skb->head_frag") +Signed-off-by: Michal Kubecek +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/core/dev.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4641,6 +4641,12 @@ struct packet_offload *gro_find_complete + } + EXPORT_SYMBOL(gro_find_complete_by_type); + ++static void napi_skb_free_stolen_head(struct sk_buff *skb) ++{ ++ skb_dst_drop(skb); ++ kmem_cache_free(skbuff_head_cache, skb); ++} ++ + static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) + { + switch (ret) { +@@ -4654,12 +4660,10 @@ static gro_result_t napi_skb_finish(gro_ + break; + + case GRO_MERGED_FREE: +- if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) { +- skb_dst_drop(skb); +- kmem_cache_free(skbuff_head_cache, skb); +- } else { ++ if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) ++ napi_skb_free_stolen_head(skb); ++ else + __kfree_skb(skb); +- } + break; + + case GRO_HELD: +@@ -4729,10 +4733,16 @@ static gro_result_t napi_frags_finish(st + break; + + case GRO_DROP: +- case GRO_MERGED_FREE: + napi_reuse_skb(napi, skb); + break; + ++ case GRO_MERGED_FREE: ++ if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) ++ napi_skb_free_stolen_head(skb); ++ else ++ napi_reuse_skb(napi, skb); ++ break; ++ + case GRO_MERGED: + break; + } diff --git a/queue-4.9/net-mlx5-cancel-delayed-recovery-work-when-unloading-the-driver.patch b/queue-4.9/net-mlx5-cancel-delayed-recovery-work-when-unloading-the-driver.patch new file mode 100644 index 00000000000..e1d4b29ccbf --- /dev/null +++ b/queue-4.9/net-mlx5-cancel-delayed-recovery-work-when-unloading-the-driver.patch @@ -0,0 +1,97 @@ +From 2a0165a034ac024b60cca49c61e46f4afa2e4d98 Mon Sep 17 00:00:00 2001 +From: Mohamad Haj Yahia +Date: Thu, 30 Mar 2017 17:09:00 +0300 +Subject: net/mlx5: Cancel delayed recovery work when unloading the driver + +From: Mohamad Haj Yahia + +commit 2a0165a034ac024b60cca49c61e46f4afa2e4d98 upstream. + +Draining the health workqueue will ignore future health works including +the one that report hardware failure and thus we can't enter error state +Instead cancel the recovery flow and make sure only recovery flow won't +be scheduled. + +Fixes: 5e44fca50470 ('net/mlx5: Only cancel recovery work when cleaning up device') +Signed-off-by: Mohamad Haj Yahia +Signed-off-by: Moshe Shemesh +Signed-off-by: Saeed Mahameed +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/ethernet/mellanox/mlx5/core/health.c | 15 ++++++++++++++- + drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- + include/linux/mlx5/driver.h | 1 + + 3 files changed, 16 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c +@@ -67,6 +67,7 @@ enum { + + enum { + MLX5_DROP_NEW_HEALTH_WORK, ++ MLX5_DROP_NEW_RECOVERY_WORK, + }; + + static u8 get_nic_state(struct mlx5_core_dev *dev) +@@ -193,7 +194,7 @@ static void health_care(struct work_stru + mlx5_handle_bad_state(dev); + + spin_lock(&health->wq_lock); +- if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) ++ if (!test_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags)) + schedule_delayed_work(&health->recover_work, recover_delay); + else + dev_err(&dev->pdev->dev, +@@ -328,6 +329,7 @@ void mlx5_start_health_poll(struct mlx5_ + init_timer(&health->timer); + health->sick = 0; + clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); ++ clear_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); + health->health = &dev->iseg->health; + health->health_counter = &dev->iseg->health_counter; + +@@ -350,11 +352,22 @@ void mlx5_drain_health_wq(struct mlx5_co + + spin_lock(&health->wq_lock); + set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); ++ set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); + spin_unlock(&health->wq_lock); + cancel_delayed_work_sync(&health->recover_work); + cancel_work_sync(&health->work); + } + ++void mlx5_drain_health_recovery(struct mlx5_core_dev *dev) ++{ ++ struct mlx5_core_health *health = &dev->priv.health; ++ ++ spin_lock(&health->wq_lock); ++ set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); ++ spin_unlock(&health->wq_lock); ++ cancel_delayed_work_sync(&dev->priv.health.recover_work); ++} ++ + void mlx5_health_cleanup(struct mlx5_core_dev *dev) + { + struct mlx5_core_health *health = &dev->priv.health; +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -1169,7 +1169,7 @@ static int mlx5_unload_one(struct mlx5_c + int err = 0; + + if (cleanup) +- mlx5_drain_health_wq(dev); ++ mlx5_drain_health_recovery(dev); + + mutex_lock(&dev->intf_state_mutex); + if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) { +--- a/include/linux/mlx5/driver.h ++++ b/include/linux/mlx5/driver.h +@@ -788,6 +788,7 @@ int mlx5_health_init(struct mlx5_core_de + void mlx5_start_health_poll(struct mlx5_core_dev *dev); + void mlx5_stop_health_poll(struct mlx5_core_dev *dev); + void mlx5_drain_health_wq(struct mlx5_core_dev *dev); ++void mlx5_drain_health_recovery(struct mlx5_core_dev *dev); + int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, + struct mlx5_buf *buf, int node); + int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf); diff --git a/queue-4.9/rocker-move-dereference-before-free.patch b/queue-4.9/rocker-move-dereference-before-free.patch new file mode 100644 index 00000000000..781fc055158 --- /dev/null +++ b/queue-4.9/rocker-move-dereference-before-free.patch @@ -0,0 +1,33 @@ +From acb4b7df48b539cb391287921de57e4e5fae3460 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 28 Jun 2017 14:44:21 +0300 +Subject: rocker: move dereference before free + +From: Dan Carpenter + +commit acb4b7df48b539cb391287921de57e4e5fae3460 upstream. + +My static checker complains that ofdpa_neigh_del() can sometimes free +"found". It just makes sense to use it first before deleting it. + +Fixes: ecf244f753e0 ("rocker: fix maybe-uninitialized warning") +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c ++++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c +@@ -1505,8 +1505,8 @@ static int ofdpa_port_ipv4_nh(struct ofd + *index = entry->index; + resolved = false; + } else if (removing) { +- ofdpa_neigh_del(trans, found); + *index = found->index; ++ ofdpa_neigh_del(trans, found); + } else if (updating) { + ofdpa_neigh_update(found, trans, NULL, false); + resolved = !is_zero_ether_addr(found->eth_dst); diff --git a/queue-4.9/series b/queue-4.9/series index 770727eb557..bf49ecaa937 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -7,3 +7,8 @@ net-dp83640-avoid-null-pointer-dereference.patch tcp-reset-sk_rx_dst-in-tcp_disconnect.patch net-prevent-sign-extension-in-dev_get_stats.patch bridge-mdb-fix-leak-on-complete_info-ptr-on-fail-path.patch +rocker-move-dereference-before-free.patch +bpf-prevent-leaking-pointer-via-xadd-on-unpriviledged.patch +net-handle-napi_gro_free_stolen_head-case-also-in-napi_frags_finish.patch +net-mlx5-cancel-delayed-recovery-work-when-unloading-the-driver.patch +liquidio-fix-bug-in-soft-reset-failure-detection.patch -- 2.47.3