Re: closefd: closes a file of any process

From: Tim Waugh (twaugh@redhat.com)
Date: Fri Jun 23 2000 - 11:27:03 EST


On Fri, Jun 23, 2000 at 05:13:08PM +0100, Tigran Aivazian wrote:

> PPS. You could write another module called munmap.o and another fchroot
> and another fchdir and another catch_rights_dgram_in_flight.o or if you
> see what I mean :)

Actually, while I think of it, does some kind hacker want to tell me
why this works (or rather, why I have to jump through the hoops I do)?

I know that it's violently ugly code already, before you tell me. ;-)

Thanks
Tim.
*/

/*
 * pchdir - change the cwd of a process
 * -or-
 * a really ugly hack
 *
 * (C) 2000 Tim Waugh <twaugh@redhat.com>
 *
 * There is some black magic here, which I don't fully
 * understand.
 * 1. I have to add some to %eip or else it won't go at all
 * 2. That means the first instruction doesn't happen, so I poke %ebx
 * 3. I need to single step afterwards to avoid ERESTARTSYS
 *
 */

#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
        pid_t victim;
        char *dir = "/"; /* just for diagnostics */
        int l = 4;
        unsigned long old[100];

/* chdir:
           movl $.root,%ebx
           mov $0xc,%eax
           int $0x80
           int $0x3
   .root:
           .string "/\0"
*/

        unsigned long new[100] = {
                0x04800dbb,
                0x000cb808,
                0x80cd0000,
                0x00002fcc,
        };
        void *addr = (void *) 0x08048000;
        struct user_regs_struct regs;
        struct user_regs_struct old_regs;
        int i;

        if (argc < 2) {
                fprintf (stderr, "too few args\n");
                exit (1);
        }

        victim = strtoul (argv[1], NULL, 0);
        if (argc > 2) {
                l = strlen (argv[2]);
                if (l < (100*4-13)) {
                        strcpy (13 + (void*)new, argv[2]);
                        l = (l + 1) / 4 + 4;
                        dir = argv[2];
                }
        }
        ptrace (PTRACE_ATTACH, victim, NULL, NULL);
        wait (NULL);

        /* Put out code in the text segment */
        for (i = 0; i < l; i++) {
                old[i] = ptrace (PTRACE_PEEKTEXT, victim,
                                 addr + i * sizeof (void *), NULL);
                ptrace (PTRACE_POKETEXT, victim,
                        addr + i * sizeof (void *), new[i]);
        }

        ptrace (PTRACE_GETREGS, victim, NULL, &regs);
        old_regs = regs;
        regs.eip = 5 + (long) addr;
        regs.ebx = 13 + (long) addr;
        ptrace (PTRACE_SETREGS, victim, NULL, &regs);
        ptrace (PTRACE_GETREGS, victim, NULL, &regs);
        
        /* The trap is set */
        ptrace (PTRACE_SINGLESTEP, victim, NULL, NULL);
        wait (NULL);
        ptrace (PTRACE_SYSCALL, victim, NULL, NULL); /* setup */
        wait (NULL);
        ptrace (PTRACE_SYSCALL, victim, NULL, NULL); /* syscall */
        wait (NULL);
        ptrace (PTRACE_SINGLESTEP, victim, NULL, NULL); /* fixup */
        wait (NULL);
        ptrace (PTRACE_GETREGS, victim, NULL, &regs);

        /* Restore normality */
        ptrace (PTRACE_SETREGS, victim, NULL, &old_regs);
        for (i = 0; i < l; i++) {
                ptrace (PTRACE_POKETEXT, victim,
                        addr + i * sizeof (void *), old[i]);
        }
        ptrace (PTRACE_DETACH, victim, NULL, NULL);
        wait (NULL);

        if (regs.eax) {
                int i = -(int)regs.eax;
                printf ("%s: %s\n", dir, sys_errlist[i]);
                return i;
        }

        return 0;
}



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jun 23 2000 - 21:00:26 EST