| prev Translate | Page next | |
This document is also available as:
"sole guardian of numerous children running and playing in a huge rye field on the edge of a cliff"
"sole guardian of numerous processes running and playing in a huge binary field on the edge of a syscalls"
「自分は、広いバイナリ畑で遊んでいるプログラムたちが、気付かずにシステムコールから落ちそうになったときに、捕まえてあげるような、そんなサービスを作りたい」
is a simple CGI that runs a given program in a chrooted field
Directory Hierarchy
% find . -xdev | sort ./0123456789abcdef ./0123456789abcdef/eval.pl ./bin ./dev ./etc ./etc/localtime ./etc/protocols ./etc/services ./lib ./libexec ./libexec/ld-elf.so.1 ./libexec/ld-elf.so.1.old ./tmp ./usr ./usr/bin ./usr/bin/bwbasic ... ./usr/bin/perl ... ./usr/bin/tclsh ./usr/lib ./usr/local ./usr/local/bin ./usr/local/lib ./usr/local/libexec ./usr/local/perl6 ./usr/local/share ./var ./var/run ./var/run/ld-elf.so.hints ./var/run/ld.so.hints
Directory Hierarchy
libraries are mounted read-only via nullfs
/lib /home/chroot/lib nullfs ro,noatime,nosuid 0 0 /usr/lib /home/chroot/usr/lib nullfs ro,noatime,nosuid 0 0 /usr/local/lib /home/chroot/usr/local/lib nullfs ro,noatime,nosuid 0 0 /usr/local/libexec /home/chroot/usr/local/libexec nullfs ro,noatime,nosuid 0 0 /usr/local/share /home/chroot/usr/local/share nullfs ro,noatime,nosuid 0 0 /usr/local/perl6 /home/chroot/usr/local/perl6 nullfs ro,noatime,nosuid 0 0
# simple strace in perl use strict; use warnings; use FreeBSD::i386::Ptrace; use FreeBSD::i386::Ptrace::Syscall; die "$0 prog args ..." unless @ARGV; my $pid = fork(); die "fork failed:$!" if !defined($pid);
  if ( $pid == 0 ) {    # son
    pt_trace_me;
    exec @ARGV;
  }
  else {                # mom
    wait;               # for exec;
    my $count = 0;
    while ( pt_to_sce($pid) == 0 ) {
        last if wait == -1;
        my $call = pt_getcall($pid);
        pt_to_scx($pid);
        wait;
        my $retval = pt_getcall($pid);
        my $name = $SYS{$call} || 'unknown';
        print "$name() = $retval\n";
        $count++;
    }
    warn "$count system calls issued\n";
  }
http://labs.cybozu.co.jp/blog/kazuho/
archives/2009/03/freebsd_ptrace.php
You can't stop the invocation but you can still poke the argument on the stack.
sub check_open {
    my $pid  = shift;
    my $regs = pt_getregs($pid);
    my $st1  = pt_read( $pid, $regs->esp + 8 );
    if ( $st1 & ( O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC ) ) {
        if ( my $st0 = pt_read( $pid, $regs->esp + 4 ) ) {
            if ( my $path = pt_peekstr( $pid, $st0 ) ) {
                pt_write( $pid, $st0, 0 );
                ptrace( PT_CONTINUE, $pid, 0, 9 );
                die qq{XXX:open("$path",$st1)\n};
            }
        }
    }
}
You can't prevent [rv]?fork but you still send them to the oblivion
pt_continue($pid, 0, 9);
both son & mom die w/ SEGV
But you can still run a program on SEGV via $SIG{SEGV}
$SIG{SEGV} = sub{
    while(1){
        warn "$$: don't kill me, please!";
        sleep(1);
    }
};
You can catch that, too.
sub check_sigaction {
    my ($pid)  = @_;
    my $regs = pt_getregs($pid);
    my $st0 = pt_read( $pid, $regs->esp + 4 );
    my $st1 = pt_read( $pid, $regs->esp + 8 );
    my $st2 = pt_read( $pid, $regs->esp + 12 );
    if ($st0 == 11 && $st1 != 0 && $sigactions++ >= $sigaction_ok){
        pt_write( $pid, $st0, 0 );
        pt_write( $pid, $st1, 0 );
        pt_write( $pid, $st2, 0 );
        ptrace( PT_CONTINUE, $pid, 0, 9 );
        die qq{XXX:sigaction($st0, $st1, $st2)\n};
    }
}
Address 0x00000000 might not be the oblivion.
syscall(&SYS_mmap,
        0,4096,
        PROT_READ|PROT_WRITE|PROT_EXEC,
        MAP_FIXED|MAP_ANON,
        -1,0,0);
You can catch that, too.
sub check_mmap {
    my ($pid)  = @_;
    my $regs = pt_getregs($pid);
    my $st0 = pt_read( $pid, $regs->esp + 4 );  # addr
    my $st1 = pt_read( $pid, $regs->esp + 8 );  # len
    my $st2 = pt_read( $pid, $regs->esp + 12 ); # prot
    my $st3 = pt_read( $pid, $regs->esp + 16 ); # flags
    my $st4 = pt_read( $pid, $regs->esp + 20 ); # fd
    my $st5 = pt_read( $pid, $regs->esp + 24 ); # offset
    if ($st2 & 0x04 && $st3 & 0x10){
        pt_write( $pid, $st0, 0 );
        pt_write( $pid, $st1, 0 );
        pt_write( $pid, $st2, 0 );
        pt_write( $pid, $st3, 0 );
        pt_write( $pid, $st4, 0 );
        pt_write( $pid, $st5, 0 );
        ptrace( PT_CONTINUE, $pid, 0, 9 );
        die qq{XXX:mmap($st0, $st1, $st2, $st3, $st4, $st5)\n};
    }
}
Let children play free -- Just CATCH before they fall off from the cliff!
while(my $q = Questions->new){
  $q->answer;
}