Commit ea25e3c7 authored by Chuck Lever's avatar Chuck Lever
Browse files

sunrpc: prevent out-of-bounds read in __cache_seq_start()



Commit 7b546bd8 ("sunrpc/cache: improve RCU safety in
cache_list walking.") changed the tail of __cache_seq_start()
to unconditionally store

	*pos = ((long long)hash << 32) + 1

before returning, dropping a prior "hash >= cd->hash_size"
guard. When the while loop exits because every remaining
bucket was empty, hash equals cd->hash_size, so the stored
*pos is one position past the table's last valid bucket.
seq_read_iter() caches that index in m->index. A subsequent
pread(2) at the same file offset skips traverse() and hands
the stored index back to __cache_seq_start(), which decodes
hash = cd->hash_size and dereferences
cd->hash_table[cd->hash_size] -- one hlist_head past the end
of the kzalloc'd table.

KASAN reports an eight-byte slab-out-of-bounds read at the
tail of the 2048-byte hash_table allocation for the NFSD
export cache (EXPORT_HASHMAX * sizeof(struct hlist_head) ==
256 * 8).

Reject an input hash that is out of range before touching the
hash table. cache_seq_next() already bounds-checks its own
loop; the start routine needs to be symmetric.

Reported-by: default avatar <syzbot+60cfa08822470bbebe44@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=60cfa08822470bbebe44


Fixes: 7b546bd8 ("sunrpc/cache: improve RCU safety in cache_list walking.")
Reviewed-by: default avatarBenjamin Coddington <bcodding@hammerspace.com>
Reviewed-by: default avatarNeilBrown <neil@brown.name>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 4f8ef58c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1348,6 +1348,9 @@ static void *__cache_seq_start(struct seq_file *m, loff_t *pos)
	hash = n >> 32;
	entry = n & ((1LL<<32) - 1);

	if (hash >= cd->hash_size)
		return NULL;

	hlist_for_each_entry_rcu(ch, &cd->hash_table[hash], cache_list)
		if (!entry--)
			return ch;