Ejemplo n.º 1
0
    def redo(self, dryrun):
        dbg.syscall("%d: %s" % (self.ob.ticket, self.ob))

        if not dryrun:
            if self.ob.ret != -1:
                p = self.ob.args["path"].path
                dbg.syscall("unlinking fd:%s" % p)
                os.unlink(p)
Ejemplo n.º 2
0
    def redo(self, dryrun):
        cur_pn = kutil.iget("/mnt/retro/trunk", self.ob.ret.inode.ino)

        if not dryrun:
            if self.ob.args["flags"] & os.O_TRUNC:
                dbg.syscall("%d: %s" % (self.ob.ticket, self.ob))
                dbg.syscall("creating empty file, %s" % cur_pn)

                open(cur_pn, "w").close()
Ejemplo n.º 3
0
    def flatten(self):
        """Set tic[0] to tac[0].

    Used for wait4 rescheduling."""
        assert self.retnode
        assert len(self.retnode.readers) == 1
        procSysRet = list(self.retnode.readers)[0]
        newtic = procSysRet.tic
        newtac = procSysRet.tac
        dbg.syscall('setting tic,tac %s %s -> %s %s' %
                    (self.tic, self.tac, newtic, newtac))
        self.tic, self.tac = newtic, newtac
Ejemplo n.º 4
0
    def redo(self, dryrun):
        cur_pn = kutil.iget("/mnt/retro/trunk", self.ob.args["fd"].inode.ino)

        dbg.syscall("%d: %s" % (self.ob.ticket, self.ob))
        dbg.syscall("re-writing to fd:%s" % cur_pn)

        if not dryrun:
            offset = self.ob.args["fd"].offset

            f = open(cur_pn, "r+")
            # append
            if offset == -1:
                f.seek(0, os.SEEK_END)
            else:
                f.seek(offset)
            f.write(self.ob.args["buf"])
            f.close()
Ejemplo n.º 5
0
    def redo(self):
        if self.argsnode.data is None:
            dbg.syscall("no argsnode data for %s, returning prematurely" %
                        self)
            return

        if (hasattr(self.argsnode, "rerun")
                and self.argsnode.rerun.is_active()):
            rerun = self.argsnode.rerun
            pid = self.argsnode.data.pid
            expanding = not hasattr(
                self, 'parent_retnode') or not self.parent_retnode
            if expanding:
                child_pid = None
            else:
                child_pid = self.parent_retnode.origdata.ret
            (r, p) = rerun.clone(pid, child_pid)
            r.sid = self.argsnode.data.sid  # TODO(ipopov): refactor into __fix_sid()

            if expanding:
                # This creates parent_retnode and child_retnode
                self.osloader.parse_record(r)
            else:
                self.child_retnode.data = deepcopy(self.child_retnode.origdata)
                self.parent_retnode.data = deepcopy(
                    self.parent_retnode.origdata)
                # TODO(ipopov): should we change the retvalue here? (probably
                # not)

            # find child actor and setup for rerun
            r = self.parent_retnode.data
            child = ProcessActor.get(r.ret, r)
            child.rerun = rerun
            rerun.add(child)
        else:
            # This should not happen.
            dbg.error('no redo performed for clonesyscall action!')
Ejemplo n.º 6
0
    def redo(self):
        dbg.syscall("redoing ProcSysRet")

        if not self.actor.rerun and getattr(self.retnode, 'rerun', None):
            self.actor.rerun = self.retnode.rerun

        if self.retnode.data is None:
            # This probably means that the retnode has been rolled back to
            # its (-Inf, -Inf, None) checkpoint and has not been updated
            # (rolled forward), probably because the syscall that was to
            # fill it never got executed.
            dbg.syscall("no argsnode data for %s, returning prematurely" %
                        self)
            return

        # start shepherded re-execution
        if self.retnode.data.name == "execve" and not self.actor.rerun:
            dbg.rerun('actor %s (%s) has no rerun object' %
                      (self.actor, id(self.actor)))
            # create rerun process
            (arg, ret) = self.actor.get_execve()
            if hasattr(self, "uids"):
                rerun = Rerun(arg, ret, self.uids)
            else:
                rerun = Rerun(arg, ret)
            rerun.execve(self.actor.pid)

            # process actor has a reference to the rerun module
            self.actor.rerun = rerun
            rerun.add(self.actor)
            return

        if self.actor.rerun and self.actor.rerun.is_expanding():
            pid = self.retnode.data.pid
            (r, p) = self.actor.rerun.next(True, pid)
            if r == None:
                return
            assert r.usage & ENTER

            # pass rerun object to the bumped process
            if r.pid != self.retnode.data.pid:
                assert r.pid == pid
                actor = ProcessActor.get(r.pid, r)
                actor.rerun = self.actor.rerun
                actor.rerun.add(actor)

            # create pcall action
            self.osloader.parse_record(r)
            return
        # It's not undesirable that we fall through to here. ProcSysRets should
        # only be reexecuted if there is some information to be handed back to the
        # process (which there never should be, because in such a circumstance, the
        # rerun module would already be active, and receiving "sysret nodes"
        # directly from the kernel, as it were).
        dbg.syscall('ignoring Procsysret redo request')
Ejemplo n.º 7
0
 def redo(self, dryrun):
     dbg.syscall("re-executing %s", self.ob)
     if not dryrun:
         print self.ob.ret
         [ret, root, pwd, fds] = self.ob.ret
     pass
Ejemplo n.º 8
0
    def redo(self):
        dbg.syscall("redoing")
        if self.argsnode.data is None:
            dbg.syscall("no argsnode data for %s, returning prematurely" %
                        self)
            return

        # share expanding & following
        if (hasattr(self.argsnode, "rerun")
                and self.argsnode.rerun.is_active()):
            rerun = self.argsnode.rerun
            pid = self.argsnode.data.pid

            # wait syscalls: make it non-blocking
            if self.argsnode.data.name == "wait4":
                result = rerun.wait4(pid)
                if not result:
                    self.flatten()
                    raise mgrapi.ReschedulePendingException
                else:
                    (r, p) = result
            elif self.argsnode.data.name == "exit_group":
                (r, p) = rerun.exit_group(pid)
                # from Taesoo:
                # while expanding (after canceling all nodes), you should
                # create new node (pcall) to dynamically create new nodes of
                # parents
                #
                # The current process is exiting. But, perhaps its reexecution
                # has spawned new children that must persist.
                if rerun.is_expanding() and len(rerun.pids) >= 1:
                    for childpid in rerun.pids:
                        dbg.info("reviewing: %s" % childpid)
                        (childr, childp) = rerun.next(True, childpid)
                        assert childr.usage & ENTER
                        self.osloader.parse_record(childr)
                return
            else:
                (r, p) = rerun.next(False, pid)

            r.sid = self.argsnode.data.sid

            # Is this actually true?:
            # Vestigial, from Taesoo: r is None with exit_group()-like
            # syscalls
            assert not r or (r and r.usage & EXIT)
            if r:
                # self.retnode exists iff the exit record has already been
                # parsed for the syscall in question, i.e. iff this syscall
                # has already been carried out, i.e. iff we are retracing it.
                if self.retnode:  # following
                    self.retnode.data = deepcopy(self.retnode.origdata)
                    self.retnode.data.ret = r.ret
                else:  # exploring new nodes/edges
                    self.osloader.parse_record(r)
            self.retnode.rerun = rerun
            return
        else:
            r = self.argsnode.data
            func = getattr(self, "syscall_%s" % r.name, None)
            if func:
                # exit_group() has no retnode
                if self.retnode:
                    self.retnode.data = func(self.argsnode, self.retnode)
                return
                # raise Exception('not impl')
                dbg.error("Not implemented:", r.name)
Ejemplo n.º 9
0
    def redo(self):
        """Execute another action of this action's actor. If the greedy
    heuristic matches the current action to the action just executed,
    we're fine. Otherwise, call parse_record() to create a new node in
    the action history graph.
    """

        dbg.syscall("redoing")
        rerun = self.actor.rerun

        if not rerun:
            dbg.syscall("no rerun instance bound to ProcSyscall %s;"
                        "returning prematurely" % self)
            return

        # following history while rerunning
        if rerun.is_following():
            (r, p) = rerun.next(True, self.actor.pid)
            if r == None:
                dbg.syscall('Aborting syscall; rerun returned no record')
                return
            assert r.usage & ENTER

            # special treatment of wait4
            # (see note in wait4.doc)
            # The following if statement seems pretty impenetrable. What I think it
            # does is the following. If a process under rerun tries to execute a
            # wait4, but that doesn't match up with the expected syscall from the
            # previous execution, call code.interact() and handle it manually.
            if (r.nr == syscall.NR_wait4
                    and self.argsnode.origdata.nr != syscall.NR_wait4):
                dbg.rerun('entering interactive')
                code.interact(local=locals())

                # wait4() again, at this time we should be able
                # to fetch child exit status
                (r, p) = rerun.next(False, self.actor.pid)
                assert r.usage & ENTER and r.nr == syscall.NR_wait4

                # this is a real system call we should execute
                # on this action node
                (r, p) = rerun.next(True, self.actor.pid)
                assert r.usage & ENTER

            # match up
            if (self.argsnode.origdata.nr == r.nr
                    and check_args(r, self.argsnode.origdata)):
                # update arguments
                self.argsnode.data = deepcopy(self.argsnode.origdata)
                self.argsnode.data.args = r.args
                self.argsnode.rerun = rerun

            # failed: need to explore/create new nodes/edges
            else:
                dbg.infom(
                    "!", "#R<mismatched#> syscalls: %s vs %s" %
                    (self.argsnode.origdata, r))
                assert self.argsnode.data == None
                ts = 0
                for a in rerun.actors:
                    t = max(a.actions)
                    if ts < t.tac:
                        ts = t.tac

                rerun.detach(r, ts)

                # Actually create a new node to correspond to what was just
                # executed.
                self.osloader.parse_record(r)

        # rerunning but creating new nodes/edges
        elif rerun.is_state("detached"):
            # if detached node
            if rerun.wait_r == self.argsnode.origdata:
                rerun.resume()
                #rerun.activate()

        # ipopov: ????
        if rerun.is_expanding():
            self.argsnode.data = self.argsnode.origdata
            self.argsnode.rerun = rerun
Ejemplo n.º 10
0
    def parse_record(self, r):
        argsnode = None
        retnode = None
        retnode_child = None
        retnode_parent = None

        is_clone = r.nr in [NR_clone, NR_fork, NR_vfork]

        # enter
        if r.usage & ENTER:
            actor_call = procmgr.ProcessActor.get(r.pid, r)
            argsname = actor_call.name + ('sysarg', r.sid)
            if mgrapi.RegisteredObject.by_name(argsname) is None:
                argsnode = mgrutil.BufferNode(argsname, r.ts + (2, ), r)
                pc = procmgr.ProcSysCall(actor_call, argsnode, self)
                pc.tic = r.ts + (0 + r.pid.gen, )
                pc.tac = r.ts + (1 + r.pid.gen, )
                pc.connect()

        # exit
        if r.usage & EXIT:
            if not is_clone:
                actor_ret = procmgr.ProcessActor.get(r.pid, r)
                retname = actor_ret.name + ('sysret', r.sid)
                if mgrapi.RegisteredObject.by_name(retname) is None:
                    retnode = mgrutil.BufferNode(retname, r.ts + (1, ), r)
                    pr = procmgr.ProcSysRet(actor_ret, retnode, self)
                    pr.tic = r.ts + (2 + r.pid.gen, )
                    pr.tac = r.ts + (3 + r.pid.gen, )
                    if r.nr == NR_execve:
                        assert hasattr(r, "uids")
                        setattr(pr, "uids", r.uids)
                    pr.connect()
            else:
                actor_child = procmgr.ProcessActor.get(r.ret, r)
                actor_parent = procmgr.ProcessActor.get(r.pid, r)

                retname_parent = actor_parent.name + ('sysret', r.sid)
                retname_child = actor_child.name + ('sysret', r.sid)
                dbg.syscall('parentnode %s' %
                            mgrapi.RegisteredObject.by_name(retname_parent))
                if mgrapi.RegisteredObject.by_name(retname_parent) is None:
                    retnode_parent = mgrutil.BufferNode(
                        retname_parent, r.ts + (1, ), r)
                    pr = procmgr.ProcSysRet(actor_parent, retnode_parent, self)
                    pr.tic = r.ts + (4 + r.pid.gen, )
                    pr.tac = r.ts + (5 + r.pid.gen, )
                    pr.connect()
                dbg.syscall('childnode %s' %
                            mgrapi.RegisteredObject.by_name(retname_child))
                if mgrapi.RegisteredObject.by_name(retname_child) is None:
                    retnode_child = mgrutil.BufferNode(retname_child,
                                                       r.ts + (1, ), r)
                    pr = procmgr.ProcSysRet(actor_child, retnode_child, self)
                    pr.tic = r.ts + (2 + r.pid.gen, )
                    pr.tac = r.ts + (3 + r.pid.gen, )
                    pr.connect()

        if is_clone:
            sc = procmgr.CloneSyscallAction.get(r, self)
            dbg.syscall(
                'populating sc %s with parent_retnode %s and child_retnode %s'
                % (sc, retnode_parent, retnode_child))
            if retnode_parent: sc.parent_retnode = retnode_parent
            if retnode_child: sc.child_retnode = retnode_child
        else:
            sc = procmgr.SyscallAction.get(r, self)
            if retnode: sc.retnode = retnode

        if argsnode: sc.argsnode = argsnode
        if r.usage & ENTER: sc.tic = r.ts + (3, )
        if r.usage & EXIT: sc.tac = r.ts + (0, )

        ## Some system calls do not have return records
        ## (or return value objects, but that's OK for now.)
        if r.nr in [NR_exit, NR_exit_group]: sc.tac = r.ts + (4, )

        sc.connect()

        return sc