Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10 5/3/83; site umcp-cs.UUCP Path: utzoo!linus!decvax!tektronix!ogcvax!omsvax!hplabs!hao!seismo!rlgvax!cvl!umcp-cs!rehmi From: rehmi@umcp-cs.UUCP Newsgroups: net.unix-wizards Subject: Re: Job Control Wishlist Message-ID: <3214@umcp-cs.UUCP> Date: Wed, 19-Oct-83 09:52:02 EDT Article-I.D.: umcp-cs.3214 Posted: Wed Oct 19 09:52:02 1983 Date-Received: Sun, 23-Oct-83 10:24:54 EDT References: <12703@sri-arpa.UUCP> Organization: Univ. of Maryland, Computer Science Dept. Lines: 372 In the spirit of Bob Brown's setuid program, I cons'd up a setf program which'll open a file and swap pointers to it with some other process. It needs some cleaning up, but... ================================= #include #include #include #include #include #include #include #include #include #include #include #include /* setf - change the file descriptors under a running process * and don't even tell it. Abuse with moderate caution. * Khron the Elder (rehmi@{umd-csd,umcp-cs}) 27 Jan 83 * * inspired and derived partially from Bob Brown's setuid (rlb@purdue) */ #define NAMELIST "/vmunix" #define KERNEL "/dev/kmem" #define MEMORY "/dev/mem" #define SWAP "/dev/drum" #define ROOT 0 /* root user id */ int Memory, Kernel, Swap; struct nlist Names[] = { { "_proc" }, #define X_PROC 0 { "_nproc" }, #define X_NPROC 1 { "_Usrptmap" }, #define X_USRPTMAP 2 { "_usrpt" }, #define X_USRPT 3 { 0 } }; struct proc proc, *Procptr; int nproc; struct pte *Usrptma, *usrpt; union myuser { struct user user; char upages[UPAGES][NBPG]; } User; #define U User.user #ifdef DEBUG # define DEBUGp 1 #else # define DEBUGp 0 #endif int NoWrite; caddr_t procp; getval(fd, addr, buf, n) int fd, addr, n; char *buf; { lseek(fd, addr, 0); return(read(fd, buf, n)); } putval(fd, addr, buf, n) int fd, addr, n; char *buf; { lseek(fd, addr, 0); #ifndef NOWRITE return(write(fd, buf, n)); #else return(n); #endif } getu(user, mproc) union myuser *user; struct proc *mproc; { struct pte apte; int pad1; /* avoid hardware botch */ struct pte arguutl[UPAGES+CLSIZE]; int pad2; /* avoid hardware botch */ register int i; int ncl, size; size = sizeof (struct user); if ((mproc->p_flag & SLOAD) == 0) { if (getval(Swap, ctob(mproc->p_swaddr), &user->user, size) != size) { fprintf(stderr, "can't read u for pid %d from %s\n", mproc->p_pid, SWAP); return (0); } return (1); } if(getval(Kernel, (int)&Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1], &apte, sizeof apte)!=sizeof(apte)) { printf("can't read indir pte to get u for pid %d from %s\n", mproc->p_pid, KERNEL); return (0); } if (getval(Memory, ctob(apte.pg_pfnum+1)-(UPAGES+CLSIZE)*sizeof (struct pte), arguutl, sizeof arguutl) != sizeof arguutl) { printf("can't read page table for u of pid %d from %s\n", mproc->p_pid, MEMORY); return (0); } ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); while (--ncl >= 0) { i = ncl * CLSIZE; if (getval(Memory, ctob(arguutl[CLSIZE+i].pg_pfnum), user->upages[i], CLSIZE*NBPG)!=CLSIZE*NBPG) { printf("can't read page %x of u of pid %d from %s\n", arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, MEMORY); return(0); } } return (1); } putu(user, mproc, member, msize) union myuser *user; struct proc *mproc; char *member; int msize; { struct pte apte; int pad1; /* avoid hardware botch */ struct pte arguutl[UPAGES+CLSIZE]; int pad2; /* avoid hardware botch */ register int i; int ncl, size; size = sizeof (struct user); #ifdef DEBUG printf("put:uid %d gid %d ruid %d rgid %d\n", user->user.u_uid, user->user.u_gid, user->user.u_ruid, user->user.u_rgid); #endif if ((mproc->p_flag & SLOAD) == 0) { if (getval(Swap, ctob(mproc->p_swaddr), &user->user, size) != size) { fprintf(stderr, "can't read u for pid %d from %s\n", mproc->p_pid, SWAP); return (0); } return (1); } if(getval(Kernel, (int)&Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1], &apte, sizeof apte)!=sizeof(apte)) { printf("can't read indir pte to get u for pid %d from %s\n", mproc->p_pid, KERNEL); return (0); } if (getval(Memory, ctob(apte.pg_pfnum+1)-(UPAGES+CLSIZE)*sizeof (struct pte), arguutl, sizeof arguutl) != sizeof arguutl) { printf("can't read page table for u of pid %d from %s\n", mproc->p_pid, MEMORY); return (0); } ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); while (--ncl >= 0) { i = ncl * CLSIZE; #ifdef DEBUG printf("i*NBPG=%x member=%x user=%x memb-user=%x msize=%x\n", i*NBPG, member, user, (int)member-(int)user, msize); #endif if((i+1)*NBPG > ((int)member-(int)user) && i*NBPG <= ((int)member-(int)user+msize)) { int foo, bar; bar=MAX(0, (int)member-(int)user-(i*NBPG)); foo=MIN(CLSIZE*NBPG, (int)member-(int)user+msize-(i*NBPG))-bar; #ifdef DEBUG printf("foo=%04x, bar=%04x, iteration %d, i=%04x\n", foo, bar, ncl, i); #endif if (putval(Memory, ctob(arguutl[CLSIZE+i].pg_pfnum)+bar, (user->upages[i])+bar, foo)!=foo) { printf("can't write page %x of u of pid %d from %s\n", arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, MEMORY); return(0); } } } return (1); } getw(loc) off_t loc; { long word; lseek(Kernel, loc, 0); if (read(Kernel, &word, sizeof word) != sizeof word) printf("error reading kmem at %x\n", loc); return (word); } getprocu(pid) int pid; { register int i, j, found, ncl; int newflag; Usrptma=(struct pte *)Names[X_USRPTMAP].n_value; usrpt=(struct pte *)Names[X_USRPT].n_value; getval(Kernel, Names[X_PROC].n_value, &procp, sizeof procp); getval(Kernel, Names[X_NPROC].n_value, &nproc, sizeof nproc); found = 0; lseek(Kernel, (char *)procp, 0); for(i = 0; i < nproc; i++){ if(read(Kernel, &proc, sizeof proc) != sizeof proc){ perror("Kernel read"); exit(1); } Procptr = &proc; if(found=(pid == Procptr->p_pid)) break; } if(!found){ fprintf(stderr, "Failed to find pid %d\n", pid); exit(1); } getu(&U, Procptr); } /* * Assignproc - place a value in the proc table for a process * * Inputs: Procptr (global) ... ptr to local copy of proc entry. * Proc (global) ... local copy of entire proc table. * praddr ............ address of field in proc to change. * value .............. pointer to new value to assign. */ assignproc (praddr, value, length) caddr_t praddr, length; char *value; { caddr_t seekto; seekto = (caddr_t)praddr - (caddr_t)Procptr + (caddr_t)procp; lseek(Kernel, seekto, 0); #ifndef NOWRITE if ( write(Kernel, value, length) < 0) { perror("Kernel write"); exit(1); } #endif } /* * openfiles - Open System Files: Paging device (Swap) * Kernel address space (Kernel) * Physical memory (Memory) * * Exits if any error */ openfiles() /* results are global variables */ { #ifdef NOWRITE #define Mode 0 #else #define Mode 2 #endif if((Kernel=open(KERNEL,Mode))<0) { perror("Kernel access"); exit(1); } if((Memory=open(MEMORY,Mode))<0) { perror("Memory access"); exit(1); } if((Swap=open(SWAP,Mode))<0) { perror("Swap access"); exit(1); } } struct nlist nlfoo[] = {{"_u"}, 0}; main(argc, argv) char argc, **argv; { int kmemfd, fd, foo, j; struct user u; struct file f, *t; struct inode i; if(argv[1][0]=='-') { NoWrite=1; argv++; } if(!NoWrite && argc<4) { fprintf(stderr, "usage: %s [-] \n", argv[0]); exit(1); } if(getuid()) exit(1); openfiles(); nlist("/vmunix", nlfoo); nlist("/vmunix", Names); setuid(getuid()); fd=open(argv[2], 2); if(fd<0) fd=creat(argv[2], 0644); if(fd<0) perror(argv[2]); lseek(Kernel, nlfoo[0].n_value, 0); read(Kernel, &u, sizeof u); getprocu(atoi(argv[1])); foo=atoi(argv[3]); if(DEBUGp || NoWrite) { printf("name %s old f[%d] %x new f[%d] %x\n", U.u_comm, foo, U.u_ofile[foo], fd, u.u_ofile[fd]); for(j=0;j