示例#1
0
 def columns(cols):
     if not isinstance(cols, list):
         raise FilamentError('Columns must be a list, '
                             '%s found' % type(cols))
     self._cols = cols
     self._tabular = Tabular(self._cols)
     self._tabular.padding_width = 10
     self._tabular.junction_char = '|'
示例#2
0
                fibratus.stop_ktrace()
            return 0
        set_console_ctrl_handler(handle_ctrl_c, True)

        if not filament:
            if len(kevent_filters) > 0:
                fibratus.add_filters(kevent_filters)
        else:
            if len(filament_filters) > 0:
                fibratus.add_filters(filament_filters)
            else:
                fibratus.add_filters([])
        try:
            fibratus.run()
        except KeyboardInterrupt:
            set_console_ctrl_handler(handle_ctrl_c, False)

    elif args['list-filaments']:
        filaments = Tabular(['Filament', 'Description'], 'Description',
                            sort_by='Filament')
        for filament, desc in Filament.list_filaments().items():
            filaments.add_row([filament, desc])
        filaments.draw()

    elif args['list-kevents']:
        kevents = Tabular(['KEvent', 'Category', 'Description'], 'Description',
                          sort_by='Category')
        for kevent, meta in KEvents.meta_info().items():
            kevents.add_row([kevent, meta[0].name, meta[1]])
        kevents.draw()
示例#3
0
def main():
    if args['run']:
        if len(kevent_filters) > 0 and not filament_name:
            for kfilter in kevent_filters:
                _check_kevent(kfilter)

        enum_handles = False if args['--no-enum-handles'] else True
        cswitch = True if args['--cswitch'] else False

        filament = None
        filament_filters = []

        if not filament_name:
            print('Starting fibratus...')
        else:
            if not Filament.exists(filament_name):
                panic(
                    'fibratus run: ERROR - %s filament does not exist. Run list-filaments to see '
                    'the availble filaments' % filament_name)
            filament = Filament()
            try:
                filament.load_filament(filament_name)
            except FilamentError as e:
                panic('fibratus run: ERROR - %s' % e)

            filament_filters = filament.filters

            if len(filament_filters) > 0:
                for kfilter in filament_filters:
                    _check_kevent(kfilter)

            filament.render_tabular()

        try:
            fibratus = Fibratus(filament,
                                enum_handles=enum_handles,
                                cswitch=cswitch)
        except KeyboardInterrupt:
            # the user has stopped command execution
            # before opening the kernel event stream
            sys.exit(0)

        @PHANDLER_ROUTINE
        def handle_ctrl_c(event):
            if event == 0:
                fibratus.stop_ktrace()
            return 0

        set_console_ctrl_handler(handle_ctrl_c, True)

        # add specific filters
        filters = dict()
        filters['pid'] = args['--pid'] if args['--pid'] else None

        if not filament:
            if len(kevent_filters) > 0:
                fibratus.add_filters(kevent_filters, **filters)
            else:
                fibratus.add_filters([], **filters)
        else:
            if len(filament_filters) > 0:
                fibratus.add_filters(filament_filters, **filters)
            else:
                fibratus.add_filters([], **filters)
        try:
            fibratus.run()
        except KeyboardInterrupt:
            set_console_ctrl_handler(handle_ctrl_c, False)

    elif args['list-filaments']:
        filaments = Tabular(['Filament', 'Description'],
                            'Description',
                            sort_by='Filament')
        for filament, desc in Filament.list_filaments().items():
            filaments.add_row([filament, desc])
        filaments.draw()

    elif args['list-kevents']:
        kevents = Tabular(['KEvent', 'Category', 'Description'],
                          'Description',
                          sort_by='Category')
        for kevent, meta in KEvents.meta_info().items():
            kevents.add_row([kevent, meta[0].name, meta[1]])
        kevents.draw()
示例#4
0
class Filament(Process):
    """Filament initialization and execution engine.

    Filaments are lightweight Python modules which run
    on top of Fibratus. They are often used to enrich/extend the
    functionality of Fibratus by performing any type of logic
    (aggregations, groupings, filters, counters, etc) on the
    kernel event stream.

    Each filament runs in its own execution context, i.e. in
    its own copy of the Python interpreter process.

    """
    def __init__(self):
        """Builds a new instance of the filament.

        Attributes:
        ----------

        filament_module: module
            module which contains the filament logic

        keventq: Queue
            queue where the main process pushes the kernel events
        """
        Process.__init__(self)
        self._filament_module = None
        self._keventq = None
        self._filters = []
        self._cols = []
        self._tabular = None
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self._log_path = None
        self._logger = None
        self.scheduler = BackgroundScheduler()

    def load_filament(self, name):
        """Loads the filament module.

        Finds and loads the python module which
        holds the filament logic. It also looks up for
        some essential filament methods and raises an error
        if they can't be found.

        Parameters
        ----------
        name: str
            name of the filament to load

        """
        Filament._assert_root_dir()
        filament_path = self._find_filament_path(name)
        if filament_path:
            loader = SourceFileLoader(name, filament_path)
            self._filament_module = loader.load_module()
            sys.path.append(FILAMENTS_DIR)
            doc = inspect.getdoc(self._filament_module)
            if not doc:
                raise FilamentError('Please provide a short '
                                    'description for the filament')

            on_next_kevent = self._find_filament_func('on_next_kevent')
            if on_next_kevent:
                if self._num_args(on_next_kevent) != 1:
                    raise FilamentError('Missing one argument on_next_kevent '
                                        'method on filament')
                self._initialize_funcs()
            else:
                raise FilamentError('Missing required on_next_kevent '
                                    'method on filament')
        else:
            raise FilamentError('%s filament not found' % name)

    def _initialize_funcs(self):
        """Setup the filament modules functions.

        Functions
        ---------

        set_filter: func
            accepts the comma separated list of kernel events
            for whose the filter should be applied
        set_interval: func
            establishes the fixed repeating interval in seconds
        columns: func
            configure the column set for the table
        add_row: func
            adds a new row to the table
        sort_by: func
            sorts the table by specific column
        """
        def set_filter(*args):
            self._filters = args

        self._filament_module.set_filter = set_filter

        def set_interval(interval):
            if not type(interval) is int:
                raise FilamentError('Interval must be an integer value')
            self._interval = interval

        self._filament_module.set_interval = set_interval

        def columns(cols):
            if not isinstance(cols, list):
                raise FilamentError('Columns must be a list, '
                                    '%s found' % type(cols))
            self._cols = cols
            self._tabular = Tabular(self._cols)
            self._tabular.padding_width = 10
            self._tabular.junction_char = '|'

        def add_row(row):
            if not isinstance(row, list):
                raise FilamentError(
                    'Expected list type for the row, found %s' % type(row))
            self._tabular.add_row(row)

        def sort_by(col, sort_desc=True):
            if len(self._cols) == 0:
                raise FilamentError('Expected at least 1 column but 0 found')
            if col not in self._cols:
                raise FilamentError('%s column does not exist' % col)
            self._sort_by = col
            self._sort_desc = sort_desc

        def limit(l):
            if len(self._cols) == 0:
                raise FilamentError('Expected at least 1 column but 0 found')
            if not type(l) is int:
                raise FilamentError('Limit must be an integer value')
            self._limit = l

        def title(text):
            self._tabular.title = text

        self._filament_module.columns = columns
        self._filament_module.title = title
        self._filament_module.sort_by = sort_by
        self._filament_module.limit = limit
        self._filament_module.add_row = add_row
        self._filament_module.render_tabular = self.render_tabular

        # call filament initialization method.
        # This is the right place to perform any
        # initialization logic
        on_init = self._find_filament_func('on_init')
        if on_init and self._zero_args(on_init):
            self._filament_module.on_init()

    def setup_adapters(self, output_adapters):
        """Creates the filament adapters accessors.

        Parameters
        ----------

        output_adapters: dict
            output adapters
        """
        for name, adapter in output_adapters.items():
            adapter_metavariable = AdapterMetaVariable(adapter)
            setattr(self._filament_module, name, adapter_metavariable)

    def run(self):
        """Filament main routine.

        Setups the interval repeating function and polls for
        the kernel events from the queue.
        """
        on_interval = self._find_filament_func('on_interval')
        if on_interval:
            self.scheduler.add_executor(ThreadPoolExecutor(max_workers=4))
            self.scheduler.start()
            self.scheduler.add_job(self._filament_module.on_interval,
                                   'interval',
                                   seconds=self._interval,
                                   max_instances=4,
                                   misfire_grace_time=60)
        while self._poll():
            try:
                kevent = self._keventq.get()
                self._filament_module.on_next_kevent(ddict(kevent))
            except Exception:
                self._logger.error('Unexpected filament error',
                                   exc_info=sys.exc_info())

    def render_tabular(self):
        """Renders the table to the console.
        """
        if len(self._cols) > 0:
            tabular = self._tabular.get_string(start=1, end=self._limit)
            if self._sort_by:
                tabular = self._tabular.get_string(start=1,
                                                   end=self._limit,
                                                   sortby=self._sort_by,
                                                   reversesort=self._sort_desc)
            self._tabular.clear_rows()
            if not _ansi_term.term_ready:
                try:
                    _ansi_term.setup_console()
                except TermInitializationError:
                    IO.write_console(
                        'fibratus run: ERROR - console initialization failed')
            _ansi_term.cls()
            _ansi_term.write_output(tabular)

    def close(self):
        on_stop = self._find_filament_func('on_stop')
        if on_stop and self._zero_args(on_stop):
            self._filament_module.on_stop()
        if self.scheduler.running:
            self.scheduler.shutdown()
        _ansi_term.restore_console()
        if self.is_alive():
            self.terminate()

    def _poll(self):
        return True

    @classmethod
    def exists(cls, filament):
        Filament._assert_root_dir()
        return os.path.exists(os.path.join(FILAMENTS_DIR, '%s.py' % filament))

    @classmethod
    def list_filaments(cls):
        Filament._assert_root_dir()
        filaments = {}
        paths = [
            os.path.join(FILAMENTS_DIR, path)
            for path in os.listdir(FILAMENTS_DIR) if path.endswith('.py')
        ]
        for path in paths:
            filament_name = os.path.basename(path)[:-3]
            loader = SourceFileLoader(filament_name, path)
            filament = loader.load_module()
            filaments[filament_name] = inspect.getdoc(filament)
        return filaments

    @classmethod
    def _assert_root_dir(cls):
        if not os.path.exists(FILAMENTS_DIR):
            IO.write_console('fibratus run: ERROR - %s path does not exist.' %
                             FILAMENTS_DIR)
            sys.exit(0)

    @property
    def keventq(self):
        return self._keventq

    @keventq.setter
    def keventq(self, keventq):
        self._keventq = keventq

    @property
    def filters(self):
        return self._filters

    @property
    def logger(self):
        return self._logger

    @logger.setter
    def logger(self, log_path):
        self._log_path = log_path
        FileHandler(self._log_path).push_application()
        self._logger = Logger(Filament.__name__)

    @property
    def filament_module(self):
        return self._filament_module

    def _find_filament_func(self, func_name):
        """Finds the function in the filament module.

        Parameters
        ----------

        func_name: str
            the name of the function
        """
        functions = inspect.getmembers(self._filament_module,
                                       predicate=inspect.isfunction)
        return next(
            iter([func for name, func in functions if name == func_name]),
            None)

    def _find_filament_path(self, filament_name):
        """Resolves the filament full path from the name

        Parameters
        ----------

        filament_name: str
            the name of the filament whose path if about to be resolved
        """
        return next(
            iter([
                os.path.join(FILAMENTS_DIR, filament)
                for filament in os.listdir(FILAMENTS_DIR)
                if filament.endswith('.py') and filament_name == filament[:-3]
            ]), None)

    def _num_args(self, func):
        return len(inspect.getargspec(func).args)

    def _zero_args(self, func):
        return self._num_args(func) == 0
示例#5
0
 def test_init_sortby(self, columns):
     tabular = Tabular(columns, sort_by='Category')
     assert tabular.sortby == 'Category'
示例#6
0
 def test_init_align_col(self, columns):
     tabular = Tabular(columns, 'Description')
     assert tabular.align['Description'] == 'l'
示例#7
0
 def test_init_columns(self, columns):
     tabular = Tabular(columns)
     assert tabular.colcount == 3
示例#8
0
        set_console_ctrl_handler(handle_ctrl_c, True)

        if not filament:
            if len(kevent_filters) > 0:
                fibratus.add_filters(kevent_filters)
        else:
            if len(filament_filters) > 0:
                fibratus.add_filters(filament_filters)
            else:
                fibratus.add_filters([])
        try:
            fibratus.run()
        except KeyboardInterrupt:
            set_console_ctrl_handler(handle_ctrl_c, False)

    elif args['list-filaments']:
        filaments = Tabular(['Filament', 'Description'],
                            'Description',
                            sort_by='Filament')
        for filament, desc in Filament.list_filaments().items():
            filaments.add_row([filament, desc])
        filaments.draw()

    elif args['list-kevents']:
        kevents = Tabular(['KEvent', 'Category', 'Description'],
                          'Description',
                          sort_by='Category')
        for kevent, meta in KEvents.meta_info().items():
            kevents.add_row([kevent, meta[0].name, meta[1]])
        kevents.draw()