Re: [PATCH v2 6/8] arm64: Import latest memcpy()/memmove() implementation

2 messages, 2 authors, 2021-09-10 · open the first message on its own page

Re: [PATCH v2 6/8] arm64: Import latest memcpy()/memmove() implementation

From: Robin Murphy <robin.murphy@arm.com>
Date: 2021-09-10 11:44:37

On 2021-09-10 01:35, Peter Collingbourne wrote:
Hi Robin,

(apologies for breaking the threading, I wasn't subscribed to
linux-arm-kernel when you sent this)

It looks like this patch breaks the KASAN unit tests when running in
HW tags mode. You can construct a config that reproduces the problem
with something like:

make O=out defconfig
scripts/config --file out/.config -e CONFIG_KUNIT -e CONFIG_KASAN -e
CONFIG_KASAN_HW_TAGS -e CONFIG_KASAN_KUNIT_TEST
yes '' | make O=out syncconfig

With that the "kmalloc_memmove_invalid_size" test fails and causes the
kernel panic below.

What appears to be going on is that whereas the old memcpy
implementation ends up returning early after not copying very much
data if supplied a "negative" size as a side effect of using
conditional branches that implement signed comparisons (e.g. b.ge on
line 75), the new implementation does not exit early and attempts to
copy a large amount of data backwards 4 bytes (after having disabled
MTE early on as a result of a tag mismatch) until it hits a read-only
page and causes a panic.
If the test depends on the implementation of memmove() being buggy, it's clearly not a very good test :/
I'm not sure what the correct fix should be. It seems that at least
when KASAN is enabled we should be able to catch these invalid memcpys
somehow, print an error report and ideally abort the entire operation.
But we should do so without causing a performance impact in the usual
case.
Not sure I follow - the top of the log below clearly shows that KASASN *is* detecting and reporting a bad access. The fact that code intended to deliberately corrupt memory goes on to corrupt memory doesn't seem particularly surprising to me. A bug exists (intentionally or otherwise) which led to that invalid access being attempted, and KASAN can't magically change that.

Robin.
Peter

[    7.726311] ==================================================================
[    7.726817] BUG: KASAN: invalid-access in __memcpy+0x1a0/0x230
[    7.727310] Read at addr f8ff000002650ef2 by task kunit_try_catch/117
[    7.727828] Pointer tag: [f8], memory tag: [fe]
[    7.728209]
[    7.728419] CPU: 0 PID: 117 Comm: kunit_try_catch Tainted: G    B
           5.14.0-rc3-00011-g7a062ce31807-dirty #1
[    7.729186] Hardware name: linux,dummy-virt (DT)
[    7.729568] Call trace:
[    7.729817]  dump_backtrace+0x0/0x1cc
[    7.730191]  show_stack+0x18/0x24
[    7.730543]  dump_stack_lvl+0x64/0x7c
[    7.730917]  print_address_description+0x7c/0x1e0
[    7.731336]  __kasan_report+0x228/0x30c
[    7.731718]  kasan_report+0x44/0x70
[    7.732076]  __do_kernel_fault+0xbc/0x248
[    7.732464]  do_tag_check_fault+0x38/0xfc
[    7.732862]  do_mem_abort+0x40/0xb4
[    7.733223]  el1_abort+0x40/0x60
[    7.733568]  el1h_64_sync_handler+0x5c/0x98
[    7.733964]  el1h_64_sync+0x78/0x7c
[    7.734327]  __memcpy+0x1a0/0x230
[    7.734684]  kunit_try_run_case+0x48/0x108
[    7.735073]  kunit_generic_run_threadfn_adapter+0x20/0x2c
[    7.735536]  kthread+0x170/0x330
[    7.735888]  ret_from_fork+0x10/0x18
[    7.736264]
[    7.736462] Allocated by task 116:
[    7.736780]  ____kasan_kmalloc+0x108/0x130
[    7.737163]  __kasan_kmalloc+0x10/0x1c
[    7.737527]  kthread+0x6c/0x330
[    7.737861]  ret_from_fork+0x10/0x18
[    7.738217]
[    7.738413] Freed by task 115:
[    7.738713]  kasan_set_track+0x3c/0x74
[    7.739080]  kasan_set_free_info+0x20/0x2c
[    7.739461]  ____kasan_slab_free+0x214/0x218
[    7.739847]  __kasan_slab_free+0x14/0x24
[    7.740223]  kfree+0x140/0x3bc
[    7.740553]  free_kthread_struct+0x28/0x4c
[    7.740935]  __put_task_struct+0x138/0x1b8
[    7.741326]  delayed_put_task_struct+0x4c/0x88
[    7.741728]  rcu_do_batch+0x130/0x3ec
[    7.742092]  rcu_core+0x1f0/0x344
[    7.742446]  rcu_core_si+0x10/0x1c
[    7.742796]  __do_softirq+0xd8/0x260
[    7.743152]
[    7.743348] The buggy address belongs to the object at ffff000002650e00
[    7.743348]  which belongs to the cache kmalloc-128 of size 128
[    7.744152] The buggy address is located 114 bytes to the right of
[    7.744152]  128-byte region [ffff000002650e00, ffff000002650e80)
[    7.744971] The buggy address belongs to the page:
[    7.745345] page:fffffc0000099400 refcount:1 mapcount:0
mapping:0000000000000000 index:0x0 pfn:0x42650
[    7.746004] flags:
0x3fffc0000000200(slab|node=0|zone=0|lastcpupid=0xffff|kasantag=0x0)
[    7.746680] raw: 03fffc0000000200 0000000000000000 0000000100000001
fdff000002401200
[    7.747276] raw: 0000000000000000 0000000080100010 00000001ffffffff
0000000000000000
[    7.747775] page dumped because: kasan: bad access detected
[    7.748190]
[    7.748383] Memory state around the buggy address:
[    7.748767]  ffff000002650c00: f8 f8 fe fe fe fe fe fe fe fe fe fe
fe fe fe fe
[    7.749303]  ffff000002650d00: f8 f8 f8 f8 f8 f8 f8 fe fe fe fe fe
fe fe fe fe
[    7.749831] >ffff000002650e00: fa fa fa fa fa fa fa fe fe fe fe fe
fe fe fe fe
[    7.750345]                                                                 ^
[    7.750853]  ffff000002650f00: f8 f8 f8 f8 fe fe fe fe fe fe fe fe
fe fe fe fe
[    7.751388]  ffff000002651000: fc fc fc fc fc fc fc fc fe fb fb fb
fb fb fb fb
[    7.751914] ==================================================================
[    7.754424] Unable to handle kernel write to read-only memory at
virtual address f8ff000002573ff0
[    7.760818] Mem abort info:
[    7.761074]   ESR = 0x9600004f
[    7.761392]   EC = 0x25: DABT (current EL), IL = 32 bits
[    7.761819]   SET = 0, FnV = 0
[    7.762086]   EA = 0, S1PTW = 0
[    7.762374]   FSC = 0x0f: level 3 permission fault
[    7.763350] Data abort info:
[    7.763600]   ISV = 0, ISS = 0x0000004f
[    7.763954]   CM = 0, WnR = 1
[    7.764282] swapper pgtable: 4k pages, 48-bit VAs, pgdp=000000004193c000
[    7.764760] [f8ff000002573ff0] pgd=180000005fff7003,
p4d=180000005fff7003, pud=180000005fff6003, pmd=180000005ffed003,
pte=0060000042573f87
[    7.766996] Internal error: Oops: 9600004f [#1] PREEMPT SMP
[    7.767561] Modules linked in:
[    7.768138] CPU: 0 PID: 117 Comm: kunit_try_catch Tainted: G    B
           5.14.0-rc3-00011-g7a062ce31807-dirty #1
[    7.768948] Hardware name: linux,dummy-virt (DT)
[    7.769444] pstate: a0400005 (NzCv daif +PAN -UAO -TCO BTYPE=--)
[    7.769987] pc : __memcpy+0x1e8/0x230
[    7.771029] lr : kmalloc_memmove_invalid_size+0x148/0x1cc
[    7.771457] sp : ffff80001023bd60
[    7.771740] x29: ffff80001023bdb0 x28: 0000000000000000 x27: f8ff000002650d40
[    7.772450] x26: f3ff000002d64600 x25: ffffc63e374bdf48 x24: ffffc63e3901c50c
[    7.773109] x23: 000001e700000001 x22: ffffc63e3905f000 x21: ffffc63e38587294
[    7.773768] x20: ffff80001000bb70 x19: f8ff000002650f00 x18: ffffffffffffffff
[    7.774422] x17: 0000000000000000 x16: 0000000000000118 x15: 0000000000000004
[    7.775067] x14: 000000000000000e x13: 42573f83d4202000 x12: d4202000d4202000
[    7.775722] x11: d4202000d4202000 x10: d4202000d4202000 x9 : d4202000d4202000
[    7.776397] x8 : d4202000d4202000 x7 : d4202000d4202000 x6 : d4202000d4202000
[    7.777040] x5 : f8ff000002574030 x4 : f8ff000002573ff4 x3 : 0000000000000000
[    7.777687] x2 : fffffffffff230b0 x1 : f8ff000002650f04 x0 : f8ff000002650f00
[    7.778441] Call trace:
[    7.778714]  __memcpy+0x1e8/0x230
[    7.779064]  kunit_try_run_case+0x48/0x108
[    7.779409]  kunit_generic_run_threadfn_adapter+0x20/0x2c
[    7.779818]  kthread+0x170/0x330
[    7.780125]  ret_from_fork+0x10/0x18
[    7.780771] Code: a93e24a8 a97e2488 a93d2caa a97d2c8a (a9bc34ac)
[    7.781490] ---[ end trace e570c3a10375543e ]---
[    7.783261] Unable to handle kernel paging request at virtual
address 00650d50f8fefff8
[    7.783766] Mem abort info:
[    7.784002]   ESR = 0x96000004
[    7.784255]   EC = 0x25: DABT (current EL), IL = 32 bits
[    7.784637]   SET = 0, FnV = 0
[    7.784892]   EA = 0, S1PTW = 0
[    7.785150]   FSC = 0x04: level 0 translation fault
[    7.785495] Data abort info:
[    7.785724]   ISV = 0, ISS = 0x00000004
[    7.786013]   CM = 0, WnR = 0
[    7.786268] [00650d50f8fefff8] address between user and kernel address ranges
[    7.786743] Internal error: Oops: 96000004 [#2] PREEMPT SMP
[    7.787122] Modules linked in:
[    7.787423] CPU: 0 PID: 117 Comm: kunit_try_catch Tainted: G    B D
           5.14.0-rc3-00011-g7a062ce31807-dirty #1
[    7.788099] Hardware name: linux,dummy-virt (DT)
[    7.788419] pstate: 004000c5 (nzcv daIF +PAN -UAO -TCO BTYPE=--)
[    7.788855] pc : swake_up_locked+0x1c/0x48
[    7.789197] lr : complete+0x44/0x64
[    7.789508] sp : ffff80001023b910
[    7.789773] x29: ffff80001023b910 x28: f3ff000002d64600 x27: f3ff000002d64600
[    7.790425] x26: f3ff000002d64600 x25: ffffc63e374bdf48 x24: ffffc63e374efbf8
[    7.791069] x23: ffff80001023baa4 x22: 0000000000000000 x21: 0000000000000000
[    7.791733] x20: f8ff000002650d40 x19: 02650d50f8ff0000 x18: ffffffffffffffff
[    7.792380] x17: 0000000000000000 x16: 0000000000000118 x15: 0000000000000004
[    7.793031] x14: 0000000000000fff x13: ffffc63e38d4aa08 x12: 0000000000000003
[    7.793683] x11: 0000000000000000 x10: 0000000000000002 x9 : 0000000000000000
[    7.794341] x8 : 0000000000000001 x7 : 205d303934313837 x6 : 372e37202020205b
[    7.794977] x5 : ffffc63e39041f58 x4 : 0000000000000001 x3 : 0000000000000000
[    7.795622] x2 : 0000000000000001 x1 : 0000000000000000 x0 : f8ff000002650d50
[    7.796272] Call trace:
[    7.796503]  swake_up_locked+0x1c/0x48
[    7.796836]  complete+0x44/0x64
[    7.797133]  mm_release+0xd4/0xec
[    7.797437]  exit_mm_release+0x28/0x38
[    7.797775]  exit_mm+0x3c/0x214
[    7.798074]  do_exit+0x180/0x778
[    7.798379]  die+0x2ac/0x2b0
[    7.798669]  __do_kernel_fault+0x1bc/0x248
[    7.799020]  do_page_fault+0x4c/0x3c4
[    7.799343]  do_mem_abort+0x40/0xb4
[    7.799661]  el1_abort+0x40/0x60
[    7.799968]  el1h_64_sync_handler+0x5c/0x98
[    7.800318]  el1h_64_sync+0x78/0x7c
[    7.800639]  __memcpy+0x1e8/0x230
[    7.800948]  kunit_try_run_case+0x48/0x108
[    7.801297]  kunit_generic_run_threadfn_adapter+0x20/0x2c
[    7.801697]  kthread+0x170/0x330
[    7.801993]  ret_from_fork+0x10/0x18
[    7.802383] Code: 910003fd f8408c13 eb00027f 54000100 (f85f8260)
[    7.802810] ---[ end trace e570c3a10375543f ]---
[    7.803154] note: kunit_try_catch[117] exited with preempt_count 2
[    7.803596] Fixing recursive fault but reboot is needed!
[   10.659826] Unable to handle kernel paging request at virtual
address ffff39c2e762363e
[   10.661382] Mem abort info:
[   10.662059]   ESR = 0x96000004
[   10.662795]   EC = 0x25: DABT (current EL), IL = 32 bits
[   10.663887]   SET = 0, FnV = 0
[   10.664634]   EA = 0, S1PTW = 0
[   10.665390]   FSC = 0x04: level 0 translation fault
[   10.666379] Data abort info:
[   10.667043]   ISV = 0, ISS = 0x00000004
[   10.667879]   CM = 0, WnR = 0
[   10.668605] swapper pgtable: 4k pages, 48-bit VAs, pgdp=000000004193c000
[   10.669507] [ffff39c2e762363e] pgd=0000000000000000, p4d=0000000000000000
[   10.670636] Internal error: Oops: 96000004 [#3] PREEMPT SMP
[   10.671425] Modules linked in:
[   10.671998] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G    B D
   5.14.0-rc3-00011-g7a062ce31807-dirty #1
[   10.673281] Hardware name: linux,dummy-virt (DT)
[   10.673958] pstate: 604000c5 (nZCv daIF +PAN -UAO -TCO BTYPE=--)
[   10.674844] pc : __queue_work+0x1f4/0x408
[   10.675536] lr : __queue_work+0x38/0x408
[   10.676205] sp : ffff800010003d80
[   10.676739] x29: ffff800010003d80 x28: ffff39c2e762363e x27: dead000000000122
[   10.678061] x26: 0000000000000000 x25: ffffc63e38d1d768 x24: 000000007fffffff
[   10.679392] x23: ffffc63e388a9638 x22: 0000000000000014 x21: 0000000000000100
[   10.680286] x20: f9ff0000025f8c00 x19: f8ff000002fcc5b0 x18: 0000000000000000
[   10.681183] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000
[   10.682071] x14: 0000000000200000 x13: f8ff000002fcc588 x12: ffff00001fecd258
[   10.682959] x11: ffffffffc0000040 x10: ffffc63e3889f000 x9 : ffff39c1e7627000
[   10.683867] x8 : 000000007fffffff x7 : 00001e8480000000 x6 : 0000000000000000
[   10.684763] x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000069
[   10.685642] x2 : f8ff000002fcc5b0 x1 : f9ff0000025f8c00 x0 : ffffc63e3901c250
[   10.686511] Call trace:
[   10.686832]  __queue_work+0x1f4/0x408
[   10.687287]  queue_work_on+0x54/0x8c
[   10.687736]  blk_rq_timed_out_timer+0x20/0x2c
[   10.688225]  __run_timers+0x1d8/0x2fc
[   10.688682]  run_timer_softirq+0x24/0x48
[   10.689154]  __do_softirq+0xd8/0x260
[   10.689592]  __irq_exit_rcu+0xf4/0xf8
[   10.689954]  irq_exit+0x10/0x20
[   10.690265]  handle_domain_irq+0x60/0x88
[   10.690609]  gic_handle_irq+0x68/0xe0
[   10.690944]  call_on_irq_stack+0x2c/0x54
[   10.691284]  el1_interrupt+0x60/0xa4
[   10.691633]  el1h_64_irq_handler+0x18/0x24
[   10.691994]  el1h_64_irq+0x78/0x7c
[   10.692316]  arch_cpu_idle+0x18/0x28
[   10.692651]  cpuidle_idle_call+0x70/0x250
[   10.693011]  do_idle+0xb0/0xfc
[   10.693317]  cpu_startup_entry+0x24/0x28
[   10.693662]  rest_init+0xe4/0xf4
[   10.693976]  arch_call_rest_init+0x10/0x1c
[   10.694343]  start_kernel+0x328/0x43c
[   10.694679]  __primary_switched+0xc0/0xc8
[   10.695101] Code: eb14013f 54000280 aa1b03e0 9439f6fb (f9400380)
[   10.695897] ---[ end trace e570c3a103755440 ]---
[   10.696360] Kernel panic - not syncing: Oops: Fatal exception in interrupt
[   10.697132] Kernel Offset: 0x463e27000000 from 0xffff800010000000
[   10.697565] PHYS_OFFSET: 0x40000000
[   10.697857] CPU features: 0x000003d9,4d330c5f
[   10.698416] Memory Limit: none
[   10.698918] ---[ end Kernel panic - not syncing: Oops: Fatal
exception in interrupt ]---
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH v2 6/8] arm64: Import latest memcpy()/memmove() implementation

From: Peter Collingbourne <hidden>
Date: 2021-09-10 20:38:06

On Fri, Sep 10, 2021 at 4:42 AM Robin Murphy [off-list ref] wrote:
On 2021-09-10 01:35, Peter Collingbourne wrote:
quoted
Hi Robin,

(apologies for breaking the threading, I wasn't subscribed to
linux-arm-kernel when you sent this)

It looks like this patch breaks the KASAN unit tests when running in
HW tags mode. You can construct a config that reproduces the problem
with something like:

make O=out defconfig
scripts/config --file out/.config -e CONFIG_KUNIT -e CONFIG_KASAN -e
CONFIG_KASAN_HW_TAGS -e CONFIG_KASAN_KUNIT_TEST
yes '' | make O=out syncconfig

With that the "kmalloc_memmove_invalid_size" test fails and causes the
kernel panic below.

What appears to be going on is that whereas the old memcpy
implementation ends up returning early after not copying very much
data if supplied a "negative" size as a side effect of using
conditional branches that implement signed comparisons (e.g. b.ge on
line 75), the new implementation does not exit early and attempts to
copy a large amount of data backwards 4 bytes (after having disabled
MTE early on as a result of a tag mismatch) until it hits a read-only
page and causes a panic.
If the test depends on the implementation of memmove() being buggy, it's
clearly not a very good test :/
quoted
I'm not sure what the correct fix should be. It seems that at least
when KASAN is enabled we should be able to catch these invalid memcpys
somehow, print an error report and ideally abort the entire operation.
But we should do so without causing a performance impact in the usual
case.
Not sure I follow - the top of the log below clearly shows that KASASN
*is* detecting and reporting a bad access. The fact that code intended
to deliberately corrupt memory goes on to corrupt memory doesn't seem
particularly surprising to me. A bug exists (intentionally or otherwise)
which led to that invalid access being attempted, and KASAN can't
magically change that.
That makes sense. So we want to make sure that:

a) memmove overflows trigger an error report
b) we can safely continue execution

It seems the best way to ensure both of these properties is to have
the memmove do an out-of-bounds read -- all writes would then be into
the correct allocation. That way, we should see an error report but no
memory corruption. We can do that by changing the memmove call to only
copy "size" bytes.

When I was about to send my patch I noticed that Andrey already sent a
fix for this in commit 1b0668be62cf that disables the memmove test
when KASAN HW tags is enabled. I reckon there's still some value in
testing a) in HW tags mode, so I went ahead and had my patch also
revert his.

Peter

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help