Example #1
0
def cmd_repair(fd, args):
    """repairing attacks: hint attacker"""
    if len(args) < 1:
        cmd_help(fd)
        return

    hint = args[0]
    pick = "pick_attack_execve" if len(args) < 2 else args[1]
    name = attacker.find_attack_node(logd, pick, hint)

    attack = mgrapi.RegisteredObject.by_name_load(name)
    if attack is None:
        dbg.error('missing attack node:', name)
        return

    chkpt = max(c for c in attack.checkpoints if c < min(attack.actions))

    assert chkpt
    assert len(attack.actions) == 1

    for a in attack.actions:
        dbg.info("cancel: %s" % a.argsnode)
        a.argsnode.data = None
        a.cancel = True

    dbg.info("pick:", chkpt)

    The(CtrlFSM).set_state("repairing")
    ctrl.repair(attack, chkpt)
    The(CtrlFSM).set_state("init")

    rtn_cmd(fd, "done")
Example #2
0
def explore_path(path, match):
    m = []
    for l in path.effects:
        if isinstance(e, PathCall):
            if e.func == match.func:
                m.append(e)
    # error: if more than single instance
    if len(m) != 1:
        dbg.error("! error (L=%d): %s", len(m), str(path))
        for l in m:
            dbg.error("! NOTE: %s", str(l))
Example #3
0
def main():
    atexit.register(retroctl.disable)

    parser = optparse.OptionParser(usage="%prog [options] LOG-DIRECTORY")
    parser.add_option("-d",
                      "--dry",
                      default=False,
                      action="store_true",
                      dest="dryrun",
                      help="dry run for repair")
    parser.add_option("-p",
                      "--profile",
                      default=False,
                      action="store_true",
                      dest="profile",
                      help="profiling execution time")

    (opts, args) = parser.parse_args()

    if opts.profile:
        runopts.set_profile()

    if len(args) != 2:
        parser.print_usage()
        exit(1)

    osloader1 = osloader.OsLoader(args[0])

    # Ensure that all syscalls have been loaded, hence connected
    osloader1.all()
    nodes1 = mgrapi.RegisteredObject.all()

    # Only load second executions's objects after we've safely stowed the
    # relevant part of the first's graph
    osloader2 = osloader.OsLoader(args[1])

    d = {}
    filenodes = [
        node for node in nodes1 if isinstance(node, fsmgr.FileDataNode)
    ]
    for node in filenodes:
        try:
            chkpt = min(node.checkpoints)
        except AttributeError:
            dbg.error('skipping rollback due to lack of checkpoints')
            continue
        else:
            assert chkpt
            d[node] = chkpt

    runopts.set_dryrun(opts.dryrun)
    ctrl.repair2(d)
Example #4
0
 def _read_records(self, offlist):
     records = []
     for (fidx, offset) in sorted(offlist):
         f = self.sfs[fidx]
         f.seek(0, 2)
         flen = f.tell()
         if offset >= flen:
             dbg.error('XXX system call offset out of range', offset, flen,
                       f.name)
             continue
         f.seek(offset)
         try:
             r = read_syscall(f)
             records.append(r)
         except EOFError:
             ## Unfortunate, but ...
             pass
     return records
Example #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!')
Example #6
0
    def register(self):
        if self.retnode: self.outputset.add(self.retnode)
        if self.argsnode: self.inputset.add(self.argsnode)

        # register() should work even with only one retnode/argsnode
        dbg.connect("%s => connect(): (%s,%s)" %
                    (self, self.argsnode, self.retnode))

        # WTF???!!! This can (and does) put the return value of the system
        # call into the node for the argument node! :(
        # XXXX
        # Why is this necessary???
        # XXXX
        # merge a bit for compatibility
        r = None
        if self.argsnode and self.argsnode.data:
            r = self.argsnode.data
        else:
            if self.retnode and self.retnode.data:
                r = self.retnode.data
        if r and self.retnode and self.retnode.data:
            setattr(r, "ret", self.retnode.data.ret)

        if r is None:
            return

        (rs, ws) = nrdep.nrdep(r)
        for x in rs | ws:
            objs = []
            if type(x) == sysarg._inode:
                if x.prefix in ('file', 'link', 'dir'):
                    n = fsmgr.FileDataNode.get(x.dev, x.ino)
                    # add checkpoints of unlink syscall
                    if r.name in ["unlinkat", "unlink", "rmdir"]:
                        # find inodes in the .inodes
                        self.__search_checkpoints(n, x)
                    objs.append(n)
                elif x.prefix == 'socket':
                    n = sockmgr.SocketNode.get(x)
                    objs.append(n)
                    if n.sport and n.dip and n.dport:
                        objs.append(networkmgr.NetworkNode.get(x))
                # elif x.prefix in ['pts', 'ptm']:
                #   objs.append(ptymgr.PtyNode.get(os.major(x.rdev), 0))
                # elif x.prefix == 'fifo':
                #   objs.append(fifomgr.FifoNode.get(x))
                # elif x.prefix == 'cdev':
                #   objs.append(cdevmgr.CdevNode.get(x))
                else:
                    dbg.error('need data node for inode type', x.prefix)
            elif type(x) == sysarg.process:
                dbg.info('pid:%s -> pid:%s' % (r.pid, x))
            elif type(x) == sysarg.dentry:
                objs.append(
                    fsmgr.DirentDataNode.get(x.inode.dev, x.inode.ino, x.name))
            else:
                dbg.error('need data node for', x, 'type', type(x))

            if len(objs) != 0:
                for n in objs:
                    if x in rs: self.inputset.add(n)
                    if x in ws: self.outputset.add(n)
Example #7
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)