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