chdt 0.2

Christos Ricudis ricudis at paiko.gr
Thu Jan 10 21:02:01 EET 2002


Na kai h deyterh ekdosh. An eiste kala paidia sas yposxomai na mh sas
ksanasteilw allh :P


/* chdt 0.2 (C) 2000-2002, Christos Ricudis ricudis at paiko.gr 

 This program executes a binary in system call trace mode 
 changing the result codes of some system calls as requested by 
 the user. 
 
 Compile with gcc -o chdt chdt.c. Run chdt without arguments for usage 
 reference.
 
 This program is supplied without warranties. 
 
 You should note that using this program to circumvent software licensing
 restrictions imposed by license managers is a violation of your licensing
 terms and it is probably illegal. For example :
 
 If you take an expired demo Sun Workshop license, and then move 
 /opt/SUNWspro/WS6/bin/acomp to /opt/SUNWspro/WS6/bin/acomp-orig and 
 replace /opt/SUNWspro/WS6/bin/acomp with a shell script that calls
 "chdt -t <some time before expiration> -- /opt/SUNWspro/WS6/bin/acomp-orig $*"
 then you are probably breaking Sun's licensing terms and it could
 put you into serious legal trouble.
 
 Changelog : 
 
 version 0.1 :	* Initial version
 
 version 0.2 :	* Fixed a SERIOUS bug : The copyright date was wrongly 
 		noted as 2000-2001, where the right one is 2000-2002. 
 		
 		* A minor useless bit of functionality was added, that 
 		allows us to monitor and intercept children processes 
 		of the program we execute, too. The wrapper trick is no 
 		longer needed, now you are able to directly use "chdt -t 
 		<time> cc -o blabla blabla.c" to put yourself in the legal 
 		trouble of the above paragraph.
 		
 		* Program restructured for destruction of any clarity 
 		left by mistake.
 		
 License : 

 This software is public domain. No warranties are expressed or implied.
 Contains gas in high pressure. Do not dispose. Use by children without
 adult supervision is prohibited. Use only certified replacement parts. 
 Do not expose in direct sunlight. Do not use near water. Use while
 intoxicated may cause accidents. Keep away of reach of children. Do not
 use without doctors advice. Contains recycleable materials. Unplug from 
 wall outlet before cleaning. Do not use soaps, liquid cleaners or aerosols. 
 Do not use in pools, bathtubs, showers, or spa. Do not immerse in water. 
 Do not use while driving a motor vehicle. Do not use a damaged power cord.
 Do not dismantle. Do not expose in extreme temperatures. Never use during a
 lightning storm. Do not use while in wet conditions. Do not place on an 
 unstable cart, stand, or table. Use only the type and size of battery 
 specified. No user-serviceable parts inside. Consists of 100% pure recycled
 electrons. Actual size and color may differ. Do not drink and drive.
 
*/
 

#include <unistd.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/fault.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/systeminfo.h>
#include <sys/procfs_isa.h>
#include <sys/stropts.h>
#include <poll.h>
#include <unistd.h>

/* Synchronization primitives inadvertenly stolen from Stevens */

static int pfd1[2], pfd2[2];

void TELL_WAIT(void) {
	if (pipe(pfd1)<0 || pipe(pfd2)<0) {
		perror("pipe()");
		exit(1);
	}
}

void TELL_PARENT(pid_t pid) {
	if (write(pfd2[1],"c",1)!=1) {
		perror("write()");
		exit(1);
	}
}

void WAIT_PARENT(void) {
	char c; 
	if (read(pfd1[0],&c,1)!=1) {
		perror("read()");
	}
	if (c!='p') {
		printf("Mparmpoutsala\n");
		exit(1);
	}
}

void TELL_CHILD(pid_t pid) {
	if (write(pfd1[1],"p",1)!=1) {
		perror("write()");
		exit(1);
	}
}

void WAIT_CHILD(void) {
	char c; 
	if (read(pfd2[0],&c,1)!=1) {
		perror("read()");
	}
	if (c!='C') {
		printf("Karamparmpoutsala\n");
		exit(1);
	}
}

/*--------------------------------------------------*/


/* global variables (yeah, I know, no, not again THIS argument!) */

char *chhost;
char *chdom;
char *chtime;
time_t regtime;
int vflag;
sysset_t sysset;

/* puke */
#define verbose if (vflag==1) 

/* routines to add/delete a process in the monitoring loop. We have a 
frigging static limit of 100 descendants. If you want more, add dynamic
memory allocation yourself :P */

int del_pid(int fdesc,int *nofds, struct pollfd fds[]) {
	int i;
	int flag=0;
	
	close(fdesc);
	verbose printf("nofds=%d\n",*nofds);
	for (i=0;i<*nofds;i++) {
		if (flag==1) {
			fds[i-1].fd=fds[i].fd;		/* Can you tell WHY there isn't a problem here when i=0; */
			fds[i-1].events=fds[i].fd;
		}
		if (fds[i].fd==fdesc) {
			flag=1;
		}
	}
	(*nofds)--;
}

int add_pid(pid_t pidoulos, int *nofds, struct pollfd fds[]) {

	char pids[100];
	int fdesc;
	
	verbose printf("Monitoring pid %d\n",pidoulos);
	sprintf(pids,"/proc/%d",pidoulos);
	verbose printf("Opening %s\n",pids);
	if ((fdesc=open(pids,O_RDWR))==-1) {
		verbose perror("open()");
	}
	
	if (ioctl(fdesc, PIOCSEXIT, &sysset) < 0) {
		verbose perror("ioctl(PIOCSEXIT)");
	}
	
	fds[*nofds].fd=fdesc;
	fds[*nofds].events=POLLPRI;
	if (((*nofds)++)>100) {
		verbose printf("Th gkamhsame megkale\n");
	}
	
}

	
void process_event(int fdesc,int *nofds, struct pollfd fds[]) {

	struct prstatus piocs;
	struct prrun piocr;
	char *buffer;
	long piocflags;
	prgreg_t regret=0;
	prgregset_t regs;
	int i;
	pid_t bpid;
                
	if (ioctl(fdesc,PIOCSTATUS,&piocs)==-1) {
		verbose perror("ioctl(PIOCSTATUS)");
		del_pid(fdesc,nofds,fds);
		return;
	}
	
	if (piocs.pr_flags&&PR_STOPPED) {
		verbose printf("Stopped\n");
		if (piocs.pr_why&&PR_SYSEXIT) {
			verbose printf("Stopped because of syscall %d\n",piocs.pr_what);
			verbose printf("PR_SYSCALL = %d\n",piocs.pr_syscall);
			verbose printf("PR_NSYSARG = %d\n",piocs.pr_nsysarg);
			verbose printf("PR_SYSARG = [ ");
			for (i=0;i<piocs.pr_nsysarg;i++) { 
				verbose printf("%lu ",piocs.pr_sysarg[i]);
			}
			verbose printf("]\n");
			if (piocs.pr_what==SYS_systeminfo) {
				if (piocs.pr_sysarg[0]==SI_HW_SERIAL && chhost!=NULL) {
					verbose printf("Intercepting serial number\n");
					lseek(fdesc,piocs.pr_sysarg[1],SEEK_SET);
					buffer=malloc(piocs.pr_sysarg[2]);
					read(fdesc,buffer,piocs.pr_sysarg[2]);
					verbose printf("Host ID : ==%s==\n",buffer);
					verbose printf("We change it to : ==%s==\n",chhost);
					lseek(fdesc,piocs.pr_sysarg[1],SEEK_SET);
					write(fdesc,chhost,strlen(chhost)+1);
					verbose printf("Put syscall's return code into R_O0 register\n");
					regret=strlen(chhost)+1;
					free(buffer);
				}
				if (piocs.pr_sysarg[0]==SI_SRPC_DOMAIN && chdom!=NULL) {
					verbose printf("Intercepting domain name\n");
					lseek(fdesc,piocs.pr_sysarg[1],SEEK_SET);
					buffer=malloc(piocs.pr_sysarg[2]);
					read(fdesc,buffer,piocs.pr_sysarg[2]);
					verbose printf("Domain name : ==%s==\n",buffer);
					verbose printf("We change it to : ==%s==\n",chdom);
					lseek(fdesc,piocs.pr_sysarg[1],SEEK_SET);
					write(fdesc,chdom,strlen(chdom)+1);
					verbose printf("Put syscall's return code into R_O0 register\n");
					regret=strlen(chdom)+1;
					free(buffer);
				}
			}
			
			if (piocs.pr_what==SYS_time) {
				verbose printf("Put syscall's return code into R_O0 register\n");
				verbose printf("Desired time : %d\n",regtime);
				regret=regtime;
			}
			
			if (piocs.pr_what==SYS_fork) {
				verbose printf("Ohmigawd! The sucker fork()ed a bastard!\n");
				bpid=piocs.pr_reg[R_O0];
				verbose printf("Bastard's PID = %d\n",bpid);
				if (bpid!=0) {
					verbose printf("Let's monitor the bastard too :>\n");
					add_pid(bpid,nofds,fds);
				} else {
					verbose printf("Nah, it's just us again\n");
				}
			}
		}
		verbose printf("Current registers contents : \n");
		for (i=0;i<NPRGREG;i++) {
			verbose printf("reg[%d]=%d\t",i,piocs.pr_reg[i]);
		}
		verbose printf("\n");
		if (regret!=0) { 
			for (i=0;i<NPRGREG;i++) {
				regs[i]=piocs.pr_reg[i];
			}
			regs[R_O0]=regret;
			verbose printf("Setting system registers\n");
			if (ioctl(fdesc,PIOCSREG,&regs)<0) {
				verbose perror("ioctl(PIOCSREG)");
				return;
			}
		}
		verbose printf("Restarting process\n");
		if (ioctl(fdesc,PIOCRUN,NULL)<0) {
			verbose perror("ioctl(PIOCRUN)");
			return;
		}
	}
}	

int main (int argc, char *argv[]) {

	pid_t pid;
	int i;
	int retval;
	char fullpid[100];
	char *c;
	struct pollfd pfd[100];
	int dummy;
	int ld,hd;
	extern char *optarg;
	extern int optind;
	int validopts;
	char arc;
	int nofds=0;
	
	/* Process command line arguments */
	
	chhost=NULL;
	chtime=NULL;
	chdom=NULL;	
	validopts=0;
	while ((arc = getopt(argc, argv, "vh:d:t:")) != EOF) {
        	switch (arc) {
			case 'h':
				chhost=optarg;
		        	break;
			case 'd':
				chdom=optarg;
		        	break;
			case 't':
				chtime=optarg;
				regtime=atol(chtime);
		        	break;
		        case 'v':
		        	vflag++;
		}
	}
	
	validopts=((chhost!=NULL) || (chdom!=NULL) || (chtime!=NULL));
	
	if (argc<=optind) validopts=0;
	
	if (!validopts) {
		printf("chdt v0.2 (c) 2000-2002 Christos Ricudis  <ricudis at paiko.gr>\n\n");
		printf("Usage : %s [ -v ] [ -h HOSTID ] [ -d DOMAIN ] [ -t TIME ]  -- <arglist>\n\n",argv[0]);
		printf("\t -v              : Be debuggingly verbose in annoying quantities\n");
		printf("\t -h HOSTID       : Change hostid to HOSTID\n");
		printf("\t -d DOMAIN       : Change domain to DOMAIN\n");
		printf("\t -t TIME         : Change time (as reported by time(3)) to TIME.\n");
		printf("\t                   the TIME argument is the desired time in UNIX epoch format\n");
		printf("\t <arglist>       : Argument list passed to exec()\n\n");
		printf("\t At least one of -h, -d, -t is required\n");
		printf("\nExample : %s -h 1919977934 -- /usr/bin/hostid\n",argv[0]);
		exit(1);
	}
	
	for (i=0;i<optind;i++) *argv++;

	/* here we are */

	TELL_WAIT();
	
	if (!(pid=fork())) {
		/* wait for parent to do its dirty work */
		WAIT_PARENT();
		execvp(*argv,argv);
	} else {
	
		/* Setup events to watch */
	
		premptyset(&sysset);
		
		if (chhost!=NULL || chdom!=NULL) {
			verbose printf("Stopping child process at exit of system call SYS_systeminfo\n");
			praddset(&sysset,SYS_systeminfo);
		} 
		if (chtime!=NULL) {
			verbose printf("Stopping child process at exit of system call SYS_time\n");
			praddset(&sysset,SYS_time);
		}
		verbose printf("Stopping child process at exit of system call SYS_fork\n");
		praddset(&sysset,SYS_fork);
		
		add_pid(pid,&nofds,pfd);
		
		verbose printf("Setup completed, allowing child to continue\n");
		
		TELL_CHILD(pid);
    
		verbose printf("Entering event loop\n");
		while (nofds>0) {
		
			if (poll(pfd,nofds,-1)<0) {
				verbose perror("poll");
				break;
			}
			
			for (i=0;i<nofds;i++) {
				if (pfd[i].revents!=0) {
					verbose printf("File descriptor %d has an event of interest\n",pfd[i].fd);
					process_event(pfd[i].fd,&nofds,pfd);
					break; /* nofds may be invalid now */
				}
			}
		
		}
		
		verbose printf("Waiting for child to terminate\n");
		wait(&dummy);
		ld = dummy & 0xff;
		hd = dummy << 8 ;
		verbose printf("wait() return code = %d lo = %d hi = %d\n",dummy,ld,hd);
		if (ld==0) {
			return(hd);
		} else {
			return(0);
		}
	}
}

-- 
Christos Ricudis

ric-NOSPAM-udis at paiko.gr			Remove -NOSPAM- to reply
spamoula at paiko.gr				Send your spam here




More information about the Linux-greek-users mailing list