#include #include #include #include #include #include #include #include #include #include #ifndef SYM #define SYM 0 #endif int sym_op = 43; int sym_skip = 0; 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; } static inline unsigned long symx() { #if SYM unsigned long x; asm volatile("csrr %0, 0x004" : "=r" (x) ); return x; #else return 0; #endif } #define NAA 128 unsigned long long aa[NAA] = { 0x0ull, 0x0ull, 0x0ull, 0x0ull, 0x10000800100040ull, 0x0ull, 0x800006000000000ull, 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, 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> } // csa_cb_program? // csa_sec_parms<>? 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); #if SYM sync(); sleep(1); sleep(1); sleep(1); asm volatile("addi x0, x0, 0x379"); #endif int pid1 = fork(); if(pid1 == 0){ close(s); if(system("echo -n mount: ; mount_nfs -o nfsv4,minorversion=1 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 dd: ; dd if=/mnt/y of=/dev/null bs=512 count=1"); system("echo -n umount: ; umount /mnt"); } exit(0); } int pid2 = fork(); if(pid2 == 0){ while(1){ 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); } 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"); } close(s1); } exit(1); } close(s); sleep(20); if(system("dmesg | grep 'unhandled sig'") == 0){ printf("unhandled signal\n"); while(1){} } #if SYM asm volatile("addi x0, x0, 0x380"); #endif }