Everhart, Glenn (FUSA) From: Daniel Brown [dbrown@CCDC.CAM.AC.UK] Sent: Tuesday, May 18, 1999 10:41 AM To: BUGTRAQ@NETSPACE.ORG Subject: Re: Clarification: LD_PRELOAD issue Here's a similar snippet for Solaris using the procfs interface... Dan. -- #include #include #include #include #include #include #include #include #include /* Faking of the time() system call via procfs. * * Daniel Brown, dbrown@ccdc.cam.ac.uk * * Compiled and tested under Solaris 2.6/sparc and 2.6/x86 */ int read_status(pid_t pid, pstatus_t *status) { char buf[MAXPATHLEN]; int fd; sprintf(buf, "/proc/%d/status", (int) pid); if ((fd = open(buf, O_RDONLY)) == -1) { perror("read_status(open)"); return 1; } if (read(fd, (void *) status, sizeof(pstatus_t)) != sizeof(pstatus_t)) { perror("read_status(read)"); return 1; } close(fd); return 0; } int write_ctl(pid_t pid, long syscall, void *arg, size_t arglen) { int fd; char buf[MAXPATHLEN]; struct iovec vec[2]; sprintf(buf, "/proc/%d/ctl", (int) pid); if ((fd = open(buf, O_WRONLY)) == -1) { perror("write_ctl(open)"); return 1; } vec[0].iov_base = (void *) &syscall; vec[0].iov_len = sizeof(long); if (arg != NULL) { vec[1].iov_base = arg; vec[1].iov_len = arglen; if (writev(fd, vec, 2) != (vec[0].iov_len + vec[1].iov_len)) { perror("write_ctl(write2)"); close(fd); return 1; } } else { if (writev(fd, vec, 1) != vec[0].iov_len) { perror("write_ctl(write1)"); return 1; } } close(fd); return 0; } int main(int argc, char **argv) { pid_t pid, ppid; pstatus_t pstatus; sysset_t sysset; long val; setvbuf(stdout, (char *) NULL, _IONBF, (size_t) 0); ppid = getpid(); if (read_status(ppid, &pstatus)) exit(1); printf("Parent PID is %d\n", (int) ppid); printf("Setting PCSEXIT for time() : stop on exit from time().\n"); premptyset(&sysset); praddset(&sysset, SYS_time); if (write_ctl(ppid, PCSEXIT, (void *) &sysset, sizeof(sysset_t))) exit(1); printf("Setting PR_FORK, so that the child inherits these traps.\n"); val = PR_FORK; if (write_ctl(ppid, PCSET, (void *) &val, sizeof(long))) exit(1); printf("Finally, setting PCSENTRY for exit() " ": stop on entry to exit().\n"); premptyset(&sysset); praddset(&sysset, SYS_exit); if (write_ctl(ppid, PCSENTRY, (void *) &sysset, sizeof(sysset_t))) exit(1); if ((pid = fork()) < 0) { perror("fork"); exit(1); } else if (pid > 0) { /* Parent */ printf("Clearing exit() trap for the parent...\n"); premptyset(&sysset); if (write_ctl(ppid, PCSENTRY, (void *) &sysset, sizeof(sysset_t))) exit(1); /* Good luck! */ if (read_status(pid, &pstatus)) exit(1); printf("Child PID is %d and %s have a trap set on time().\n", (int) pstatus.pr_pid, (prismember(&pstatus.pr_sysexit, SYS_time)) ? "does" : "doesn't"); while (1) { printf("Waiting for child to call time() or exit().\n"); if (write_ctl(pid, PCWSTOP, (void *) 0, 0)) exit(1); printf("Write PCWSTOP returned. Reading status.\n"); if (read_status(pid, &pstatus)) exit(1); if (pstatus.pr_lwp.pr_syscall == SYS_exit) { printf("Child has called exit(). Bye!\n"); exit(0); } else if (pstatus.pr_lwp.pr_syscall != SYS_time) { printf("We've caught syscall %d! Eeeek!\n", (int) pstatus.pr_lwp.pr_syscall); exit(1); } printf("Child has called time().\n"); printf("LWP register R_R0 is %d.\n", (int) pstatus.pr_lwp.pr_reg[R_R0]); printf("Setting LWP register R_R0 to 123.\n"); pstatus.pr_lwp.pr_reg[R_R0] = 123; if (write_ctl(pid, PCSREG, (void *) &pstatus.pr_lwp.pr_reg, sizeof(prgregset_t))) exit(1); printf("Restarting the child.\n"); val = 0L; if (write_ctl(pid, PCRUN, (void *) &val, sizeof(long))) exit(1); printf("Restarted.\n"); } /* while (1) */ /* NOT REACHED */ } /* Child */ sleep(5); execl("/usr/bin/date", "/usr/bin/date", (char *) NULL); perror("execl failed"); return 99; }