1
0
Fork 0
remarkable-linux/net/sched
Paolo Abeni ebadf88828 cls_u32: fix use after free in u32_destroy_key()
[ Upstream commit d7cdee5ea8 ]

Li Shuang reported an Oops with cls_u32 due to an use-after-free
in u32_destroy_key(). The use-after-free can be triggered with:

dev=lo
tc qdisc add dev $dev root handle 1: htb default 10
tc filter add dev $dev parent 1: prio 5 handle 1: protocol ip u32 divisor 256
tc filter add dev $dev protocol ip parent 1: prio 5 u32 ht 800:: match ip dst\
 10.0.0.0/8 hashkey mask 0x0000ff00 at 16 link 1:
tc qdisc del dev $dev root

Which causes the following kasan splat:

 ==================================================================
 BUG: KASAN: use-after-free in u32_destroy_key.constprop.21+0x117/0x140 [cls_u32]
 Read of size 4 at addr ffff881b83dae618 by task kworker/u48:5/571

 CPU: 17 PID: 571 Comm: kworker/u48:5 Not tainted 4.15.0+ #87
 Hardware name: Dell Inc. PowerEdge R730/072T6D, BIOS 2.1.7 06/16/2016
 Workqueue: tc_filter_workqueue u32_delete_key_freepf_work [cls_u32]
 Call Trace:
  dump_stack+0xd6/0x182
  ? dma_virt_map_sg+0x22e/0x22e
  print_address_description+0x73/0x290
  kasan_report+0x277/0x360
  ? u32_destroy_key.constprop.21+0x117/0x140 [cls_u32]
  u32_destroy_key.constprop.21+0x117/0x140 [cls_u32]
  u32_delete_key_freepf_work+0x1c/0x30 [cls_u32]
  process_one_work+0xae0/0x1c80
  ? sched_clock+0x5/0x10
  ? pwq_dec_nr_in_flight+0x3c0/0x3c0
  ? _raw_spin_unlock_irq+0x29/0x40
  ? trace_hardirqs_on_caller+0x381/0x570
  ? _raw_spin_unlock_irq+0x29/0x40
  ? finish_task_switch+0x1e5/0x760
  ? finish_task_switch+0x208/0x760
  ? preempt_notifier_dec+0x20/0x20
  ? __schedule+0x839/0x1ee0
  ? check_noncircular+0x20/0x20
  ? firmware_map_remove+0x73/0x73
  ? find_held_lock+0x39/0x1c0
  ? worker_thread+0x434/0x1820
  ? lock_contended+0xee0/0xee0
  ? lock_release+0x1100/0x1100
  ? init_rescuer.part.16+0x150/0x150
  ? retint_kernel+0x10/0x10
  worker_thread+0x216/0x1820
  ? process_one_work+0x1c80/0x1c80
  ? lock_acquire+0x1a5/0x540
  ? lock_downgrade+0x6b0/0x6b0
  ? sched_clock+0x5/0x10
  ? lock_release+0x1100/0x1100
  ? compat_start_thread+0x80/0x80
  ? do_raw_spin_trylock+0x190/0x190
  ? _raw_spin_unlock_irq+0x29/0x40
  ? trace_hardirqs_on_caller+0x381/0x570
  ? _raw_spin_unlock_irq+0x29/0x40
  ? finish_task_switch+0x1e5/0x760
  ? finish_task_switch+0x208/0x760
  ? preempt_notifier_dec+0x20/0x20
  ? __schedule+0x839/0x1ee0
  ? kmem_cache_alloc_trace+0x143/0x320
  ? firmware_map_remove+0x73/0x73
  ? sched_clock+0x5/0x10
  ? sched_clock_cpu+0x18/0x170
  ? find_held_lock+0x39/0x1c0
  ? schedule+0xf3/0x3b0
  ? lock_downgrade+0x6b0/0x6b0
  ? __schedule+0x1ee0/0x1ee0
  ? do_wait_intr_irq+0x340/0x340
  ? do_raw_spin_trylock+0x190/0x190
  ? _raw_spin_unlock_irqrestore+0x32/0x60
  ? process_one_work+0x1c80/0x1c80
  ? process_one_work+0x1c80/0x1c80
  kthread+0x312/0x3d0
  ? kthread_create_worker_on_cpu+0xc0/0xc0
  ret_from_fork+0x3a/0x50

 Allocated by task 1688:
  kasan_kmalloc+0xa0/0xd0
  __kmalloc+0x162/0x380
  u32_change+0x1220/0x3c9e [cls_u32]
  tc_ctl_tfilter+0x1ba6/0x2f80
  rtnetlink_rcv_msg+0x4f0/0x9d0
  netlink_rcv_skb+0x124/0x320
  netlink_unicast+0x430/0x600
  netlink_sendmsg+0x8fa/0xd60
  sock_sendmsg+0xb1/0xe0
  ___sys_sendmsg+0x678/0x980
  __sys_sendmsg+0xc4/0x210
  do_syscall_64+0x232/0x7f0
  return_from_SYSCALL_64+0x0/0x75

 Freed by task 112:
  kasan_slab_free+0x71/0xc0
  kfree+0x114/0x320
  rcu_process_callbacks+0xc3f/0x1600
  __do_softirq+0x2bf/0xc06

 The buggy address belongs to the object at ffff881b83dae600
  which belongs to the cache kmalloc-4096 of size 4096
 The buggy address is located 24 bytes inside of
  4096-byte region [ffff881b83dae600, ffff881b83daf600)
 The buggy address belongs to the page:
 page:ffffea006e0f6a00 count:1 mapcount:0 mapping:          (null) index:0x0 compound_mapcount: 0
 flags: 0x17ffffc0008100(slab|head)
 raw: 0017ffffc0008100 0000000000000000 0000000000000000 0000000100070007
 raw: dead000000000100 dead000000000200 ffff880187c0e600 0000000000000000
 page dumped because: kasan: bad access detected

 Memory state around the buggy address:
  ffff881b83dae500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
  ffff881b83dae580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 >ffff881b83dae600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                             ^
  ffff881b83dae680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff881b83dae700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ==================================================================

The problem is that the htnode is freed before the linked knodes and the
latter will try to access the first at u32_destroy_key() time.
This change addresses the issue using the htnode refcnt to guarantee
the correct free order. While at it also add a RCU annotation,
to keep sparse happy.

v1 -> v2: use rtnl_derefence() instead of RCU read locks
v2 -> v3:
  - don't check refcnt in u32_destroy_hnode()
  - cleaned-up u32_destroy() implementation
  - cleaned-up code comment
v3 -> v4:
  - dropped unneeded comment

Reported-by: Li Shuang <shuali@redhat.com>
Fixes: c0d378ef12 ("net_sched: use tcf_queue_work() in u32 filter")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-03-08 22:41:16 -08:00
..
Kconfig net: sched: select cls when cls_act is enabled 2017-06-05 10:56:36 -04:00
Makefile License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
act_api.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_bpf.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_connmark.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_csum.c net: accept UFO datagrams from tuntap and packet 2017-12-17 15:07:58 +01:00
act_gact.c net/sched: Fix update of lastuse in act modules implementing stats_update 2018-01-17 09:45:22 +01:00
act_ife.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_ipt.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_meta_mark.c Support to encoding decoding skb mark on IFE action 2016-03-01 17:15:23 -05:00
act_meta_skbprio.c Support to encoding decoding skb prio on IFE action 2016-03-01 17:15:23 -05:00
act_meta_skbtcindex.c net sched ife action: Introduce skb tcindex metadata encap decap 2016-09-19 21:55:28 -04:00
act_mirred.c net/sched: Fix update of lastuse in act modules implementing stats_update 2018-01-17 09:45:22 +01:00
act_nat.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_pedit.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_police.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_sample.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_simple.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_skbedit.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_skbmod.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_tunnel_key.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
act_vlan.c Revert "net_sched: hold netns refcnt for each action" 2017-11-09 10:03:09 +09:00
cls_api.c net: sched: report if filter is too large to dump 2018-03-08 22:41:10 -08:00
cls_basic.c cls_basic: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:09 +09:00
cls_bpf.c cls_bpf: don't decrement net's refcount when offload fails 2017-12-17 15:07:59 +01:00
cls_cgroup.c cls_cgroup: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:09 +09:00
cls_flow.c cls_flow: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:09 +09:00
cls_flower.c cls_flower: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:09 +09:00
cls_fw.c cls_fw: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:09 +09:00
cls_matchall.c cls_matchall: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:10 +09:00
cls_route.c cls_route: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:10 +09:00
cls_rsvp.c
cls_rsvp.h cls_rsvp: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:10 +09:00
cls_rsvp6.c
cls_tcindex.c cls_tcindex: use tcf_exts_get_net() before call_rcu() 2017-11-09 10:03:10 +09:00
cls_u32.c cls_u32: fix use after free in u32_destroy_key() 2018-03-08 22:41:16 -08:00
em_canid.c net: sched: remove tcf_proto from ematch calls 2014-10-06 18:02:32 -04:00
em_cmp.c
em_ipset.c netfilter: x_tables: move hook state into xt_action_param structure 2016-11-03 10:56:21 +01:00
em_meta.c net: convert sock.sk_refcnt from atomic_t to refcount_t 2017-07-01 07:39:08 -07:00
em_nbyte.c net: sched: remove tcf_proto from ematch calls 2014-10-06 18:02:32 -04:00
em_text.c net: Remove state argument from skb_find_text() 2015-02-22 15:59:54 -05:00
em_u32.c
ematch.c netlink: pass extended ACK struct to parsing functions 2017-04-13 13:58:22 -04:00
sch_api.c net_sched: avoid matching qdisc with zero handle 2017-10-29 17:55:03 +09:00
sch_atm.c net_sched: remove tc class reference counting 2017-08-25 17:19:10 -07:00
sch_blackhole.c net_sched: drop packets after root qdisc lock is released 2016-06-25 12:19:35 -04:00
sch_cbq.c net: sched: cbq: create block for q->link.block 2017-12-17 15:07:58 +01:00
sch_choke.c net_sched: red: Avoid illegal values 2018-02-25 11:07:59 +01:00
sch_codel.c netlink: pass extended ACK struct to parsing functions 2017-04-13 13:58:22 -04:00
sch_drr.c net_sched: remove tc class reference counting 2017-08-25 17:19:10 -07:00
sch_dsmark.c net_sched: remove tc class reference counting 2017-08-25 17:19:10 -07:00
sch_fifo.c sched: don't use skb queue helpers 2016-09-19 01:47:18 -04:00
sch_fq.c mm, tree wide: replace __GFP_REPEAT by __GFP_RETRY_MAYFAIL with more useful semantic 2017-07-12 16:26:03 -07:00
sch_fq_codel.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-09-01 17:42:05 -07:00
sch_generic.c net_sched: always reset qdisc backlog in qdisc_reset() 2017-09-21 11:56:32 -07:00
sch_gred.c net_sched: red: Avoid illegal values 2018-02-25 11:07:59 +01:00
sch_hfsc.c net_sched/hfsc: fix curve activation in hfsc_change_class() 2017-09-21 11:56:32 -07:00
sch_hhf.c sch_hhf: fix null pointer dereference on init failure 2017-08-30 15:26:11 -07:00
sch_htb.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-09-01 17:42:05 -07:00
sch_ingress.c net: sched: fix static key imbalance in case of ingress/clsact_init error 2018-01-02 20:31:12 +01:00
sch_mq.c net_sched: remove tc class reference counting 2017-08-25 17:19:10 -07:00
sch_mqprio.c net_sched: remove tc class reference counting 2017-08-25 17:19:10 -07:00
sch_multiq.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-09-01 17:42:05 -07:00
sch_netem.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-09-01 17:42:05 -07:00
sch_pie.c netlink: pass extended ACK struct to parsing functions 2017-04-13 13:58:22 -04:00
sch_plug.c net_sched: drop packets after root qdisc lock is released 2016-06-25 12:19:35 -04:00
sch_prio.c sched: Use __qdisc_drop instead of kfree_skb in sch_prio and sch_qfq 2017-09-06 21:20:07 -07:00
sch_qfq.c sched: Use __qdisc_drop instead of kfree_skb in sch_prio and sch_qfq 2017-09-06 21:20:07 -07:00
sch_red.c net_sched: red: Avoid illegal values 2018-02-25 11:07:59 +01:00
sch_sfb.c net_sched: remove tc class reference counting 2017-08-25 17:19:10 -07:00
sch_sfq.c net_sched: red: Avoid illegal values 2018-02-25 11:07:59 +01:00
sch_tbf.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-09-01 17:42:05 -07:00
sch_teql.c net: make ndo_get_stats64 a void function 2017-01-08 17:51:44 -05:00