Messages in this thread | | | Date | Wed, 22 May 2019 17:29:46 +0100 | From | Al Viro <> | Subject | Re: d_lookup: Unable to handle kernel paging request |
| |
On Wed, May 22, 2019 at 05:44:30PM +0200, Vicente Bergas wrote:
> 2d30: f8617893 ldr x19, [x4, x1, lsl #3] > 2d34: f27ffa73 ands x19, x19, #0xfffffffffffffffe > 2d38: 54000920 b.eq 2e5c <__d_lookup_rcu+0x15c> // b.none > 2d3c: aa0003f5 mov x21, x0 > 2d40: d360feda lsr x26, x22, #32 > 2d44: a90363f7 stp x23, x24, [sp, #48] > 2d48: aa0203f8 mov x24, x2 > 2d4c: d3608ad7 ubfx x23, x22, #32, #3 > 2d50: a90573fb stp x27, x28, [sp, #80] > 2d54: 2a1603fc mov w28, w22 > 2d58: 9280001b mov x27, #0xffffffffffffffff // #-1 > 2d5c: 14000003 b 2d68 <__d_lookup_rcu+0x68> > 2d60: f9400273 ldr x19, [x19] > 2d64: b4000793 cbz x19, 2e54 <__d_lookup_rcu+0x154>
OK, that looks like hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) in there, x19 being 'node'.
> 2d68: b85fc265 ldur w5, [x19, #-4] > 2d6c: d50339bf dmb ishld
... and that's seq = raw_seqcount_begin(&dentry->d_seq), with ->d_seq being 4 bytes before ->d_hash. So that one has stepped into 0x1000000 (i.e. 1<<24) in hlist forward pointer (or head - either is possible).
> 0000000000002e98 <__d_lookup>:
> 2ed0: f8607833 ldr x19, [x1, x0, lsl #3] > 2ed4: f27ffa73 ands x19, x19, #0xfffffffffffffffe > 2ed8: 54000320 b.eq 2f3c <__d_lookup+0xa4> // b.none > 2edc: 5280001b mov w27, #0x0 // #0 > 2ee0: 92800018 mov x24, #0xffffffffffffffff // #-1 > 2ee4: a9025bf5 stp x21, x22, [sp, #32] > 2ee8: d2800016 mov x22, #0x0 // #0 > 2eec: 52800035 mov w21, #0x1 // #1
That's hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
> 2ef0: b9401a62 ldr w2, [x19, #24]
... and fetching dentry->d_name.hash for subsequent if (dentry->d_name.hash != hash) continue;
> 2ef4: d1002274 sub x20, x19, #0x8 > 2ef8: 6b17005f cmp w2, w23 > 2efc: 540001a1 b.ne 2f30 <__d_lookup+0x98> // b.any
IOW, here we have also run into bogus hlist forward pointer or head - same 0x1000000 in one case and 0x0000880001000000 in two others.
Have you tried to see if KASAN catches anything on those loads? Use-after-free, for example... Another thing to try: slap WARN_ON(entry->d_flags & DCACHE_NORCU); in __d_rehash() and see if it triggers.
| |