Skip to content

Plugins

ETenal edited this page Oct 5, 2023 · 20 revisions

ExpBridge provides a comprehensive interface for reproducing upstream kernel bugs. It can easily integrate with existing bug assessment tools, as a form of a standalone plugin of ExpBridge.

In fact, all the current functionalities of ExpBridge (reproducing bugs on downstream, extracting kernel trace, automatically tuning the original PoCs, etc.) were implemented as one or more plugins. Plugins can share data with each other and collaborate with other plugins. ExpBridge also provides rich API for common functionalities, such as launching VM, detecting kernel crashes, etc.

  • RawBugReproduce: RawBugReproduce takes upstream PoC to downstream. Without any adaptation, RawBugReproduce runs the PoC on the downstream distro and monitors any kernel crashes.

  • SyzFeatureMinimize: SyzFeatureMinimize minimizes the features that are required by the testcase. Those features normally control how does PoC work, for example, repeat, sandbox. Minimizing the features provides the maximum capability to accommodate different downstream distro environments.

  • TraceAnalysis: TraceAnalysis extract PoC execution traces from upstream and downstream distro. Those traces later feed to ModulesAnalysis for further analysis.

  • ModulesAnalysis: ModulesAnalysis takes the kernel traces from TraceAnalysis, and compare the upstream trace with the downstream traces. The differences in their traces reflect the potential missing modules.

  • BugReproduce: BugReproduce takes the results from previous plugins, and make adaptations to the upstream PoC and test it on downstream distros.

Workflow

A blank plugin the following entries:

  • prepare() is a common entry to prepare a plugin. It has no arguments, users are able to pass customized arguments through ExpBridge configuration file. prepare() function can pass arguments to prepare_on_demand() if necessary.

  • prepare_on_demand() is used to setup variables and conditions. It's also handy when you are testing a plugin by passing the arguments directly to the plugin without a config file.

  • success() can only be called once for each case. It makes the current case move to the succeed category.

  • run() is the main entry of a plugin. It's where you implement the main functionality of your plugin. It returns True to create a success stamp, otherwise, no stamp will be created.

  • generate_report() executes after run() returns True.

  • cleanup() executes after plugin is finished.

from plugins import AnalysisModule

class Template(AnalysisModule):
    NAME = "Template"
    REPORT_START = "======================Template Report======================"
    REPORT_END =   "==================================================================="
    REPORT_NAME = "Report_Template"
    DEPENDENCY_PLUGINS = []

    def __init__(self):
        super().__init__()
        
    def prepare(self):
        plugin = self.cfg.get_plugin(self.NAME)
        if plugin == None:
            self.err_msg("No such plugin {}".format(self.NAME))
        try:
            self.greeting = int(plugin.greeting)
        except AttributeError:
            self.err_msg("Failed to get greeting")
            return False
        return self.prepare_on_demand()
    
    def prepare_on_demand(self):
        self._prepared = True
        return True
    
    def success(self):
        return self._move_to_success

    def run(self):
        """
        do something
        True: plugin return successfully
        False: something goes wrong, stamp will not be created
        """
        self.logger.info("Hello you, {}".format(self.greeting))
        return True
    
    def generate_report(self):
        final_report = "\n".join(self.report)
        self.info_msg(final_report)
        self._write_to(final_report, self.REPORT_NAME)
    
    def _write_to(self, content, name):
        file_path = "{}/{}".format(self.path_case_plugin, name)
        super()._write_to(content, file_path)

    def cleanup(self):
        super().cleanup()