Bugtraq mailing list archives

Re: Clarification: LD_PRELOAD issue


From: dbrown () CCDC CAM AC UK (Daniel Brown)
Date: Tue, 18 May 1999 15:40:38 +0100


Here's a similar snippet for Solaris using the procfs interface...

Dan.

--

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <sys/uio.h>

#include <fcntl.h>
#include <procfs.h>
#include <stdio.h>
#include <unistd.h>

/* 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;
}



Current thread: