move fail binaries

This commit is contained in:
2026-03-18 19:54:44 +01:00
parent 5d4d84de39
commit a6a335aaf4
33 changed files with 23 additions and 2 deletions

View File

@ -0,0 +1,147 @@
#!/usr/bin/python3
import os, sys
from optparse import OptionParser
from subprocess import *
from tempfile import mkstemp, mkdtemp
import shutil
from distutils.spawn import find_executable
import os.path
def parseArgs():
parser = OptionParser()
parser.add_option("-e", "--elf-file", dest="elf_file",
help="elf file to be executed", metavar="ELF")
parser.add_option("-i", "--iso-file", dest="iso_file",
help="iso file to be executed", metavar="ISO")
parser.add_option("-f", "--fail-client", dest="fail_client",
help="fail-client to be executed", metavar="ISO")
parser.add_option("-m", "--memory", dest="memory", default="16",
help="memory for the bochs VM", metavar="SIZE")
parser.add_option("-b", "--bios", dest="bios", default="/fs/proj/i4ezs/tools/fail-ws21/buildartifacts/BIOS-bochs-latest",
help="bios image for bochs", metavar="BIOS")
parser.add_option("-V", "--vgabios", dest="vgabios", default="/fs/proj/i4ezs/tools/fail-ws21/buildartifacts/vgabios.bin",
help="vgabios image for bochs", metavar="VGABIOS")
parser.add_option("-F", "--freq", dest="freq", default="5",
help="frquency in MHZ", metavar="MHZ")
parser.add_option("-1", "--once",
action="store_false", dest="forever", default=True,
help="fail-client to be executed")
parser.add_option("-j", "--jobs",
dest="jobs", default="1",
help="parallel execution")
(options, args) = parser.parse_args()
if not (options.elf_file and options.iso_file and options.fail_client):
parser.error("elf, iso and fail-client are required")
return options, args
def execute(options, args, bochsrc, statedir):
failcmd = options.fail_client
command = "FAIL_ELF_PATH=%s FAIL_STATEDIR=%s %s -q -f %s %s" % \
(options.elf_file, statedir, failcmd, bochsrc, " ".join(args))
print("executing: " + command)
p = Popen(command, shell=True, stdout=PIPE, stderr=STDOUT)
reconnect = 0
while p.poll() is None:
line = p.stdout.readline()
if line is None:
break
if "Connection refused" in line.decode("utf-8", "ignore"):
reconnect += 1
print(line),
if reconnect > 10:
return 1
p.wait()
if reconnect > 0:
return 123
return p.returncode
def main(options, args):
bochsrc_args = {
"memory": options.memory,
"bios": options.bios,
"vgabios": options.vgabios,
"iso": options.iso_file,
"ips": int(options.freq) * 1000000,
}
bochsrc_text = """
config_interface: textconfig
display_library: nogui
romimage: file="{bios}"
cpu: count=1, ips={ips}, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
cpuid: mmx=1, sep=1, sse=sse4_2, xapic=1, aes=1, movbe=1, xsave=1, cpuid_limit_winnt=0
memory: guest={memory}, host={memory}
vgaromimage: file="{vgabios}"
vga: extension=vbe
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
ata0-slave: type=cdrom, path="{iso}", status=inserted
port_e9_hack: enabled=1
com1: enabled=1, mode=file, dev=serial.out
boot: cdrom
clock: sync=none, time0=946681200
floppy_bootsig_check: disabled=0
panic: action=fatal
error: action=fatal
info: action=ignore
debug: action=ignore
pass: action=ignore
debugger_log: -
parport1: enabled=0
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
private_colormap: enabled=0
i440fxsupport: enabled=0, slot1=pcivga
""".format(**bochsrc_args)
bochsrc = mkstemp()
fd = os.fdopen(bochsrc[0], "w")
fd.write(bochsrc_text)
fd.close()
bochsrc = bochsrc[1]
statedir = mkdtemp()
if options.forever:
while True:
res = execute(options, args, bochsrc, statedir)
if res != 0:
break
ret = 0
else:
ret = execute(options, args, bochsrc, statedir)
os.unlink(bochsrc)
shutil.rmtree(statedir)
sys.exit(ret)
if __name__ == "__main__":
(options, args) = parseArgs()
import threading
i = 1
# n-1 jobs in threads
while i < int(options.jobs):
fred = threading.Thread(target = main, args = (options, args))
fred.start()
print("starting: "+str(i))
i = i + 1
main(options, args)

3
fail/bin/fail-x86-tracing Executable file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0810cb612b7b5bc0e9485a6b499253d8f7ca6e3a133096db396d13e9f881a707
size 21437120

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:584214e3439e62591ac3b21b43bbd374137a1a8101a3f191054075fea35118a5
size 25567248

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a36268c32352d6a0d71ac519682e1d5195153cf2faf982ed691ee85e2c3926b7
size 12607768

3
fail/bin/import-trace Executable file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1c6d4fcd2c94c635ca8e176a0031f01ee21dedab764ec4320f480cdecd1ecdbf
size 13468904

3
fail/bin/prune-trace Executable file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:97a1fe328b6ecb98d609c4eb2d6b7d4f74c67af88cb18e3d6b37d2af29b712dd
size 8744232

1
fail/bin/resultbrowser.py Symbolic link
View File

@ -0,0 +1 @@
./resultbrowser/run.py

View File

@ -0,0 +1,19 @@
FAIL* Result Browser
Requirements:
* Python
* Flask (sudo pip install Flask)
* MySQLDB (sudo aptitude install python-mysqldb)
* YAML (sudo aptitude install python-yaml)
Based on Flask web microframework (Werkzeug, Jinja 2)
and old school MySQL bindings.
Connects to a FAIL* result database given by a mysql config file.
Usage:
./run.py
Defaults to mysql config file ~/.my.cnf, or
./run.py -c <path to sqlconfig.cnf>
YAML based configuration for table and variant details.

View File

@ -0,0 +1,4 @@
from flask import Flask
app = Flask(__name__)
from app import views

View File

@ -0,0 +1,143 @@
from pprint import pprint
from . import details
from . import model
def scrub(table_name):
return ''.join( chr for chr in table_name if chr.isalnum() or chr == '_' )
class Resulttype:
def __init__(self, name, count):
self.name = name
self.count = count
def getName(self):
return self.name
def getCount(self):
return self.count
class Variant:
def __init__(self, id, name, table, benchmark, detail):
self.id = id
self.dbname = name
self.parenttable = table # TableDetails
self.details = detail # VariantDetails
self.benchmark = benchmark # BenchmarkDetails
self.results = {}
self.totalresults = 0
def getMapper(self):
mapper = self.benchmark.getMapper()
if not mapper: #try benchmark mapper
mapper = self.details.getMapper()
if not mapper: # of not there, try parent tables mapper
mapper = self.parenttable.getMapper()
if not mapper: # no mapper found at all, try default mapper
mapper = model.detaildealer.getDefaultMapper()
return mapper
def addResulttype(self, name, count):
mapper = self.getMapper()
label = mapper.getLabel(name)
oldcount = self.results.setdefault(label, 0)
self.results[label] = oldcount + count
self.totalresults += count
def getResultLabels(self):
return self.results.keys()
def getDBName(self):
return str(self.name)
def getId(self):
return self.id
def getResults(self):
return self.results
def getTableDetails(self):
return self.parenttable
def getBenchmarkDetails(self):
return self.benchmark
def getDetails(self):
return self.details
def getTotals(self):
return self.totalresults
def __str__(self):
ret = "Variant: " + self.getDetails().getTitle() + " - " + self.getBenchmarkDetails().getTitle() +" (id: " + str( self.id )+ ")" + " "
ret += "Total Results: " + str( self.totalresults ) + "\n"
for v in self.results:
ret += "\t" + v.name + ": " + str( v.count ) + "\n"
return ret
__repr__ = __str__
'''A ResultTable contains n Variants'''
class ResultTable:
def __init__(self, name, cfg):
self.name = scrub(name)
self.details = cfg.getTable(name)
self.variants = {}
def addVariant(self, var):
if var.getId() in self.variants:
return
self.variants[var.getId()] = var # Add if not existing yet
def getVariant(self, id):
if id in self.variants:
return self.variants[id]
return None
def getVariantById(self, varid):
for k,v in self.variants.items():
if int(v.getId()) == int(varid):
return v
return None
def getDetails(self):
return self.details
def getVariants(self):
return self.variants
def __str__(self):
ret = "Result: " + self.getDetails().getTitle() + "\n"
for k,v in self.variants.items():
ret += "\t" + str(v) + "\n"
return ret
__repr__ = __str__
'''Overview has n ResultTables'''
class Overview:
def __init__(self):
self.tables = {}
def add(self, table):
self.tables[table.getDetails().getDBName()] = table
def getTables(self):
return self.tables
def getTable(self, dbname):
return self.tables.get(dbname, None)
def getVariantById(self, variant_id):
for key,table in self.tables.items():
variant = table.getVariantById(variant_id)
if variant:
return variant
print("Variant not found.")
return None
def length(self):
return len(self.tables)

View File

@ -0,0 +1,216 @@
class BasicDetails(object):
def __init__(self,name):
self.dbname = name
self.title = name
self.details = ''
self.mapper = None
def getDBName(self):
return self.dbname
def getDetails(self):
return self.details
def setDetails(self,det):
self.details = det
def getTitle(self):
return self.title
def addMapper(self, mapper):
self.mapper = mapper
def getMapper(self):
return self.mapper
def extractDetails(self, dictionary):
self.details = dictionary.pop(('details'), '')
self.title = dictionary.pop(('title'), self.dbname)
custommapping = dictionary.pop(('mapping'), None)
if custommapping:
self.mapper = ResulttypeMapper()
self.mapper.add(custommapping)
else:
self.mapper = None
def __repr__(self):
return self.getTitle() + ": " + self.getDetails()
__str__ = __repr__
class BenchmarkDetails(BasicDetails):
def __init__(self, dbname):
BasicDetails.__init__(self, dbname)
def __repr__(self):
return "Benchmark: " + BasicDetails.__repr__(self)
__str__ = __repr__
class VariantDetails(BasicDetails):
def __init__(self, dbname):
BasicDetails.__init__(self, dbname)
self.benchmarks = {}
def addBenchmark(self, bm):
self.benchmarks[bm.getDBName()] = bm
def getBenchmark(self, dbbm):
return self.benchmarks.get(dbbm, BenchmarkDetails(dbbm))
def __repr__(self):
ret = "Variant: " + BasicDetails.__repr__(self)
for v in self.benchmarks.values():
ret += "\n\t\t" + str(v)
return ret
__str__ = __repr__
class TableDetails(BasicDetails):
def __init__(self, tbl):
BasicDetails.__init__(self, tbl)
self.variants = {}
def addVariant(self, var):
self.variants[var.getDBName()] = var
def getVariant(self, varname):
return self.variants.get(varname, VariantDetails(varname))
def __repr__(self):
ret = "Table: " + BasicDetails.__repr__(self) + "(" + self.getDBName() + ")"
for v in self.variants.values():
ret += "\n\t" + str(v)
return ret
__str__ = __repr__
from pprint import pprint
class ResulttypeMapper(object):
def __init__(self):
self.mappings = {}
def add(self, mapping):
for label, dbnamelist in mapping.items():
self.mappings[label] = dbnamelist
def getLabel(self, dbname):
for label, dbnamelist in self.mappings.items():
if dbname in dbnamelist:
return label
return dbname
def getLabelList(self):
return self.mappings.keys()
def getDBNames(self, label):
return self.mappings.get(label, None)
def __repr__(self):
ret = "Resulttype Mapper:"
for label,dbnames in self.mappings.items():
ret += "\n\t" + label
for db in dbnames:
ret += "\n\t\t" + db
return ret
__str__ = __repr__
import yaml
class DetailDealer:
def __init__(self, configfile=None):
self.tables = {}
self.defaultMapper = ResulttypeMapper()
if not configfile:
return
self.reload(configfile)
if not self.tables:
print("DetailDealer: no details found for " + configfile)
def reload(self, configfile):
self.tables = {}
self.defaultMapper = ResulttypeMapper()
if not configfile:
return # no details.
f = open(configfile)
# use safe_load instead load
cfg = yaml.safe_load(f)
f.close()
# Read out default mapping, if existent
self.extractDefaults(cfg)
tables = cfg.pop('tables', None)
if tables:
for tablename,details in tables.items():
tab = TableDetails(tablename)
# pop: return and remove when key present, else return 'notfound'
tab.extractDetails(details)
variants = details.pop('variants')
for variantname, vdetails in variants.items():
var = VariantDetails(variantname)
var.extractDetails(vdetails)
benchmarks = vdetails.pop('benchmarks')
for benchmark, bdetails in benchmarks.items():
bm = BenchmarkDetails(benchmark)
bm.extractDetails(bdetails)
var.addBenchmark(bm)
tab.addVariant(var)
self.tables[tab.getDBName()] = (tab)
def extractDefaults(self, cfg):
defs = cfg.pop('defaults', None)
if defs:
defmap = defs.pop('mapping', None)
if defmap:
self.defaultMapper.add(defmap)
def getDefaultMapper(self):
return self.defaultMapper
def getTable(self, tablename):
tab = self.tables.get(tablename, None)
if tab:
return tab
return TableDetails(tablename)
def getVariant(self, tablename, variantname):
tab = self.getTable(tablename)
if tab:
return tab.getVariant(variantname)
return VariantDetails(variantname) # Default
def getBenchmark(self, table, variant, bechmark):
tab = self.getTable(table)
if tab:
var = tab.getVariant(variant)
if var:
return var.getBenchmark(bechmark)
return BenchmarkDetails(benchmark) # Default
def __repr__(self):
ret = str(self.defaultMapper) + '\n'
for tabledetails in self.tables.values():
ret += str(tabledetails) + '\n'
return ret
if __name__ == "__main__":
dd = DetailDealer('./test.yml')
pprint(dd)

View File

@ -0,0 +1,211 @@
#!/usr/bin/env python
import MySQLdb
import MySQLdb.cursors
import yaml
import sys
import os.path
from pprint import pprint
from . import data
from . import details
"""Get command line options"""
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-c", "--conf", type="string", help="MySQL config file", dest="config", default= os.path.join(os.path.expanduser("~"),".my.cnf"))
parser.add_option("-s", "--host", type="string", help="Webserver hostname", dest="host", default="localhost")
parser.add_option("-d", "--details", type="string", help="Detailed information (YAML configuration file)", dest="details", default=None)
parser.add_option("-p", "--port", type="string", help="Webserver port", dest="port", default="5000")
opts, args = parser.parse_args()
"""Check if configuration files exist"""
def checkConfigFile(msg, fname):
if not os.path.isfile(fname):
sys.exit("Error: '" + fname + "' not found")
else:
print(msg, "->", fname)
# Check sql config
sqlconfig = opts.config
checkConfigFile("MySQL config", sqlconfig)
# Check details file
if opts.details:
checkConfigFile("Details", opts.details)
# Instantiate global detail dealer, will be initialized in reloadOverview
detaildealer = details.DetailDealer()
"""Remove all characters from string except alphanuermics and _"""
def scrub(table_name):
return ''.join( chr for chr in table_name if chr.isalnum() or chr == '_' )
"""Global mysql handles"""
db = None
cur = None
def loadSession(dbconf):
global db
if db:
db.close()
db = MySQLdb.connect(read_default_file=dbconf, cursorclass=MySQLdb.cursors.DictCursor)
return db.cursor()
def closeSession():
if cur: cur.close()
global db
db.close()
db = None
'''Populate variant results for overview data'''
def getVariants(cur, table):
restbl = table.getDetails().getDBName()
cur.execute("""SELECT sum((t.time2 - t.time1 + 1) * width) AS total, resulttype,variant, v.id as variant_id, benchmark, details FROM variant v JOIN trace t ON v.id = t.variant_id JOIN fspgroup g ON g.variant_id = t.variant_id AND g.instr2 = t.instr2 AND g.data_address = t.data_address JOIN %s r ON r.pilot_id = g.pilot_id JOIN fsppilot p ON r.pilot_id = p.id GROUP BY v.id, resulttype, details""" % (restbl)) # % is used here, as a tablename must not be quoted
res = cur.fetchall()
rdic = {}
# Build dict with variant id as key
for r in res:
# if variant entry already exists:
variant = table.getVariant(int(r['variant_id']))
if not variant: # if variant did not exist yet, create it:
variant_details = detaildealer.getVariant(restbl, r['variant'])
benchmark_details = detaildealer.getBenchmark(restbl, r['variant'], r['benchmark'])
table_details = detaildealer.getTable(restbl)
variant = data.Variant(int(r['variant_id']), r['variant'], table_details, benchmark_details, variant_details)
variant.addResulttype(r['resulttype'], r['total'])
table.addVariant(variant)
'''Get overview data for index page'''
def reloadOverview():
overview = data.Overview()
detaildealer.reload(opts.details)
cur = loadSession(sqlconfig)
cur.execute("show tables like 'result_%'")
result_tables = cur.fetchall()
results = {}
for rdic in result_tables:
# r is the tablename, -> result_FOOBAR
for key, tablename in rdic.items():
table = data.ResultTable(tablename,detaildealer)
getVariants(cur, table)
overview.add(table)
# Check if objdump table exists
cur.execute("SHOW TABLES like 'objdump'")
objdump_exists = (len(cur.fetchall()) == 1)
closeSession()
return overview, objdump_exists
"""Load overview data at server startup"""
print("Loading overview data from database. This may take a while ...")
overview_data, objdump_exists = reloadOverview()
print("done.")
## Get overview data for views.index()
def getOverview():
return overview_data
def objdumpExists():
return objdump_exists
"""Get Results for one variant id"""
def getVariantResult(table, variantid):
cur = loadSession(sqlconfig)
restbl = scrub(table)
stmt = "SELECT resulttype, count(*) as total from %s r join fsppilot on r.pilot_id=fsppilot.id join variant on fsppilot.variant_id=variant.id" % (restbl)
where = " WHERE variant.id = %s group by resulttype ORDER BY resulttype "
stmt = stmt + where
cur.execute(stmt, variantid)
res = cur.fetchall()
closeSession()
return res
'''Show objdump together with according injection result types.'''
def getCode(result_table, variant_id, resultlabel=None):
result_table = scrub(result_table)
filt = ''
if not variant_id or not result_table:
return None
variant = overview_data.getVariantById(variant_id)
mapper = variant.getMapper()
if resultlabel:
dbnames = mapper.getDBNames(resultlabel)
if dbnames:
filt = " and ( "
for dbn in dbnames[:-1]:
filt += "resulttype = '" + dbn + "' OR "
filt += "resulttype = '" + dbnames[-1] +"' ) "
else:
filt = " and resulttype = '" + resultlabel + "' "
# I especially like this one:
select = "SELECT instr_address, opcode, disassemble, comment, sum(t.time2 - t.time1 + 1) as totals, GROUP_CONCAT(DISTINCT resulttype SEPARATOR ', ') as results FROM variant v "
join = " JOIN trace t ON v.id = t.variant_id JOIN fspgroup g ON g.variant_id = t.variant_id AND g.instr2 = t.instr2 AND g.data_address = t.data_address JOIN %s r ON r.pilot_id = g.pilot_id JOIN fsppilot p ON r.pilot_id = p.id JOIN objdump ON objdump.variant_id = v.id AND objdump.instr_address = injection_instr_absolute " %(scrub(result_table))
where = "WHERE v.id = %s "
group = "GROUP BY injection_instr_absolute ORDER BY totals DESC "
cur = loadSession(sqlconfig)
stmt = select + join + where + filt + group
cur.execute(stmt, (variant_id))
dump = cur.fetchall()
closeSession()
resulttypes = variant.getResultLabels()
return dump, resulttypes
def getCodeExcerpt(variant_id, instr_addr):
code = {}
limit = 8
cur = loadSession(sqlconfig)
cur.execute( """(SELECT instr_address, opcode, disassemble, comment FROM objdump \
WHERE instr_address < %s AND variant_id = %s \
ORDER BY instr_address DESC LIMIT %s) \
ORDER BY instr_address ASC""" , (instr_addr, variant_id, limit))
below = cur.fetchall()
code['below'] = below
cur.execute("""SELECT instr_address, opcode, disassemble, comment FROM objdump \
WHERE instr_address >= %s AND variant_id = %s \
ORDER BY instr_address ASC LIMIT %s""", (instr_addr, variant_id, limit+1))
upper = cur.fetchall()
code['upper'] = upper
closeSession()
return code
def getResultsbyInstruction(result_table, variant_id, instr_addr, resultlabel=None):
restypefilter = None
if resultlabel:
variant = overview_data.getVariantById(variant_id)
mapper = variant.getMapper()
if resultlabel:
dbnames = mapper.getDBNames(resultlabel)
if dbnames:
restypefilter = " and ( "
for dbn in dbnames[:-1]:
restypefilter += "resulttype = '" + dbn + "' OR "
restypefilter += "resulttype = '" + dbnames[-1] +"' ) "
select = "SELECT bitoffset as 'Bit Offset', hex(injection_instr_absolute) as 'Instruction Address', hex(original_value) as 'Original Value', hex(data_address) as 'Data Address', resulttype as 'Result Type', details as 'Details' from %s " % scrub(result_table)
join = "JOIN fsppilot ON pilot_id = fsppilot.id "
where = "WHERE variant_id = %s and injection_instr_absolute = %s "
order = "ORDER BY data_address, bitoffset"
cur = loadSession(sqlconfig)
if not restypefilter:
stmt = select + join + where + order
cur.execute(stmt, (variant_id, instr_addr))
else:
stmt = select + join + where + restypefilter + order
cur.execute(stmt, (variant_id, instr_addr))
res = cur.fetchall()
closeSession()
return res
def showDBstatus():
res = "TODO"
return res

View File

@ -0,0 +1,5 @@
dl.horizontal {font-size:12px; width:850px;}
dl.horizontal dt {float:left; width:300px; clear:both; margin:0 0 5px 0; padding:3px;}
dl.horizontal dd {float:left; width:500px; border:1px solid #aaaaaa; margin:0 0 5px 0; padding:2px; -moz-box-shadow: 1px 1px 3px #aaaaaa;}
dl.horizontal dd span {background:#91b4e6; display:block; color:black; text-indent:4px;}

View File

@ -0,0 +1,214 @@
body {
margin: 0;
padding: 0;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #444;
}
a:visited {
color : #444;
}
a:link {
color : #444;
text-decoration: none;
}
/*
* Create dark grey header with a white logo
*/
header {
background-color: #2B2B2B;
height: 30px;
width: 100%;
opacity: .9;
margin-bottom: 10px;
}
header h1.logo {
margin: 0;
font-size: 1.5em;
color: #fff;
text-transform: uppercase;
float: left;
}
header h1.logo:hover {
color: #fff;
text-decoration: none;
}
/*
* Center the body content
*/
.container {
width: 95%;
margin: 0 auto;
}
div.jumbo {
padding: 10px 0 30px 0;
background-color: #eeeeee;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
}
h2 {
font-size: 1.2em;
margin-top: 40px;
text-align: center;
letter-spacing: -1px;
}
h3 {
font-size: 1.0em;
font-weight: 100;
margin-top: 30px;
text-align: center;
/*letter-spacing: -1px;*/
color: #999;
}
#footer {
text-align: center;
color: #444;
font-size:10pt;
}
/*
* Table styles
*/
.codetable, .resulttable, .overviewtable{
font-family: monospace;
margin: auto;
}
.overviewtable {
border: 1px gray solid;
margin: auto;
}
/*
.overviewtable tr:nth-child(4n), .overviewtable tr:nth-child(4n-1) {
background: #fff;
}
.overviewtable tr:nth-child(4n-2), .overviewtable tr:nth-child(4n-3) {
background: #e8ffb3;
}
*/
.resulttable, .codetable, .overviewtable{
margin: auto;
border: solid #ccc 1px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
-webkit-box-shadow: 0 1px 1px #ccc;
-moz-box-shadow: 0 1px 1px #ccc;
box-shadow: 0 1px 1px #ccc;
}
.codetable tr:hover, .resulttable tr:hover {
background: #fbf8e9;
/* -o-transition: all 0.1s ease-in-out;
-webkit-transition: all 0.1s ease-in-out;
-moz-transition: all 0.1s ease-in-out;
-ms-transition: all 0.1s ease-in-out;
transition: all 0.1s ease-in-out;
*/
}
.resulttable td, .resulttable th, .codetable td, .codetable th {
border-left: none;
border-top: none;
padding: 2px;
text-align: left;
display: table-cell;
}
.codetable td a {
text-decoration: none;
display: block;
padding: 0px;
height: 100%;
}
.resulttable th, .codetable th, .overviewtable th {
background-color: #dce9f9;
background-image: -webkit-gradient(linear, left top, left bottom, from(#efe), to(#91b4e6));
background-image: -webkit-linear-gradient(top, #efe, #91b4e6);
background-image: -moz-linear-gradient(top, #efe, #91b4e6);
background-image: -ms-linear-gradient(top, #efe, #91b4e6);
background-image: -o-linear-gradient(top, #efe, #91b4e6);
background-image: linear-gradient(top, #efe, #91b4e6);
-webkit-box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
-moz-box-shadow:0 1px 0 rgba(255,255,255,.8) inset;
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
border-top: none;
text-shadow: 0 1px 0 rgba(255,255,255,.5);
}
.resulttable td:first-child, .resulttable th:first-child, .codetable td:first-child, .codetable th:first-child {
border-left: none;
}
.resulttable th:first-child, .codetable th:first-child {
-moz-border-radius: 6px 0 0 0;
-webkit-border-radius: 6px 0 0 0;
border-radius: 6px 0 0 0;
}
.resulttable th:last-child, .codetable th:last-child {
-moz-border-radius: 0 6px 0 0;
-webkit-border-radius: 0 6px 0 0;
border-radius: 0 6px 0 0;
}
.resulttable th:only-child, .codetable th:only-child{
-moz-border-radius: 6px 6px 0 0;
-webkit-border-radius: 6px 6px 0 0;
border-radius: 6px 6px 0 0;
}
.resulttable tr:last-child td:first-child, .codetable tr:last-child td:first-child {
-moz-border-radius: 0 0 0 6px;
-webkit-border-radius: 0 0 0 6px;
border-radius: 0 0 0 6px;
}
.resulttable tr:last-child td:last-child, .codetable tr:last-child td:last-child {
-moz-border-radius: 0 0 6px 0;
-webkit-border-radius: 0 0 6px 0;
border-radius: 0 0 6px 0;
}
.resulttypemenu {
text-align: center;
font-size: 12px
}
/*
* Display navigation links inline
*/
.menu {
float: right;
margin-top: 8px;
}
.menu li {
display: inline;
}
.menu li + li {
margin-left: 35px;
}
.menu li a {
color: #999;
text-decoration: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,11 @@
{% extends "layout.html" %}
{% block content %}
{% if status %}
<h2>About</h2>
{{ status }}
{% else %}
<h2> Sorry, no status information.</h2>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,50 @@
{% extends "layout.html" %}
{% block content %}
<h1>Variant Results</h1>
{% if resulttypes %}
<table>
<tr><td>Result Table</td><td><b>{{ variant_details.getTableDetails().getTitle() }}</b><td></tr>
<tr><td>Variant </td><td><b>{{ variant_details.getDetails().getTitle() }}</b></td></tr>
<tr><td>Details </td><td><b>{{ variant_details.getDetails().getDetails() }}</b></td></tr>
<tr><td>Benchmark </td><td><b>{{ variant_details.getBenchmarkDetails().getTitle() }}</b></td></tr>
<tr><td>Details </td><td><b>{{ variant_details.getBenchmarkDetails().getDetails() }}</b></td></tr>
<tr><td>Result Count </td><td><b>{{ results|length }}</b></td></tr>
</table>
<hr>
<p class='resulttypemenu'>| <a href="{{ url_for('code', variant_id=request.args.get('variant_id'), table=request.args.get('table')) }}">All Results</a> |
{% for restype in resulttypes %}
<a href="{{ url_for('code', variant_id=request.args.get('variant_id'), table=request.args.get('table'), resulttype=restype )}}">{{ restype}}</a> |
{% endfor %}
</p>
<hr>
<table class="codetable">
<tr>
<th>Address</th>
<th>Opcode</th>
<th>Disassembly</th>
<th>Comment</th>
<th>Results</th>
<th># Results</th>
</tr>
{% for d in results %}
{% set link = url_for('instr_details', table=request.args.get('table'), variant_id=request.args.get('variant_id'), benchmark=request.args.get('benchmark'), variant=request.args.get('variant'), resulttype=request.args.get('resulttype'), instr_address=d['instr_address'] ) %}
<tr>
<td><a href="{{ link }}">{{ "0x%x"|format(d['instr_address']) }}</a></td>
<td><a href="{{ link }}">{{ d['opcode'] }}</a></td>
<td><a href="{{ link }}">{{ d['disassemble'] }}</a></td>
<td><a href="{{ link }}">{{ d['comment'] }}</a></td>
<td><a href="{{ link }}">{{ d['results'] }}</a></td>
<td><a href="{{ link }}">{{ d['totals'] }}</a></td>
</tr>
{% endfor %}
</table>
{% else %}
<h1> Sorry, no dump found.</h1>
{% endif %}
{%endblock %}

View File

@ -0,0 +1,55 @@
{% extends "layout.html" %}
{% block content %}
{%if overview %}
{% for tablekey, resulttable in overview.getTables().items() %}
<h2>Result table: {{ resulttable.getDetails().getTitle() }}</h2>
-> <a href="{{ url_for('index', reload=1) }}">Reload data</a> <-
<dl>
<dt>Details:</td>
<dd>
{{ resulttable.getDetails().getDetails() }}
<dd>
</dl>
{% if not objdump_there %}
No objdump found
{% endif %}
<table class="overviewtable" cellspacing="0px">
{% for varid, variant in resulttable.getVariants().items() %}
<tr><th>
{% set variant_title=variant.getDetails().getTitle() ~ " - " ~ variant.getBenchmarkDetails().getTitle() ~ " id: " ~ variant.getId() %}
{% if objdump_there %}
<a href="{{ url_for('code',table=resulttable.getDetails().getDBName(), variant_id=variant.getId() ) }}">{{ variant_title }}</a>
{% else %}
{{ variant_title }}
{% endif %}
(Total: {{ variant.getTotals() }})</a>
</th></tr>
<tr><td>
{% if variant.getDetails().getDetails() %}
Variant Details: {{ variant.getDetails().getDetails() }}
{% endif %}
{% if variant.getBenchmarkDetails().getDetails() %}
<br> Benchmark Details: {{ variant.getBenchmarkDetails().getDetails() }}</td></tr>
{% endif %}
<tr><td>
<dl class="horizontal">
{% for reslabel,count in variant.getResults().items() %}
<dt>
{% if objdump_there %}
<a href="{{ url_for('code', table=resulttable.getDetails().getDBName(), variant_id=variant.getId(), resulttype=reslabel ) }}">{{ reslabel }}</a>
{% else %}
{{ reslabel }}
{% endif %}
</dt>
<dd><span style="width:{{count * 100 / variant.getTotals() }}%;">{{count}}</span></dd>
{% endfor %}
</dl></td></tr>
{% endfor %}
</table>
{% endfor %}
{% else %}
<h2> Sorry, no results found.</h2>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,65 @@
{% extends "layout.html" %}
{% block content %}
{% if code %}
<h1>Result by Instruction</h1>
<table>
<tr><td>Result Table</td><td><b>{{ variant_details.getTableDetails().getTitle() }}</b><td></tr>
<tr><td>Variant </td><td><b>{{ variant_details.getDetails().getTitle() }}</b></td></tr>
<tr><td>Benchmark </td><td><b>{{ variant_details.getBenchmarkDetails().getTitle() }}</b></td></tr>
<tr><td>Details </td><td><b>{{ variant_details.getDetails().getDetails() }}</b></td></tr>
<tr><td>Instruction Address </td><td><b>{{ "0x%x (Dec: %d)"|format(request.args.get('instr_address')|int, request.args.get('instr_address')|int) }}</b></td></tr>
<tr><td>Total Results</td><td><b>{{ result|length }}</b></td></tr>
</table>
<hr>
<h2>Code</h2>
<table class="codetable">
<tr>
<th>Address</th>
<th>Opcode</th>
<th>Disassembly</th>
<th>Comment</th>
</tr>
{% for d in code['below'] %}
<tr>
<td>{{ "0x%x"|format(d['instr_address']) }}</td>
<td>{{ d['opcode'] }}</td>
<td>{{ d['disassemble'] }}</td>
<td>{{ d['comment'] }}</td>
</tr>
{% endfor %}
<tr style="font-weight: bold">
<td>{{ "0x%x"|format(code['upper'][0]['instr_address']) }}</td>
<td>{{ code['upper'][0]['opcode'] }}</td>
<td>{{ code['upper'][0]['disassemble'] }}</td>
<td>{{ code['upper'][0]['comment'] }}</td>
</tr>
{% for d in code['upper'][1:] %}
<tr>
<td>{{ "0x%x"|format(d['instr_address']) }}</td>
<td>{{ d['opcode'] }}</td>
<td>{{ d['disassemble'] }}</td>
<td>{{ d['comment'] }}</td>
</tr>
{% endfor %}</table>
<hr>
<h2>Results ({{ result|length }})</h2>
<table class="resulttable">
<tr>
{% for key, value in result[0].items() -%}
<th>{{ key }}</th>
{% endfor -%}
</tr>
{% for r in result -%}
<tr>
{% for k,v in r.items() -%}
<td>{{ v }}</td>
{% endfor -%}
</tr>
{% endfor -%}
</tr>
</table>
{% else %}
<h2> Sorry, no details found.</h2>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>FAIL* Results</title>
<strong><link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}"></strong>
<strong><link rel="stylesheet" href="{{ url_for('static', filename='css/barchart.css') }}"></strong>
</head>
<body>
<header>
<div class="container">
<h1 class="logo">FAIL*</h1>
<strong><nav>
<ul class="menu">
<li><a href="{{ url_for('index') }}">Home</a></li>
<li><a href="{{ url_for('about') }}">About</a></li>
</ul>
</nav></strong>
</div>
</header>
<div class="container">
{% block content %}
{% endblock %}
</div>
<hr>
<div id="footer">
&copy; FAIL* - Fault Injection Leveraged
</div>
</body>
</html>

View File

@ -0,0 +1,42 @@
from flask import render_template,request
from app import app
# import model
# import data
from . import model
from . import data
@app.route('/')
@app.route('/index')
def index():
reload_overview = request.args.get('reload', False)
if reload_overview:
print("Reloading overview...")
model.reloadOverview()
return render_template("index.html", overview=model.getOverview(), objdump_there = model.objdumpExists())
@app.route('/code')
def code():
variant_id = request.args.get('variant_id', None)
resulttype = request.args.get('resulttype', None)
table = request.args.get('table', None)
res,restypes = model.getCode(table, variant_id, resulttype)
var_dets = model.getOverview().getVariantById(variant_id)
return render_template("code.html", results=res, resulttypes=restypes, variant_details=var_dets )
@app.route('/instr_details')
def instr_details():
table = request.args.get('table', None)
variant_id = request.args.get('variant_id', None)
instr_addr = request.args.get('instr_address', None)
resulttype = request.args.get('resulttype', None)
codeexcerpt = model.getCodeExcerpt(variant_id, instr_addr)
var_dets = model.getOverview().getVariantById(variant_id)
results = model.getResultsbyInstruction(table, variant_id, instr_addr, resulttype)
return render_template("instr_details.html", code=codeexcerpt, result=results, variant_details=var_dets)
@app.route('/about')
def about():
stat = model.showDBstatus()
return render_template("about.html", status=stat)

View File

@ -0,0 +1,69 @@
# YAML-based: http://yaml.org/
# Online parser for testing: http://yaml-online-parser.appspot.com/
# Some notes:
# YAML is case-sensitive and structured by indention!
#
# The 'defaults' section describes an *optional* default result type mapping for all tables.
# The 'tables' section describes result tables in more detail.
# A table consists of variants, each variant of benchmarks.
# Each of these configuration items
# title: Table title
# details: Some textual description
# mapping: A distinct mapping, if not set, the parent item's mapping is used
defaults:
mapping:
Everything OK:
- OK
- OK_DETECTED_ERROR
- OK_WRONG_CONTROL_FLOW
Outside Data Section:
- ERR_OUTSIDE_DATA
Hardware Trap:
- ERR_OUTSIDE_TEXT
- ERR_TRAP
Silent Data Corruption:
- ERR_WRONG_RESULT
tables:
result_CoredVoterProtoMsg:
title: CoRed Voter Experiment Results
variants:
x86_cored_voter:
title: x86 CoRed Voter Experiment
details: Some interesting details about the experiment.
benchmarks:
ean-random-4:
title: Random 4 bit injections
details: |
The details can also written this way.
The pipe insert the newlines. Cool, isn't it?
ean-random-5:
title: Random 5 bit injections
details: Details about 5 bit random injection benchmark.
mapping:
Alright:
- OK
- OK_DETECTED_ERROR
- OK_WRONG_CONTROL_FLOW
Not Alright:
- ERR_OUTSIDE_DATA
- ERR_OUTSIDE_TEXT
- ERR_TRAP
- ERR_WRONG_RESULT
Timeout:
- ERR_TIMEOUT
# Another variant within result_CoredVoterProtoMsg
x86_cored_voter2:
title: variant title
details: variant details
benchmarks:
ean-random-2:
title: benchmarktitle
details: some benchmark details
ean-random-3:
title: benchmark random 3
details: some benchmark 3 details

5
fail/bin/resultbrowser/run.py Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env python
from app import app
from app import model
app.run(debug=False, port=int(model.opts.port), host=model.opts.host)