Beispiel #1
0
class DeviceManagerADBTestCase(unittest.TestCase):
    tempLocalDir = "tempDir"
    tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt")
    tempRemoteDir = None
    tempRemoteFile = None
    tempRemoteSystemFile = None

    def setUp(self):
        self.assertTrue(find_mount_permissions(self.dm, "/system"), "ro")

        self.assertTrue(os.path.exists(self.tempLocalDir))
        self.assertTrue(os.path.exists(self.tempLocalFile))

        if self.dm.fileExists(self.tempRemoteFile):
            self.dm.removeFile(self.tempRemoteFile)
        self.assertFalse(self.dm.fileExists(self.tempRemoteFile))

        if self.dm.fileExists(self.tempRemoteSystemFile):
            self.dm.removeFile(self.tempRemoteSystemFile)

        self.assertTrue(self.dm.dirExists(self.tempRemoteDir))

    @classmethod
    def setUpClass(self):
        self.dm = DeviceManagerADB()
        if not os.path.exists(self.tempLocalDir):
            os.mkdir(self.tempLocalDir)
        if not os.path.exists(self.tempLocalFile):
            # Create empty file
            open(self.tempLocalFile, 'w').close()
        self.tempRemoteDir = self.dm.getTempDir()
        self.tempRemoteFile = os.path.join(
            self.tempRemoteDir, os.path.basename(self.tempLocalFile))
        self.tempRemoteSystemFile = \
            os.path.join("/system", os.path.basename(self.tempLocalFile))

    @classmethod
    def tearDownClass(self):
        os.remove(self.tempLocalFile)
        os.rmdir(self.tempLocalDir)
        if self.dm.dirExists(self.tempRemoteDir):
            # self.tempRemoteFile will get deleted with it
            self.dm.removeDir(self.tempRemoteDir)
        if self.dm.fileExists(self.tempRemoteSystemFile):
            self.dm.removeFile(self.tempRemoteSystemFile)
class DeviceManagerADBTestCase(unittest.TestCase):
    tempLocalDir = "tempDir"
    tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt")
    tempRemoteDir = None
    tempRemoteFile = None
    tempRemoteSystemFile = None

    def setUp(self):
        self.assertTrue(find_mount_permissions(self.dm, "/system"), "ro")

        self.assertTrue(os.path.exists(self.tempLocalDir))
        self.assertTrue(os.path.exists(self.tempLocalFile))

        if self.dm.fileExists(self.tempRemoteFile):
            self.dm.removeFile(self.tempRemoteFile)
        self.assertFalse(self.dm.fileExists(self.tempRemoteFile))

        if self.dm.fileExists(self.tempRemoteSystemFile):
            self.dm.removeFile(self.tempRemoteSystemFile)

        self.assertTrue(self.dm.dirExists(self.tempRemoteDir))

    @classmethod
    def setUpClass(self):
        self.dm = DeviceManagerADB()
        if not os.path.exists(self.tempLocalDir):
            os.mkdir(self.tempLocalDir)
        if not os.path.exists(self.tempLocalFile):
            # Create empty file
            open(self.tempLocalFile, 'w').close()
        self.tempRemoteDir = self.dm.getTempDir()
        self.tempRemoteFile = os.path.join(self.tempRemoteDir,
                os.path.basename(self.tempLocalFile))
        self.tempRemoteSystemFile = \
            os.path.join("/system", os.path.basename(self.tempLocalFile))

    @classmethod
    def tearDownClass(self):
        os.remove(self.tempLocalFile)
        os.rmdir(self.tempLocalDir)
        if self.dm.dirExists(self.tempRemoteDir):
            # self.tempRemoteFile will get deleted with it
            self.dm.removeDir(self.tempRemoteDir)
        if self.dm.fileExists(self.tempRemoteSystemFile):
            self.dm.removeFile(self.tempRemoteSystemFile)
Beispiel #3
0
class DeviceManagerADBTestCase(unittest.TestCase):
    tempLocalDir = "tempDir"
    tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt")
    tempRemoteDir = None
    tempRemoteFile = None

    def setUp(self):
        self.dm = DeviceManagerADB()
        if not os.path.exists(self.tempLocalDir):
            os.mkdir(self.tempLocalDir)
        if not os.path.exists(self.tempLocalFile):
            # Create empty file
            open(self.tempLocalFile, 'w').close()
        self.tempRemoteDir = self.dm.getTempDir()
        self.tempRemoteFile = os.path.join(
            self.tempRemoteDir, os.path.basename(self.tempLocalFile))

    def tearDown(self):
        os.remove(self.tempLocalFile)
        os.rmdir(self.tempLocalDir)
        if self.dm.dirExists(self.tempRemoteDir):
            self.dm.removeDir(self.tempRemoteDir)
class DeviceManagerADBTestCase(unittest.TestCase):
    tempLocalDir = "tempDir"
    tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt")
    tempRemoteDir = None
    tempRemoteFile = None

    def setUp(self):
        self.dm = DeviceManagerADB()
        if not os.path.exists(self.tempLocalDir):
            os.mkdir(self.tempLocalDir)
        if not os.path.exists(self.tempLocalFile):
            # Create empty file
            open(self.tempLocalFile, 'w').close()
        self.tempRemoteDir = self.dm.getTempDir()
        self.tempRemoteFile = os.path.join(self.tempRemoteDir,
                os.path.basename(self.tempLocalFile))

    def tearDown(self):
        os.remove(self.tempLocalFile)
        os.rmdir(self.tempLocalDir)
        if self.dm.dirExists(self.tempRemoteDir):
            self.dm.removeDir(self.tempRemoteDir)
Beispiel #5
0
class ADBFuzz:

  def __init__(self, cfgFile):
    self.config = ADBFuzzConfig(cfgFile)

    self.HTTPProcess = None
    self.logProcesses = []
    self.logThreads = []
    self.remoteInitialized = None

    self.triager = Triager(self.config)
    
    # Seed RNG with localtime
    random.seed()
    
  def deploy(self, packageFile, prefFile):
    self.dm = DeviceManagerADB(self.config.remoteAddr, 5555)
    
    # Install a signal handler that shuts down our external programs on SIGINT
    signal.signal(signal.SIGINT, self.signal_handler)
    
    self.dm.updateApp(packageFile)
    
    # Standard init stuff
    self.appName = self.dm.packageName
    self.appRoot = self.dm.getAppRoot(self.appName)
    self.profileBase = self.appRoot + "/files/mozilla"
    
    # Ensure no Fennec instance is running
    self.stopFennec()
    
    # Start Fennec, so a profile is created if this is the first install
    self.startFennec(blank=True)
    
    # Grant some time to create profile
    time.sleep(self.config.runTimeout * 2)
    
    # Stop Fennec again
    self.stopFennec()
    
    # Now try to get the profile(s)
    self.profiles = self.getProfiles()

    if (len(self.profiles) == 0):
      print "Failed to detect any valid profile, aborting..."
      return 1

    self.defaultProfile = self.profiles[0]

    if (len(self.profiles) > 1):
      print "Multiple profiles detected, using the first: " + self.defaultProfile
      
    # Push prefs.js to profile
    self.dm.pushFile(prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js")
    
    # Try to install addon if requested by configuration
    if self.config.addon != None:
      self.ensureExtensionInstalled(self.config.addon)
    
    print "Successfully deployed package."
    
  def reset(self, prefFile):
    self.dm = DeviceManagerADB(self.config.remoteAddr, 5555)
    
    # Install a signal handler that shuts down our external programs on SIGINT
    signal.signal(signal.SIGINT, self.signal_handler)
    
    # Standard init stuff
    self.appName = self.dm.packageName
    self.appRoot = self.dm.getAppRoot(self.appName)
    self.profileBase = self.appRoot + "/files/mozilla"
    
    # Ensure no Fennec instance is running
    self.stopFennec()
    
    # Now try to get the old profile(s)
    self.profiles = self.getProfiles()
    
    for profile in self.profiles:
      self.dm.removeDir(self.profileBase + "/" + profile)
      
    self.dm.removeFile(self.profileBase + "/profiles.ini")
    
    # Start Fennec, so a new profile is created
    self.startFennec(blank=True)
    
    # Grant some time to create profile
    time.sleep(self.config.runTimeout * 2)
    
    # Stop Fennec again
    self.stopFennec()
    
    # Now try to get the profile(s) again
    self.profiles = self.getProfiles()

    if (len(self.profiles) == 0):
      print "Failed to detect any valid profile, aborting..."
      return 1

    self.defaultProfile = self.profiles[0]

    if (len(self.profiles) > 1):
      print "Multiple profiles detected, using the first: " + self.defaultProfile
      
    # Push prefs.js to profile
    self.dm.pushFile(prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js")
    
    # Try to install addon if requested by configuration
    if self.config.addon != None:
      self.ensureExtensionInstalled(self.config.addon)
    
    print "Successfully resetted profile."

  def remoteInit(self):
    if (self.remoteInitialized != None):
      return

    self.dm = DeviceManagerADB(self.config.remoteAddr, 5555)
    self.appName = self.dm.packageName
    self.appRoot = self.dm.getAppRoot(self.appName)
    self.profileBase = self.appRoot + "/files/mozilla"
    self.profiles = self.getProfiles()

    # Install a signal handler that shuts down our external programs on SIGINT
    signal.signal(signal.SIGINT, self.signal_handler)

    if (len(self.profiles) == 0):
      print "Failed to detect any valid profile, aborting..."
      return 1

    self.defaultProfile = self.profiles[0]

    if (len(self.profiles) > 1):
      print "Multiple profiles detected, using the first: " + self.defaultProfile
      
    
    # Workaround for bug 754575. Avoid using DeviceManagerADB's "removeDir" because
    # that calls "rm" on every single entry which takes a lot of additional time.
    print "Purging possible cache leftover directories..."
    self.dm.runCmd(['shell', 'rm', '-r', self.profileBase + "/" + self.defaultProfile + "/Cache.Trash*"]).communicate()

    self.remoteInitialized = True

  def signal_handler(self, signal, frame):
    self.cleanupProcesses()
    sys.exit(0)

  def cleanupProcesses(self):
    self.stopFennec()
    if (self.HTTPProcess != None):
      try:
        self.HTTPProcess.terminate()
      except:
        pass
    if (self.logProcesses != None):
      try:
        self.stopLoggers()
      except:
        pass

  def loopFuzz(self, maxIterations=None):
    try:
      iterations = 0
      while (maxIterations == None or maxIterations >= iterations):
        self.runFuzzer()
        iterations += 1
    except:
      self.cleanupProcesses()
      raise

  def runFuzzer(self):
    self.remoteInit()

    # Ensure Fennec isn't running
    if self.isFennecRunning():
      self.stopFennec()

    # Clean all existing minidumps
    if not self.clearMinidumps():
      raise Exception("Failed to clean existing minidumps")

    # Start our HTTP server for serving the fuzzer code
    self.HTTPProcess = self.startHTTPServer()

    # Start all loggers
    self.startLoggers()

    # Start Fennec
    self.startFennec()

    # Even though the program is already running, we should grant it
    # some extra time to load the fuzzer source and start running,
    # so it isn't directly diagnosed as hanging
    time.sleep(10);
    
    logSize = 0
    hangDetected = False
    forceRestart = False
    while(self.isFennecRunning() and not self.checkLoggingThreads()):
      time.sleep(self.config.runTimeout)

      if not os.path.exists(self.logFile):
        raise Exception("Logfile not present. If you are using websockets, this could indicate a network problem.")

      # Poor man's hang detection. Yes, this is a bad
      # idea, just for the sake of proof-of-concept
      newLogSize = os.path.getsize(self.logFile)
      if (logSize == newLogSize):
        hangDetected = True
        break
      else:
        logSize = newLogSize
        if newLogSize > self.config.maxLogSize:
          forceRestart = True
          break

    if hangDetected or forceRestart:
      self.stopFennec()
      self.stopLoggers()
      print "Hang detected or running too long, restarting..."
    else:
      try:
        # Fennec died or a logger found something
        checkCrashDump = True
        crashUUID = None
        minidump = None
        
        # If Fennec is still running, stop it now
        if self.isFennecRunning():
          checkCrashDump = False
          self.stopFennec()
        
        # Terminate our logging processes first
        self.stopLoggers()
        
        if checkCrashDump:
          dumps = self.getMinidumps()
          if (len(dumps) > 1):
            raise Exception("Multiple dumps detected!")
            
          if (len(dumps) < 1):
            raise Exception("No crash dump detected!")
    
          if not self.fetchMinidump(dumps[0]):
            raise Exception("Failed to fetch minidump with UUID " + dumps[0])
  
          crashUUID = dumps[0]
  
          # Copy logfiles
          shutil.copy2(self.syslogFile, dumps[0] + ".syslog")
          shutil.copy2(self.logFile, dumps[0] + ".log")
    
          minidump = Minidump(dumps[0] + ".dmp", self.config.libDir)
        else:
          # We need to generate an arbitrary ID here
          crashUUID = str(uuid.uuid4())
          
          # Copy logfiles
          shutil.copy2(self.syslogFile, crashUUID + ".syslog")
          shutil.copy2(self.logFile, crashUUID + ".log")
  
        print "Crash detected. Reproduction logfile stored at: " + crashUUID + ".log"
        if checkCrashDump:
          crashTrace = minidump.getCrashTrace()
          crashType = minidump.getCrashType()
          print "Crash type: " + crashType
          print "Crash backtrace:"
          print ""
          print crashTrace
        else:
          print "Crash type: Abnormal behavior (e.g. Assertion violation)"
  
        self.triager.process(crashUUID, minidump, crashUUID + ".syslog", crashUUID + ".log")
      except Exception, e:
        print "Error during crash processing: "
        print traceback.format_exc()

    self.HTTPProcess.terminate()
    return
def uninstall(adb="adb"):
    dm = DeviceManagerADB(adbPath=adb)
    dm.remount()
    if dm.dirExists(INSTALL_DIR):
        dm.removeDir(INSTALL_DIR)
class ADBFuzz:
    def __init__(self, cfgFile):
        self.config = ADBFuzzConfig(cfgFile)

        self.HTTPProcess = None
        self.logProcesses = []
        self.logThreads = []
        self.remoteInitialized = None

        self.triager = Triager(self.config)

        # Seed RNG with localtime
        random.seed()

    def deploy(self, packageFile, prefFile):
        self.dm = DeviceManagerADB(self.config.remoteAddr, 5555)

        # Install a signal handler that shuts down our external programs on SIGINT
        signal.signal(signal.SIGINT, self.signal_handler)

        self.dm.updateApp(packageFile)

        # Standard init stuff
        self.appName = self.dm.packageName
        self.appRoot = self.dm.getAppRoot(self.appName)
        self.profileBase = self.appRoot + "/files/mozilla"

        # Ensure no Fennec instance is running
        self.stopFennec()

        # Start Fennec, so a profile is created if this is the first install
        self.startFennec(blank=True)

        # Grant some time to create profile
        time.sleep(self.config.runTimeout * 2)

        # Stop Fennec again
        self.stopFennec()

        # Now try to get the profile(s)
        self.profiles = self.getProfiles()

        if (len(self.profiles) == 0):
            print "Failed to detect any valid profile, aborting..."
            return 1

        self.defaultProfile = self.profiles[0]

        if (len(self.profiles) > 1):
            print "Multiple profiles detected, using the first: " + self.defaultProfile

        # Push prefs.js to profile
        self.dm.pushFile(
            prefFile,
            self.profileBase + "/" + self.defaultProfile + "/prefs.js")

        # Try to install addon if requested by configuration
        if self.config.addon != None:
            self.ensureExtensionInstalled(self.config.addon)

        print "Successfully deployed package."

    def reset(self, prefFile):
        self.dm = DeviceManagerADB(self.config.remoteAddr, 5555)

        # Install a signal handler that shuts down our external programs on SIGINT
        signal.signal(signal.SIGINT, self.signal_handler)

        # Standard init stuff
        self.appName = self.dm.packageName
        self.appRoot = self.dm.getAppRoot(self.appName)
        self.profileBase = self.appRoot + "/files/mozilla"

        # Ensure no Fennec instance is running
        self.stopFennec()

        # Now try to get the old profile(s)
        self.profiles = self.getProfiles()

        for profile in self.profiles:
            self.dm.removeDir(self.profileBase + "/" + profile)

        self.dm.removeFile(self.profileBase + "/profiles.ini")

        # Start Fennec, so a new profile is created
        self.startFennec(blank=True)

        # Grant some time to create profile
        time.sleep(self.config.runTimeout * 2)

        # Stop Fennec again
        self.stopFennec()

        # Now try to get the profile(s) again
        self.profiles = self.getProfiles()

        if (len(self.profiles) == 0):
            print "Failed to detect any valid profile, aborting..."
            return 1

        self.defaultProfile = self.profiles[0]

        if (len(self.profiles) > 1):
            print "Multiple profiles detected, using the first: " + self.defaultProfile

        # Push prefs.js to profile
        self.dm.pushFile(
            prefFile,
            self.profileBase + "/" + self.defaultProfile + "/prefs.js")

        # Try to install addon if requested by configuration
        if self.config.addon != None:
            self.ensureExtensionInstalled(self.config.addon)

        print "Successfully resetted profile."

    def remoteInit(self):
        if (self.remoteInitialized != None):
            return

        self.dm = DeviceManagerADB(self.config.remoteAddr, 5555)
        self.appName = self.dm.packageName
        self.appRoot = self.dm.getAppRoot(self.appName)
        self.profileBase = self.appRoot + "/files/mozilla"
        self.profiles = self.getProfiles()

        # Install a signal handler that shuts down our external programs on SIGINT
        signal.signal(signal.SIGINT, self.signal_handler)

        if (len(self.profiles) == 0):
            print "Failed to detect any valid profile, aborting..."
            return 1

        self.defaultProfile = self.profiles[0]

        if (len(self.profiles) > 1):
            print "Multiple profiles detected, using the first: " + self.defaultProfile

        # Workaround for bug 754575. Avoid using DeviceManagerADB's "removeDir" because
        # that calls "rm" on every single entry which takes a lot of additional time.
        print "Purging possible cache leftover directories..."
        self.dm.runCmd([
            'shell', 'rm', '-r',
            self.profileBase + "/" + self.defaultProfile + "/Cache.Trash*"
        ]).communicate()

        self.remoteInitialized = True

    def signal_handler(self, signal, frame):
        self.cleanupProcesses()
        sys.exit(0)

    def cleanupProcesses(self):
        self.stopFennec()
        if (self.HTTPProcess != None):
            try:
                self.HTTPProcess.terminate()
            except:
                pass
        if (self.logProcesses != None):
            try:
                self.stopLoggers()
            except:
                pass

    def loopFuzz(self, maxIterations=None):
        try:
            iterations = 0
            while (maxIterations == None or maxIterations >= iterations):
                self.runFuzzer()
                iterations += 1
        except:
            self.cleanupProcesses()
            raise

    def runFuzzer(self):
        self.remoteInit()

        # Ensure Fennec isn't running
        if self.isFennecRunning():
            self.stopFennec()

        # Clean all existing minidumps
        if not self.clearMinidumps():
            raise Exception("Failed to clean existing minidumps")

        # Start our HTTP server for serving the fuzzer code
        self.HTTPProcess = self.startHTTPServer()

        # Start all loggers
        self.startLoggers()

        # Start Fennec
        self.startFennec()

        # Even though the program is already running, we should grant it
        # some extra time to load the fuzzer source and start running,
        # so it isn't directly diagnosed as hanging
        time.sleep(10)

        logSize = 0
        hangDetected = False
        forceRestart = False
        while (self.isFennecRunning() and not self.checkLoggingThreads()):
            time.sleep(self.config.runTimeout)

            if not os.path.exists(self.logFile):
                raise Exception(
                    "Logfile not present. If you are using websockets, this could indicate a network problem."
                )

            # Poor man's hang detection. Yes, this is a bad
            # idea, just for the sake of proof-of-concept
            newLogSize = os.path.getsize(self.logFile)
            if (logSize == newLogSize):
                hangDetected = True
                break
            else:
                logSize = newLogSize
                if newLogSize > self.config.maxLogSize:
                    forceRestart = True
                    break

        if hangDetected or forceRestart:
            self.stopFennec()
            self.stopLoggers()
            print "Hang detected or running too long, restarting..."
        else:
            try:
                # Fennec died or a logger found something
                checkCrashDump = True
                crashUUID = None
                minidump = None

                # If Fennec is still running, stop it now
                if self.isFennecRunning():
                    checkCrashDump = False
                    self.stopFennec()

                # Terminate our logging processes first
                self.stopLoggers()

                if checkCrashDump:
                    dumps = self.getMinidumps()
                    if (len(dumps) > 1):
                        raise Exception("Multiple dumps detected!")

                    if (len(dumps) < 1):
                        raise Exception("No crash dump detected!")

                    if not self.fetchMinidump(dumps[0]):
                        raise Exception("Failed to fetch minidump with UUID " +
                                        dumps[0])

                    crashUUID = dumps[0]

                    # Copy logfiles
                    shutil.copy2(self.syslogFile, dumps[0] + ".syslog")
                    shutil.copy2(self.logFile, dumps[0] + ".log")

                    minidump = Minidump(dumps[0] + ".dmp", self.config.libDir)
                else:
                    # We need to generate an arbitrary ID here
                    crashUUID = str(uuid.uuid4())

                    # Copy logfiles
                    shutil.copy2(self.syslogFile, crashUUID + ".syslog")
                    shutil.copy2(self.logFile, crashUUID + ".log")

                print "Crash detected. Reproduction logfile stored at: " + crashUUID + ".log"
                if checkCrashDump:
                    crashTrace = minidump.getCrashTrace()
                    crashType = minidump.getCrashType()
                    print "Crash type: " + crashType
                    print "Crash backtrace:"
                    print ""
                    print crashTrace
                else:
                    print "Crash type: Abnormal behavior (e.g. Assertion violation)"

                self.triager.process(crashUUID, minidump,
                                     crashUUID + ".syslog", crashUUID + ".log")
            except Exception, e:
                print "Error during crash processing: "
                print traceback.format_exc()

        self.HTTPProcess.terminate()
        return
def uninstall(adb="adb"):
    dm = DeviceManagerADB(adbPath=adb)
    dm.remount()
    if dm.dirExists(INSTALL_DIR):
        dm.removeDir(INSTALL_DIR)