Job Control Wishlist
rehmi at umcp-cs.UUCP
rehmi at umcp-cs.UUCP
Wed Oct 19 23:52:02 AEST 1983
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 <stdio.h>
#include <signal.h>
#include <nlist.h>
#include <pwd.h>
#include <sys/pte.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/vm.h>
#include <sys/file.h>
#include <sys/inode.h>
/* 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 at 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 [-] <pid> <file> <fd>\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<NOFILE;j++)
printf("u.u_ofile[%2d] = %08x\tU.u_ofile[%2d] = %08x\n",
j, u.u_ofile[j], j, U.u_ofile[j]);
}
t=U.u_ofile[foo];
U.u_ofile[foo]=u.u_ofile[fd];
u.u_ofile[fd]=t;
if(!NoWrite) {
putu(&U, Procptr, &U.u_ofile[foo], sizeof U.u_ofile[0]);
putval(Kernel, nlfoo[0].n_value, &u, sizeof u);
}
}
====================================
Enjoy(!),
-rehmi
--
By the fork, spoon, and exec of The Basfour.
Arpa: rehmi.umcp-cs at csnet-relay
Uucp:...!harpo!seismo!umcp-cs!rehmi
...!{allegra,brl-bmd}!umcp-cs!rehmi
More information about the Comp.unix.wizards
mailing list