3 # IGOR (Injection experiment GeneratOR)
5 # Tool for generating scripts running fault injection experiments
6 # based on Romain running in QEMU
8 # (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
9 # economic rights: Technische Universität Dresden (Germany)
11 # This file is part of TUD:OS and distributed under the terms of the
12 # GNU General Public License 2.
13 # Please see the COPYING-GPL-2 file for details.
23 Application configuration
27 self.config_time = time.strftime("%G%b%d-%H%M%S")
28 self.directory = "/tmp" + "/results-%s" % (self.config_time)
29 self.qemu_dir = "qemu"
32 self.l4reconf_dir = ""
43 def DryRun(self): return self.dryrun
46 def Verbose(self): return self.verbose
49 def FullDir(self): return self.directory
52 def ConfDir(self): return self.FullDir + "/config"
55 def ResDir(self): return self.FullDir + "/results"
58 def QemuDir(self): return self.qemu_dir
61 def FiascoDir(self): return self.fiasco_dir
64 def L4ReDir(self): return self.l4re_dir
67 def MaxRuns(self): return self.runs
70 def App(self): return self.app
73 def AppBinary(self): return self.App.split()[0]
76 def Mode(self): return self.mode
79 def InstallFiles(self): return self.install
82 def SleepTime(self): return self.sleep
85 def KipAddresses(self): return self.kipaddr
90 self.conf = Configuration()
91 self.parser = argparse.ArgumentParser(description = "Generate thtartup thcriptth for a Romain/QEMU-bathed THWIFI campaign.")
93 self.parser.add_argument("-c", "--config", dest="configfile", help="read config from a thource file inthtead of command line"
94 + " (overrideth all other cmdline parameterth)", default=None)
96 self.parser.add_argument("--qemu", dest="qemu", help="QEMU to uthe, default: %(default)s",
98 self.parser.add_argument("--basedir", dest="basedir", help="where to plathe rethult thubdirth, default: %(default)s",
100 self.parser.add_argument("--fiasco", dest="fiasco", help="fiathco build dir",
101 default="/path/to/fiasco/build")
102 self.parser.add_argument("--l4re", dest="l4re", help="L4Re build dir",
103 default="/path/to/l4rebuild")
104 self.parser.add_argument("--app", dest="app", help="Application (cmd line) to perform tethtth on",
107 self.parser.add_argument("--runs", dest="runs", help="no. of fault injection runth",
110 self.parser.add_argument('-d', "--dry", action="store_true", help="only print content that would be generated",
112 self.parser.add_argument("-v", "--verbose", action="store_true", help="do not throw away Qemu output",
115 self.parser.add_argument('-a', dest="inject_addr", default="0",
116 help="hex address to inject faults")
117 self.parser.add_argument('-m', dest="mode", default="gpr",
118 help="injection mode (gpr|alu|instr|rat)")
119 self.parser.add_argument('-i', dest="install", default="",
120 help="additional files to install and boot")
121 self.parser.add_argument('-s', dest="sleep", default="10",
122 help="time to keep an experiment running before killing it.")
123 self.parser.add_argument('--kip', dest="kip", default="",
124 help="kip time emulation addresses (comma-separated hex)")
127 def parse(self, args = sys.argv[1:]):
128 ns = self.parser.parse_args(args)
130 if ns.configfile is not None:
131 exec "from %s import adapt" % ns.configfile
132 exec "adapt(self.conf)"
134 self.conf.DryRun = ns.dryrun
135 self.conf.Verbose = ns.verbose
136 self.conf.MaxRuns = int(ns.runs)
137 self.conf.App = ns.app
139 self.conf.QemuDir = ns.qemu
140 self.conf.FullDir = ns.basedir + "/results-%s" % (self.conf.config_time)
141 self.conf.FiascoDir = ns.fiasco
142 self.conf.L4ReDir = ns.l4re
143 self.conf.inject_addr = int(ns.inject_addr, 16)
144 self.conf.mode = ns.mode
145 self.conf.sleep = int(ns.sleep,10)
147 self.conf.install = ns.install.split(",")
149 self.conf.kipaddr = [int(s,16) for s in ns.kip.split(",")]
154 class TemplateWriter:
158 The idea is to have a string template for the file to be written
159 and let this template be filled with arguments depending on specific
162 def __init__(self, global_config, filename):
163 self.config = global_config
164 self.filename = "%s/%s" % (self.config.ConfDir, filename)
167 print "======== %s ========" % self.filename
170 class LuaScriptWriter(TemplateWriter):
172 Generator for Romain Lua startup scripts.
174 def __init__(self, global_config, filename):
175 TemplateWriter.__init__(self, global_config, filename)
178 return """package.path = "rom/?.lua";
181 local ldr = L4.default_loader;
183 ldr:start( { caps = {} ,
184 log = {"romain", "c"},
186 "rom/romain rom/%s" );""" % self.config.App
189 TemplateWriter.write(self)
190 if self.config.DryRun:
191 print self.template()
193 f = file(self.filename, "w")
194 f.write(self.template())
197 class IniFileWriter(TemplateWriter):
199 Generator for Romain INI files
201 def __init__(self, global_config, filename):
202 TemplateWriter.__init__(self, global_config, filename)
206 ret += "page_fault_handling = rw\n"
207 ret += "romain = yes\n"
208 ret += "swifi = yes\n"
209 ret += "log = swifi\n"
210 ret += "intercept_kip = true\n"
212 if self.config.KipAddresses != []:
213 ret += "[kip-time]\n"
215 ret += "0x%08x" % self.config.KipAddresses[0]
216 for a in self.config.KipAddresses[1:]:
217 ret += (",0x%08x" % a)
224 TemplateWriter.write(self)
225 if self.config.DryRun:
226 print self.template()
228 f = file(self.filename, "w")
229 f.write(self.template())
232 class GPRIniFileWriter(IniFileWriter):
234 Generator for specific INI files aimed at flipping bits in GPRs
236 def __init__(self, global_config, filename):
237 IniFileWriter.__init__(self, global_config, filename)
240 return IniFileWriter.template(self) + """[swifi]
243 """ % (self.config.inject_addr, "gpr")
246 class InstrIniFileWriter(IniFileWriter):
248 Generator for decoder-flipping
250 def __init__(self, global_config, filename):
251 IniFileWriter.__init__(self, global_config, filename)
254 return IniFileWriter.template(self) + """[swifi]
257 """ % (self.config.inject_addr, "instr")
260 class AluIniFileWriter(IniFileWriter):
261 def __init__(self, global_config, filename):
262 IniFileWriter.__init__(self, global_config, filename)
265 return IniFileWriter.template(self) + """[swifi]
268 """ % (self.config.inject_addr, "alu")
271 class ScriptWriter(TemplateWriter):
273 Writer for the SWIFI campaign startup script
275 def __init__(self, global_config, filename):
276 TemplateWriter.__init__(self, global_config, filename)
279 build = self.config.L4ReDir
280 fiasco = "%s/fiasco -jdb_cmd=JS -serial_esc" % self.config.FiascoDir
281 ret = "%s -kernel %s/../bootstrap " % (self.config.QemuDir, build)
282 ret += "-append \"bootstrap -modaddr 0x01100000\" "
287 for s in ["sigma0", "moe rom/romain.lua", "l4re", "ned", self.config.AppBinary, "romain",]:
289 ret += "%s/%s" % (build, s)
291 for f in self.config.InstallFiles:
293 ret += "%s/%s" % (self.config.ConfDir, f.split("/")[-1])
295 ret += ",%s" % ("%s/romain.ini" % (self.config.ConfDir))
296 ret += ",%s" % ("%s/romain.lua" % (self.config.ConfDir))
298 ret += "\" -no-reboot -nographic -serial file:$filename-raw$no.log "
299 ret += "-monitor file:/dev/null"
305 ret = "#!/bin/bash\n"
307 ret += "max=%d\n" % self.config.MaxRuns
308 ret += ("logdir=%s\n" % self.config.ResDir +
309 "logprefix=swifi\n" +
310 "filename=$logdir/$logprefix\n\n" +
311 "mkdir -p $logdir\n" +
312 "while [[ $no -lt $max ]]; do\n" +
314 ret += """%s %s &\n\n"""
315 ret += " sleep %d && kill $!\n\n" % self.config.SleepTime
316 ret += """ cat $filename-raw$no.log | sed -r "s:\x1B\[[0-9;]*[A-Za-z]::g" >$filename$no.log ;
317 rm $filename-raw$no.log
324 TemplateWriter.write(self)
327 if (not self.config.Verbose):
328 verbose_redir = ">/dev/null 2>/dev/null"
330 if self.config.DryRun:
331 print self.template() % (self.qemu_cmd(), verbose_redir)
333 f = file(self.filename, "w")
334 f.write(self.template() % (self.qemu_cmd(), verbose_redir))
335 os.chmod(self.filename, 0700)
338 class AdditionalFileInstaller:
339 def __init__(self, globalconfig):
340 self.config = globalconfig
343 print "======== Installing files ========"
344 for f in self.config.InstallFiles:
345 print f, "->", self.config.ConfDir
346 if not self.config.DryRun:
347 os.symlink(f, "%s/%s" % (self.config.ConfDir, f.split("/")[-1]))
350 class CampaignRunner:
351 def __init__(self, config):
353 self.script = "%s/swifi.sh" % self.conf.ConfDir
356 print "======== Exthecuting ========"
357 if not self.conf.DryRun:
359 subprocess.call(self.script)
361 print "Not exthecuting %s in a dry run." % self.script
365 "alu" : AluIniFileWriter,
366 "gpr" : GPRIniFileWriter,
367 "instr" : InstrIniFileWriter,
372 if not config.DryRun:
373 os.mkdir(config.FullDir)
374 os.mkdir(config.ConfDir)
375 os.mkdir(config.ResDir)
377 writers[config.Mode](config, "romain.ini").write()
378 LuaScriptWriter(config, "romain.lua").write()
379 ScriptWriter(config, "swifi.sh").write()
380 AdditionalFileInstaller(config).install()
381 CampaignRunner(config).run()
383 if __name__ == "__main__":
384 run(ArgumentParser().parse())