def execve(self, pid): enter = self.arg dbg.infom("!", "#R<re-execute#>: %s" % str(enter)) fn = enter.args["filename"].path argv = enter.args["argv"] envp = enter.args["envp"] [ret, root, pwd, fds] = self.ret.aux # set sequence number as execve()'s sid self.seq = enter.sid & ((1 << 48) - 1) + 1 # XXX # - setup fds self.proc = rerun.Ptrace([fn] + argv[1:], envp, kutil.get(pwd), kutil.get(root) if root.ino != 2 else None, self.uids) # enter/exit should be execve() too (r, p) = self.proc.load(True, None) (r, p) = self.proc.load(False, None) assert r.usage & EXIT and r.nr == syscall.NR_execve # virtualize pid self.pids[pid] = r.pid dbg.rerun("vpid:%s -> pid:%s (active)" % (pid, r.pid)) # enable rerun module self.state = "active"
def syscall_read(self, arg, ret): r = arg.data assert r.nr == syscall.NR_read fd = arg.data.args["fd"] inode = fd.inode dbg.syscallm("!", "#R<read#>: reading %s with %s" % (inode, r)) # read & create mock object pn = kutil.get(inode) with open(pn, 'r') as f: f.seek(fd.offset) file_data = f.read(r.args["count"]) sha = sha1(file_data) dbg.syscallm("!", "#R<read#>: sha1:%s (old:%s)" \ % (hexdigest(sha), hexdigest(ret.origdata.args["buf"]))) new_data = deepcopy(ret.origdata) new_data.args["buf"] = sha new_data.args["real_buf"] = file_data new_data.ret = len(file_data) return new_data
def syscall_open(self, arg, ret): r = arg.data assert r.nr == syscall.NR_open assert ((r.args["path"].inode is None) or (r.args["path"].inode == r.ret.inode)) inode = r.ret.inode dbg.syscallm("!", "#R<open#>: %s" % (str(r))) if runopts.dryrun: return ret.origdata pn = r.args['path'].path # pathname to file # if not absolute pathname, retrieve with iget if not pn.startswith('/'): dentry = r.args['path'].entries[0] assert type(dentry) == sysarg.dentry pn = os.path.join("%s/%s" % (kutil.get(dentry.parent), dentry.name)) # flag == os.O_CREAT and only the case we really created an empty file if (r.args["path"].inode is None): src_pn = os.path.join(kutil.fsget(inode.dev), ".inodes", str(inode.ino)) # to keep the inode os.rename(src_pn, pn) # make it empty when newly created with open(pn, "w") as f: pass dbg.syscallm("!", "#R<rename#>: %s -> %s" % (src_pn, pn)) # if explicit truncate request if (r.args['flags'] & os.O_TRUNC): with open(pn, "w") as f: pass # If the syscall opened a _different_ inode than the file # points to now. path = r.args['path'] arg_name = path.path dir_dev = path.entries[0].parent.dev dir_ino = path.entries[0].parent.ino dirent = fsmgr.DirentDataNode.get(dir_dev, dir_ino, arg_name) (cur_dev, cur_ino) = dirent.get_file_dev_ino() ret.data = deepcopy(ret.origdata) ret.data.ret.inode.ino, ret.data.ret.inode.dev = (cur_ino, cur_dev) return ret.data
def syscall_write(self, arg, ret): r = arg.data assert r.nr == syscall.NR_write dbg.syscallm( "!", "#R<write#>: %d with %s" % (r.args["fd"].inode.ino, str(r))) if runopts.dryrun: return ret.origdata fd = r.args["fd"] # XXX pts if not fd.inode.prefix in ["file"]: print "-" * 60 print r.args["buf"] print "-" * 60 return ret.origdata # regular write on files cur_pn = kutil.get(fd.inode) offset = fd.offset f = open(cur_pn, "r+") # append if offset == -1: f.seek(0, os.SEEK_END) else: f.seek(offset) f.write(r.args["buf"]) f.close() # XXX # dynamically generated snapshots for fast lookup # dev = fd.inode.dev # ino = fd.inode.ino # tic = ret.origdata.ts # cp = fsmgr.FileContentCheckpoint(tic, tic, dev, ino) # fsmgr.FileDataNode.get(dev, ino).checkpoints.add(cp) # XXX update ret node return ret.origdata
def equiv(self): # ipopov: conjecture: the following four lines are probably to # guard against equiv() going ahead with incomplete data about # argument values and return values and such. if self.argsnode is None or self.retnode is None: return False if self.argsnode.data is None or self.retnode.data is None: return False if (hasattr(self.argsnode, "rerun") and self.argsnode.rerun.is_active()): return False r = self.argsnode.data if r.nr == syscall.NR_read: fd = r.args["fd"] dev = fd.inode.dev ino = fd.inode.ino off = fd.offset cnt = self.retnode.data.ret sha = self.retnode.data.args["buf"] if not fd.inode.prefix in ["file"]: return False src_pn = kutil.get(fd.inode) with open(src_pn, 'r') as f: f.seek(off) h = sha1(f.read(cnt)) dbg.sha1m("!", "%s vs %s = %s" \ % (hexdigest(h), hexdigest(sha), h == sha)) return h == sha return False elif r.nr == syscall.NR_open: path = r.args['path'] arg_name = path.path dir_dev = path.entries[0].parent.dev dir_ino = path.entries[0].parent.ino ret_dev = self.retnode.data.ret.inode.dev ret_ino = self.retnode.data.ret.inode.ino dirent = fsmgr.DirentDataNode.get(dir_dev, dir_ino, arg_name) (cur_dev, cur_ino) = dirent.get_file_dev_ino() #code.interact(local=locals()) dbg.info('open on %s yields (dev, ino) (%s, %s) origdata was' '(%s %s)' % (path, cur_dev, cur_ino, ret_dev, ret_ino)) if (cur_dev, cur_ino) == (ret_dev, ret_ino): # XXXX what if the file got _created_ by the open syscall? i.e. # if r.args['path'] contains no inode? return True else: return False if self.argsnode.origdata == self.argsnode.data: return True # # add any cases to stop the propagations # dbg.warn('#Y<XXX#> not quite right') return False