Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | #!/usr/bin/python |
michael@0 | 2 | |
michael@0 | 3 | # |
michael@0 | 4 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 6 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 7 | |
michael@0 | 8 | """ |
michael@0 | 9 | Runs the static rooting analysis |
michael@0 | 10 | """ |
michael@0 | 11 | |
michael@0 | 12 | from subprocess import Popen |
michael@0 | 13 | import subprocess |
michael@0 | 14 | import os |
michael@0 | 15 | import argparse |
michael@0 | 16 | import sys |
michael@0 | 17 | import re |
michael@0 | 18 | |
michael@0 | 19 | def env(config): |
michael@0 | 20 | e = dict(os.environ) |
michael@0 | 21 | e['PATH'] = '%s:%s' % (e['PATH'], config['sixgill_bin']) |
michael@0 | 22 | e['XDB'] = '%(sixgill_bin)s/xdb.so' % config |
michael@0 | 23 | e['SOURCE'] = config['source'] |
michael@0 | 24 | e['ANALYZED_OBJDIR'] = config['objdir'] |
michael@0 | 25 | return e |
michael@0 | 26 | |
michael@0 | 27 | def fill(command, config): |
michael@0 | 28 | try: |
michael@0 | 29 | return tuple(s % config for s in command) |
michael@0 | 30 | except: |
michael@0 | 31 | print("Substitution failed:") |
michael@0 | 32 | problems = [] |
michael@0 | 33 | for fragment in command: |
michael@0 | 34 | try: |
michael@0 | 35 | fragment % config |
michael@0 | 36 | except: |
michael@0 | 37 | problems.append(fragment) |
michael@0 | 38 | raise Exception("\n".join(["Substitution failed:"] + [ " %s" % s for s in problems ])) |
michael@0 | 39 | |
michael@0 | 40 | def print_command(command, outfile=None, env=None): |
michael@0 | 41 | output = ' '.join(command) |
michael@0 | 42 | if outfile: |
michael@0 | 43 | output += ' > ' + outfile |
michael@0 | 44 | if env: |
michael@0 | 45 | changed = {} |
michael@0 | 46 | e = os.environ |
michael@0 | 47 | for key,value in env.items(): |
michael@0 | 48 | if (key not in e) or (e[key] != value): |
michael@0 | 49 | changed[key] = value |
michael@0 | 50 | if changed: |
michael@0 | 51 | outputs = [] |
michael@0 | 52 | for key, value in changed.items(): |
michael@0 | 53 | if key in e and e[key] in value: |
michael@0 | 54 | start = value.index(e[key]) |
michael@0 | 55 | end = start + len(e[key]) |
michael@0 | 56 | outputs.append('%s="%s${%s}%s"' % (key, |
michael@0 | 57 | value[:start], |
michael@0 | 58 | key, |
michael@0 | 59 | value[end:])) |
michael@0 | 60 | else: |
michael@0 | 61 | outputs.append("%s='%s'" % (key, value)) |
michael@0 | 62 | output = ' '.join(outputs) + " " + output |
michael@0 | 63 | |
michael@0 | 64 | print output |
michael@0 | 65 | |
michael@0 | 66 | def generate_hazards(config, outfilename): |
michael@0 | 67 | jobs = [] |
michael@0 | 68 | for i in range(config['jobs']): |
michael@0 | 69 | command = fill(('%(js)s', |
michael@0 | 70 | '%(analysis_scriptdir)s/analyzeRoots.js', |
michael@0 | 71 | '%(gcFunctions_list)s', |
michael@0 | 72 | '%(gcEdges)s', |
michael@0 | 73 | '%(suppressedFunctions_list)s', |
michael@0 | 74 | '%(gcTypes)s', |
michael@0 | 75 | str(i+1), '%(jobs)s', |
michael@0 | 76 | 'tmp.%s' % (i+1,)), |
michael@0 | 77 | config) |
michael@0 | 78 | outfile = 'rootingHazards.%s' % (i+1,) |
michael@0 | 79 | output = open(outfile, 'w') |
michael@0 | 80 | print_command(command, outfile=outfile, env=env(config)) |
michael@0 | 81 | jobs.append((command, Popen(command, stdout=output, env=env(config)))) |
michael@0 | 82 | |
michael@0 | 83 | final_status = 0 |
michael@0 | 84 | while jobs: |
michael@0 | 85 | pid, status = os.wait() |
michael@0 | 86 | jobs = [ job for job in jobs if job[1].pid != pid ] |
michael@0 | 87 | final_status = final_status or status |
michael@0 | 88 | |
michael@0 | 89 | if final_status: |
michael@0 | 90 | raise subprocess.CalledProcessError(final_status, 'analyzeRoots.js') |
michael@0 | 91 | |
michael@0 | 92 | with open(outfilename, 'w') as output: |
michael@0 | 93 | command = ['cat'] + [ 'rootingHazards.%s' % (i+1,) for i in range(config['jobs']) ] |
michael@0 | 94 | print_command(command, outfile=outfilename) |
michael@0 | 95 | subprocess.call(command, stdout=output) |
michael@0 | 96 | |
michael@0 | 97 | JOBS = { 'dbs': |
michael@0 | 98 | (('%(ANALYSIS_SCRIPTDIR)s/run_complete', |
michael@0 | 99 | '--foreground', |
michael@0 | 100 | '--no-logs', |
michael@0 | 101 | '--build-root=%(objdir)s', |
michael@0 | 102 | '--wrap-dir=%(sixgill)s/scripts/wrap_gcc', |
michael@0 | 103 | '--work-dir=work', |
michael@0 | 104 | '-b', '%(sixgill_bin)s', |
michael@0 | 105 | '--buildcommand=%(buildcommand)s', |
michael@0 | 106 | '.'), |
michael@0 | 107 | ()), |
michael@0 | 108 | |
michael@0 | 109 | 'callgraph': |
michael@0 | 110 | (('%(js)s', '%(analysis_scriptdir)s/computeCallgraph.js'), |
michael@0 | 111 | 'callgraph.txt'), |
michael@0 | 112 | |
michael@0 | 113 | 'gcFunctions': |
michael@0 | 114 | (('%(js)s', '%(analysis_scriptdir)s/computeGCFunctions.js', '%(callgraph)s', |
michael@0 | 115 | '[gcFunctions]', '[gcFunctions_list]', '[gcEdges]', '[suppressedFunctions_list]'), |
michael@0 | 116 | ('gcFunctions.txt', 'gcFunctions.lst', 'gcEdges.txt', 'suppressedFunctions.lst')), |
michael@0 | 117 | |
michael@0 | 118 | 'gcTypes': |
michael@0 | 119 | (('%(js)s', '%(analysis_scriptdir)s/computeGCTypes.js',), |
michael@0 | 120 | 'gcTypes.txt'), |
michael@0 | 121 | |
michael@0 | 122 | 'allFunctions': |
michael@0 | 123 | (('%(sixgill_bin)s/xdbkeys', 'src_body.xdb',), |
michael@0 | 124 | 'allFunctions.txt'), |
michael@0 | 125 | |
michael@0 | 126 | 'hazards': |
michael@0 | 127 | (generate_hazards, 'rootingHazards.txt'), |
michael@0 | 128 | |
michael@0 | 129 | 'explain': |
michael@0 | 130 | (('python', '%(analysis_scriptdir)s/explain.py', |
michael@0 | 131 | '%(hazards)s', '%(gcFunctions)s', |
michael@0 | 132 | '[explained_hazards]', '[unnecessary]', '[refs]'), |
michael@0 | 133 | ('hazards.txt', 'unnecessary.txt', 'refs.txt')) |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | def out_indexes(command): |
michael@0 | 137 | for i in range(len(command)): |
michael@0 | 138 | m = re.match(r'^\[(.*)\]$', command[i]) |
michael@0 | 139 | if m: |
michael@0 | 140 | yield (i, m.group(1)) |
michael@0 | 141 | |
michael@0 | 142 | def run_job(name, config): |
michael@0 | 143 | cmdspec, outfiles = JOBS[name] |
michael@0 | 144 | print("Running " + name + " to generate " + str(outfiles)) |
michael@0 | 145 | if hasattr(cmdspec, '__call__'): |
michael@0 | 146 | cmdspec(config, outfiles) |
michael@0 | 147 | else: |
michael@0 | 148 | temp_map = {} |
michael@0 | 149 | cmdspec = fill(cmdspec, config) |
michael@0 | 150 | if isinstance(outfiles, basestring): |
michael@0 | 151 | stdout_filename = '%s.tmp' % name |
michael@0 | 152 | temp_map[stdout_filename] = outfiles |
michael@0 | 153 | print_command(cmdspec, outfile=outfiles, env=env(config)) |
michael@0 | 154 | else: |
michael@0 | 155 | stdout_filename = None |
michael@0 | 156 | pc = list(cmdspec) |
michael@0 | 157 | outfile = 0 |
michael@0 | 158 | for (i, name) in out_indexes(cmdspec): |
michael@0 | 159 | pc[i] = outfiles[outfile] |
michael@0 | 160 | outfile += 1 |
michael@0 | 161 | print_command(pc, env=env(config)) |
michael@0 | 162 | |
michael@0 | 163 | command = list(cmdspec) |
michael@0 | 164 | outfile = 0 |
michael@0 | 165 | for (i, name) in out_indexes(cmdspec): |
michael@0 | 166 | command[i] = '%s.tmp' % name |
michael@0 | 167 | temp_map[command[i]] = outfiles[outfile] |
michael@0 | 168 | outfile += 1 |
michael@0 | 169 | |
michael@0 | 170 | sys.stdout.flush() |
michael@0 | 171 | if stdout_filename is None: |
michael@0 | 172 | subprocess.check_call(command, env=env(config)) |
michael@0 | 173 | else: |
michael@0 | 174 | with open(stdout_filename, 'w') as output: |
michael@0 | 175 | subprocess.check_call(command, stdout=output, env=env(config)) |
michael@0 | 176 | for (temp, final) in temp_map.items(): |
michael@0 | 177 | try: |
michael@0 | 178 | os.rename(temp, final) |
michael@0 | 179 | except OSError: |
michael@0 | 180 | print("Error renaming %s -> %s" % (temp, final)) |
michael@0 | 181 | raise |
michael@0 | 182 | |
michael@0 | 183 | config = { 'ANALYSIS_SCRIPTDIR': os.path.dirname(__file__) } |
michael@0 | 184 | |
michael@0 | 185 | defaults = [ '%s/defaults.py' % config['ANALYSIS_SCRIPTDIR'], |
michael@0 | 186 | '%s/defaults.py' % os.getcwd() ] |
michael@0 | 187 | |
michael@0 | 188 | for default in defaults: |
michael@0 | 189 | try: |
michael@0 | 190 | execfile(default, config) |
michael@0 | 191 | print("Loaded %s" % default) |
michael@0 | 192 | except: |
michael@0 | 193 | pass |
michael@0 | 194 | |
michael@0 | 195 | data = config.copy() |
michael@0 | 196 | |
michael@0 | 197 | parser = argparse.ArgumentParser(description='Statically analyze build tree for rooting hazards.') |
michael@0 | 198 | parser.add_argument('step', metavar='STEP', type=str, nargs='?', |
michael@0 | 199 | help='run starting from this step') |
michael@0 | 200 | parser.add_argument('--source', metavar='SOURCE', type=str, nargs='?', |
michael@0 | 201 | help='source code to analyze') |
michael@0 | 202 | parser.add_argument('--upto', metavar='UPTO', type=str, nargs='?', |
michael@0 | 203 | help='last step to execute') |
michael@0 | 204 | parser.add_argument('--jobs', '-j', default=None, metavar='JOBS', type=int, |
michael@0 | 205 | help='number of simultaneous analyzeRoots.js jobs') |
michael@0 | 206 | parser.add_argument('--list', const=True, nargs='?', type=bool, |
michael@0 | 207 | help='display available steps') |
michael@0 | 208 | parser.add_argument('--buildcommand', '--build', '-b', type=str, nargs='?', |
michael@0 | 209 | help='command to build the tree being analyzed') |
michael@0 | 210 | parser.add_argument('--tag', '-t', type=str, nargs='?', |
michael@0 | 211 | help='name of job, also sets build command to "build.<tag>"') |
michael@0 | 212 | parser.add_argument('--expect-file', type=str, nargs='?', |
michael@0 | 213 | help='deprecated option, temporarily still present for backwards compatibility') |
michael@0 | 214 | |
michael@0 | 215 | args = parser.parse_args() |
michael@0 | 216 | for k,v in vars(args).items(): |
michael@0 | 217 | if v is not None: |
michael@0 | 218 | data[k] = v |
michael@0 | 219 | |
michael@0 | 220 | if args.tag and not args.buildcommand: |
michael@0 | 221 | args.buildcommand="build.%s" % args.tag |
michael@0 | 222 | |
michael@0 | 223 | if args.jobs is not None: |
michael@0 | 224 | data['jobs'] = args.jobs |
michael@0 | 225 | if not data.get('jobs'): |
michael@0 | 226 | data['jobs'] = subprocess.check_output(['nproc', '--ignore=1']) |
michael@0 | 227 | |
michael@0 | 228 | if args.buildcommand: |
michael@0 | 229 | data['buildcommand'] = args.buildcommand |
michael@0 | 230 | elif 'BUILD' in os.environ: |
michael@0 | 231 | data['buildcommand'] = os.environ['BUILD'] |
michael@0 | 232 | else: |
michael@0 | 233 | data['buildcommand'] = 'make -j4 -s' |
michael@0 | 234 | |
michael@0 | 235 | if 'ANALYZED_OBJDIR' in os.environ: |
michael@0 | 236 | data['objdir'] = os.environ['ANALYZED_OBJDIR'] |
michael@0 | 237 | |
michael@0 | 238 | if 'SOURCE' in os.environ: |
michael@0 | 239 | data['source'] = os.environ['SOURCE'] |
michael@0 | 240 | if not data.get('source') and data.get('sixgill_bin'): |
michael@0 | 241 | path = subprocess.check_output(['sh', '-c', data['sixgill_bin'] + '/xdbkeys file_source.xdb | grep jsapi.cpp']) |
michael@0 | 242 | data['source'] = path.replace("/js/src/jsapi.cpp", "") |
michael@0 | 243 | |
michael@0 | 244 | steps = [ 'dbs', |
michael@0 | 245 | 'callgraph', |
michael@0 | 246 | 'gcTypes', |
michael@0 | 247 | 'gcFunctions', |
michael@0 | 248 | 'allFunctions', |
michael@0 | 249 | 'hazards', |
michael@0 | 250 | 'explain' ] |
michael@0 | 251 | |
michael@0 | 252 | if args.list: |
michael@0 | 253 | for step in steps: |
michael@0 | 254 | command, outfilename = JOBS[step] |
michael@0 | 255 | if outfilename: |
michael@0 | 256 | print("%s -> %s" % (step, outfilename)) |
michael@0 | 257 | else: |
michael@0 | 258 | print(step) |
michael@0 | 259 | sys.exit(0) |
michael@0 | 260 | |
michael@0 | 261 | for step in steps: |
michael@0 | 262 | command, outfiles = JOBS[step] |
michael@0 | 263 | if isinstance(outfiles, basestring): |
michael@0 | 264 | data[step] = outfiles |
michael@0 | 265 | else: |
michael@0 | 266 | outfile = 0 |
michael@0 | 267 | for (i, name) in out_indexes(command): |
michael@0 | 268 | data[name] = outfiles[outfile] |
michael@0 | 269 | outfile += 1 |
michael@0 | 270 | assert len(outfiles) == outfile, 'step \'%s\': mismatched number of output files and params' % step |
michael@0 | 271 | |
michael@0 | 272 | if args.step: |
michael@0 | 273 | steps = steps[steps.index(args.step):] |
michael@0 | 274 | |
michael@0 | 275 | if args.upto: |
michael@0 | 276 | steps = steps[:steps.index(args.upto)+1] |
michael@0 | 277 | |
michael@0 | 278 | for step in steps: |
michael@0 | 279 | run_job(step, data) |