2022-01-04 20:08:20

by rtm

[permalink] [raw]
Subject: nfs v4 decode_read_plus_hole() insufficient length sanity check

decode_read_plus_hole() reads a 64-bit length from the server's RPC
reply. There's a sanity-check:

if (length + res->count > args->count) {

but it doesn't work if length is big enough that the sum wraps, e.g.
0xffffffffffffffff. In that case, eventually the loop in
xdr_buf_pages_zero() calls memset() on the wrong memory.

I've attached a demo:

# uname -a
Linux (none) 5.16.0-rc7-00108-g800829388818-dirty #23 SMP Tue Jan 4 19:38:52 UTC 2022 riscv64 riscv64 riscv64 GNU/Linux
# cc nfs_20.c
# ./a.out
...
[ 74.362358] Unable to handle kernel paging request at virtual address 92492d8ddff40000
[ 74.612471] status: 0000000200000121 badaddr: 92492d8ddff40000 cause: 000000000000000f
[ 74.626913] [<ffffffff80346650>] __memset+0x60/0xfc
[ 74.637735] [<ffffffff802333ac>] nfs4_xdr_dec_read_plus+0x2d6/0x3fa
[ 74.650614] [<ffffffff80617406>] rpcauth_unwrap_resp_decode+0x12/0x1a
[ 74.663084] [<ffffffff80618124>] rpcauth_unwrap_resp+0x12/0x1a
[ 74.675822] [<ffffffff8060e23a>] call_decode+0x112/0x176
[ 74.686253] [<ffffffff8061686c>] __rpc_execute+0x7e/0x21a
[ 74.696694] [<ffffffff80616a2c>] rpc_async_schedule+0x24/0x46
[ 74.709450] [<ffffffff800209d4>] process_one_work+0x13e/0x28a
[ 74.722182] [<ffffffff80020b9c>] worker_thread+0x7c/0x320
[ 74.732607] [<ffffffff80027010>] kthread+0x124/0x136
[ 74.743073] [<ffffffff8000303e>] ret_from_exception+0x0/0xc
[ 74.764059] ---[ end trace ca32aa753f3ddad2 ]---


Attachments:
nfs_20.c (31.14 kB)